* Re: [PATCH] kvm_host: unify VM_STAT and VCPU_STAT definitions in a single place
From: Philippe Mathieu-Daudé @ 2020-04-13 21:34 UTC (permalink / raw)
To: 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, Paolo Bonzini, Vitaly Kuznetsov, linuxppc-dev
In-Reply-To: <20200413140332.22896-1-eesposit@redhat.com>
Hi Emanuele,
On 4/13/20 4:03 PM, Emanuele Giuseppe Esposito wrote:
> The macros VM_STAT and VCPU_STAT are redundantly implemented in multiple
> files, each used by a different architecure to initialize the debugfs
> entries for statistics. Since they all have the same purpose, they can be
> unified in a single common definition in include/linux/kvm_host.h
>
> Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
> ---
> arch/arm64/kvm/guest.c | 23 +++++++--------
> arch/mips/kvm/mips.c | 61 +++++++++++++++++++--------------------
> arch/powerpc/kvm/book3s.c | 3 --
> arch/powerpc/kvm/booke.c | 3 --
> arch/s390/kvm/kvm-s390.c | 3 --
> arch/x86/kvm/x86.c | 3 --
> include/linux/kvm_host.h | 3 ++
> 7 files changed, 43 insertions(+), 56 deletions(-)
>
> diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
> index 23ebe51410f0..3e3aee8b37c0 100644
> --- a/arch/arm64/kvm/guest.c
> +++ b/arch/arm64/kvm/guest.c
> @@ -29,20 +29,17 @@
>
> #include "trace.h"
>
> -#define VM_STAT(x) { #x, offsetof(struct kvm, stat.x), KVM_STAT_VM }
> -#define VCPU_STAT(x) { #x, offsetof(struct kvm_vcpu, stat.x), KVM_STAT_VCPU }
> -
> struct kvm_stats_debugfs_item debugfs_entries[] = {
> - VCPU_STAT(halt_successful_poll),
> - VCPU_STAT(halt_attempted_poll),
> - VCPU_STAT(halt_poll_invalid),
> - VCPU_STAT(halt_wakeup),
> - VCPU_STAT(hvc_exit_stat),
> - VCPU_STAT(wfe_exit_stat),
> - VCPU_STAT(wfi_exit_stat),
> - VCPU_STAT(mmio_exit_user),
> - VCPU_STAT(mmio_exit_kernel),
> - VCPU_STAT(exits),
> + { "halt_successful_poll", VCPU_STAT(halt_successful_poll) },
> + { "halt_attempted_poll", VCPU_STAT(halt_attempted_poll) },
> + { "halt_poll_invalid", VCPU_STAT(halt_poll_invalid) },
> + { "halt_wakeup", VCPU_STAT(halt_wakeup) },
> + { "hvc_exit_stat", VCPU_STAT(hvc_exit_stat) },
> + { "wfe_exit_stat", VCPU_STAT(wfe_exit_stat) },
> + { "wfi_exit_stat", VCPU_STAT(wfi_exit_stat) },
> + { "mmio_exit_user", VCPU_STAT(mmio_exit_user) },
> + { "mmio_exit_kernel", VCPU_STAT(mmio_exit_kernel) },
> + { "exits", VCPU_STAT(exits) },
> { NULL }
> };
>
[...]
> diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
> index 6d58beb65454..e02d38c7fff1 100644
> --- a/include/linux/kvm_host.h
> +++ b/include/linux/kvm_host.h
> @@ -1130,6 +1130,9 @@ struct kvm_stats_debugfs_item {
> #define KVM_DBGFS_GET_MODE(dbgfs_item) \
> ((dbgfs_item)->mode ? (dbgfs_item)->mode : 0644)
>
> +#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().
> +
> extern struct kvm_stats_debugfs_item debugfs_entries[];
> extern struct dentry *kvm_debugfs_dir;
>
>
^ permalink raw reply
* Re: [PATCH 2/2] crypto: Remove unnecessary memzero_explicit()
From: Waiman Long @ 2020-04-13 21:52 UTC (permalink / raw)
To: Joe Perches, Andrew Morton, David Howells, Jarkko Sakkinen,
James Morris, Serge E. Hallyn, Linus Torvalds, Matthew Wilcox,
David Rientjes
Cc: samba-technical, virtualization, linux-mm, linux-sctp,
target-devel, linux-stm32, devel, linux-s390, linux-scsi, x86,
kasan-dev, cocci, linux-wpan, intel-wired-lan, linux-crypto,
linux-pm, ecryptfs, linux-nfs, linux-fscrypt, linux-mediatek,
linux-amlogic, linux-arm-kernel, linux-cifs, netdev,
linux-wireless, linux-kernel, linux-bluetooth,
linux-security-module, keyrings, tipc-discussion, wireguard,
linux-ppp, linux-integrity, linuxppc-dev, linux-btrfs
In-Reply-To: <efd6ceb1f182aa7364e9706422768a1c1335aee4.camel@perches.com>
On 4/13/20 5:31 PM, Joe Perches wrote:
> On Mon, 2020-04-13 at 17:15 -0400, Waiman Long wrote:
>> Since kfree_sensitive() will do an implicit memzero_explicit(), there
>> is no need to call memzero_explicit() before it. Eliminate those
>> memzero_explicit() and simplify the call sites.
> 2 bits of trivia:
>
>> diff --git a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-cipher.c b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-cipher.c
> []
>> @@ -391,10 +388,7 @@ int sun8i_ce_aes_setkey(struct crypto_skcipher *tfm, const u8 *key,
>> dev_dbg(ce->dev, "ERROR: Invalid keylen %u\n", keylen);
>> return -EINVAL;
>> }
>> - if (op->key) {
>> - memzero_explicit(op->key, op->keylen);
>> - kfree(op->key);
>> - }
>> + kfree_sensitive(op->key);
>> op->keylen = keylen;
>> op->key = kmemdup(key, keylen, GFP_KERNEL | GFP_DMA);
>> if (!op->key)
> It might be a defect to set op->keylen before the kmemdup succeeds.
It could be. I can move it down after the op->key check.
>> @@ -416,10 +410,7 @@ int sun8i_ce_des3_setkey(struct crypto_skcipher *tfm, const u8 *key,
>> if (err)
>> return err;
>>
>> - if (op->key) {
>> - memzero_explicit(op->key, op->keylen);
>> - kfree(op->key);
>> - }
>> + free_sensitive(op->key, op->keylen);
> Why not kfree_sensitive(op->key) ?
Oh, it is a bug. I will send out v2 to fix that.
Thanks for spotting it.
Cheers,
Longman
>
>
^ permalink raw reply
* [PATCH v2 2/2] crypto: Remove unnecessary memzero_explicit()
From: Waiman Long @ 2020-04-13 22:28 UTC (permalink / raw)
To: Andrew Morton, David Howells, Jarkko Sakkinen, James Morris,
Serge E. Hallyn, Linus Torvalds, Joe Perches, Matthew Wilcox,
David Rientjes
Cc: samba-technical, virtualization, linux-mm, linux-sctp,
target-devel, linux-stm32, devel, linux-s390, linux-scsi, x86,
kasan-dev, cocci, linux-wpan, intel-wired-lan, Waiman Long,
linux-crypto, linux-pm, ecryptfs, linux-nfs, linux-fscrypt,
linux-mediatek, linux-amlogic, linux-arm-kernel, linux-cifs,
netdev, linux-wireless, linux-kernel, linux-bluetooth,
linux-security-module, keyrings, tipc-discussion, wireguard,
linux-ppp, linux-integrity, linuxppc-dev, linux-btrfs
In-Reply-To: <20200413211550.8307-1-longman@redhat.com>
Since kfree_sensitive() will do an implicit memzero_explicit(), there
is no need to call memzero_explicit() before it. Eliminate those
memzero_explicit() and simplify the call sites. For better correctness,
the setting of keylen is also moved down after the key pointer check.
Signed-off-by: Waiman Long <longman@redhat.com>
---
.../allwinner/sun8i-ce/sun8i-ce-cipher.c | 19 +++++-------------
.../allwinner/sun8i-ss/sun8i-ss-cipher.c | 20 +++++--------------
drivers/crypto/amlogic/amlogic-gxl-cipher.c | 12 +++--------
drivers/crypto/inside-secure/safexcel_hash.c | 3 +--
4 files changed, 14 insertions(+), 40 deletions(-)
diff --git a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-cipher.c b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-cipher.c
index aa4e8fdc2b32..8358fac98719 100644
--- a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-cipher.c
+++ b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-cipher.c
@@ -366,10 +366,7 @@ void sun8i_ce_cipher_exit(struct crypto_tfm *tfm)
{
struct sun8i_cipher_tfm_ctx *op = crypto_tfm_ctx(tfm);
- if (op->key) {
- memzero_explicit(op->key, op->keylen);
- kfree(op->key);
- }
+ kfree_sensitive(op->key);
crypto_free_sync_skcipher(op->fallback_tfm);
pm_runtime_put_sync_suspend(op->ce->dev);
}
@@ -391,14 +388,11 @@ int sun8i_ce_aes_setkey(struct crypto_skcipher *tfm, const u8 *key,
dev_dbg(ce->dev, "ERROR: Invalid keylen %u\n", keylen);
return -EINVAL;
}
- if (op->key) {
- memzero_explicit(op->key, op->keylen);
- kfree(op->key);
- }
- op->keylen = keylen;
+ kfree_sensitive(op->key);
op->key = kmemdup(key, keylen, GFP_KERNEL | GFP_DMA);
if (!op->key)
return -ENOMEM;
+ op->keylen = keylen;
crypto_sync_skcipher_clear_flags(op->fallback_tfm, CRYPTO_TFM_REQ_MASK);
crypto_sync_skcipher_set_flags(op->fallback_tfm, tfm->base.crt_flags & CRYPTO_TFM_REQ_MASK);
@@ -416,14 +410,11 @@ int sun8i_ce_des3_setkey(struct crypto_skcipher *tfm, const u8 *key,
if (err)
return err;
- if (op->key) {
- memzero_explicit(op->key, op->keylen);
- kfree(op->key);
- }
- op->keylen = keylen;
+ kfree_sensitive(op->key);
op->key = kmemdup(key, keylen, GFP_KERNEL | GFP_DMA);
if (!op->key)
return -ENOMEM;
+ op->keylen = keylen;
crypto_sync_skcipher_clear_flags(op->fallback_tfm, CRYPTO_TFM_REQ_MASK);
crypto_sync_skcipher_set_flags(op->fallback_tfm, tfm->base.crt_flags & CRYPTO_TFM_REQ_MASK);
diff --git a/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-cipher.c b/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-cipher.c
index 5246ef4f5430..0495fbc27fcc 100644
--- a/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-cipher.c
+++ b/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-cipher.c
@@ -249,7 +249,6 @@ static int sun8i_ss_cipher(struct skcipher_request *areq)
offset = areq->cryptlen - ivsize;
if (rctx->op_dir & SS_DECRYPTION) {
memcpy(areq->iv, backup_iv, ivsize);
- memzero_explicit(backup_iv, ivsize);
kfree_sensitive(backup_iv);
} else {
scatterwalk_map_and_copy(areq->iv, areq->dst, offset,
@@ -367,10 +366,7 @@ void sun8i_ss_cipher_exit(struct crypto_tfm *tfm)
{
struct sun8i_cipher_tfm_ctx *op = crypto_tfm_ctx(tfm);
- if (op->key) {
- memzero_explicit(op->key, op->keylen);
- kfree(op->key);
- }
+ kfree_sensitive(op->key);
crypto_free_sync_skcipher(op->fallback_tfm);
pm_runtime_put_sync(op->ss->dev);
}
@@ -392,14 +388,11 @@ int sun8i_ss_aes_setkey(struct crypto_skcipher *tfm, const u8 *key,
dev_dbg(ss->dev, "ERROR: Invalid keylen %u\n", keylen);
return -EINVAL;
}
- if (op->key) {
- memzero_explicit(op->key, op->keylen);
- kfree(op->key);
- }
- op->keylen = keylen;
+ kfree_sensitive(op->key);
op->key = kmemdup(key, keylen, GFP_KERNEL | GFP_DMA);
if (!op->key)
return -ENOMEM;
+ op->keylen = keylen;
crypto_sync_skcipher_clear_flags(op->fallback_tfm, CRYPTO_TFM_REQ_MASK);
crypto_sync_skcipher_set_flags(op->fallback_tfm, tfm->base.crt_flags & CRYPTO_TFM_REQ_MASK);
@@ -418,14 +411,11 @@ int sun8i_ss_des3_setkey(struct crypto_skcipher *tfm, const u8 *key,
return -EINVAL;
}
- if (op->key) {
- memzero_explicit(op->key, op->keylen);
- kfree(op->key);
- }
- op->keylen = keylen;
+ kfree_sensitive(op->key);
op->key = kmemdup(key, keylen, GFP_KERNEL | GFP_DMA);
if (!op->key)
return -ENOMEM;
+ op->keylen = keylen;
crypto_sync_skcipher_clear_flags(op->fallback_tfm, CRYPTO_TFM_REQ_MASK);
crypto_sync_skcipher_set_flags(op->fallback_tfm, tfm->base.crt_flags & CRYPTO_TFM_REQ_MASK);
diff --git a/drivers/crypto/amlogic/amlogic-gxl-cipher.c b/drivers/crypto/amlogic/amlogic-gxl-cipher.c
index fd1269900d67..6aa9ce7bbbd4 100644
--- a/drivers/crypto/amlogic/amlogic-gxl-cipher.c
+++ b/drivers/crypto/amlogic/amlogic-gxl-cipher.c
@@ -341,10 +341,7 @@ void meson_cipher_exit(struct crypto_tfm *tfm)
{
struct meson_cipher_tfm_ctx *op = crypto_tfm_ctx(tfm);
- if (op->key) {
- memzero_explicit(op->key, op->keylen);
- kfree(op->key);
- }
+ kfree_sensitive(op->key);
crypto_free_sync_skcipher(op->fallback_tfm);
}
@@ -368,14 +365,11 @@ int meson_aes_setkey(struct crypto_skcipher *tfm, const u8 *key,
dev_dbg(mc->dev, "ERROR: Invalid keylen %u\n", keylen);
return -EINVAL;
}
- if (op->key) {
- memzero_explicit(op->key, op->keylen);
- kfree(op->key);
- }
- op->keylen = keylen;
+ kfree_sensitive(op->key);
op->key = kmemdup(key, keylen, GFP_KERNEL | GFP_DMA);
if (!op->key)
return -ENOMEM;
+ op->keylen = keylen;
return crypto_sync_skcipher_setkey(op->fallback_tfm, key, keylen);
}
diff --git a/drivers/crypto/inside-secure/safexcel_hash.c b/drivers/crypto/inside-secure/safexcel_hash.c
index 43962bc709c6..4a2d162914de 100644
--- a/drivers/crypto/inside-secure/safexcel_hash.c
+++ b/drivers/crypto/inside-secure/safexcel_hash.c
@@ -1081,8 +1081,7 @@ static int safexcel_hmac_init_pad(struct ahash_request *areq,
}
/* Avoid leaking */
- memzero_explicit(keydup, keylen);
- kfree(keydup);
+ kfree_sensitive(keydup);
if (ret)
return ret;
--
2.18.1
^ permalink raw reply related
* Re: [PATCH v2 0/4] huge vmalloc mappings
From: David Rientjes @ 2020-04-14 0:27 UTC (permalink / raw)
To: Nicholas Piggin
Cc: linux-arch, H. Peter Anvin, Will Deacon, x86, linux-kernel,
linux-mm, Ingo Molnar, Borislav Petkov, Catalin Marinas,
Thomas Gleixner, linuxppc-dev, linux-arm-kernel
In-Reply-To: <20200413125303.423864-1-npiggin@gmail.com>
On Mon, 13 Apr 2020, Nicholas Piggin wrote:
> We can get a significant win with larger mappings for some of the big
> global hashes.
>
> Since RFC, relevant architectures have added p?d_leaf accessors so no
> real arch changes required, and I changed it not to allocate huge
> mappings for modules and a bunch of other fixes.
>
Hi Nicholas,
Any performance numbers to share besides the git diff in the last patch in
the series? I'm wondering if anything from mmtests or lkp-tests makes
sense to try?
> Nicholas Piggin (4):
> mm/vmalloc: fix vmalloc_to_page for huge vmap mappings
> mm: Move ioremap page table mapping function to mm/
> mm: HUGE_VMAP arch query functions cleanup
> mm/vmalloc: Hugepage vmalloc mappings
>
> arch/arm64/mm/mmu.c | 8 +-
> arch/powerpc/mm/book3s64/radix_pgtable.c | 6 +-
> arch/x86/mm/ioremap.c | 6 +-
> include/linux/io.h | 3 -
> include/linux/vmalloc.h | 15 +
> lib/ioremap.c | 203 +----------
> mm/vmalloc.c | 413 +++++++++++++++++++----
> 7 files changed, 380 insertions(+), 274 deletions(-)
>
> --
> 2.23.0
>
>
>
^ permalink raw reply
* Re: [PATCH 1/2] mm, treewide: Rename kzfree() to kfree_sensitive()
From: David Rientjes @ 2020-04-14 0:29 UTC (permalink / raw)
To: Waiman Long
Cc: linux-btrfs, Jarkko Sakkinen, virtualization, David Howells,
linux-mm, linux-sctp, keyrings, kasan-dev, samba-technical,
linux-stm32, devel, linux-s390, linux-scsi, x86, James Morris,
Matthew Wilcox, cocci, Linus Torvalds, intel-wired-lan,
Serge E. Hallyn, linux-wpan, linux-pm, ecryptfs, linux-nfs,
linux-fscrypt, linux-mediatek, linux-amlogic, linux-integrity,
linux-arm-kernel, linux-cifs, netdev, linux-wireless,
linux-kernel, linux-bluetooth, linux-security-module,
target-devel, tipc-discussion, linux-crypto, linux-ppp,
Joe Perches, Andrew Morton, linuxppc-dev, wireguard
In-Reply-To: <20200413211550.8307-2-longman@redhat.com>
On Mon, 13 Apr 2020, Waiman Long wrote:
> As said by Linus:
>
> A symmetric naming is only helpful if it implies symmetries in use.
> Otherwise it's actively misleading.
>
> In "kzalloc()", the z is meaningful and an important part of what the
> caller wants.
>
> In "kzfree()", the z is actively detrimental, because maybe in the
> future we really _might_ want to use that "memfill(0xdeadbeef)" or
> something. The "zero" part of the interface isn't even _relevant_.
>
> The main reason that kzfree() exists is to clear sensitive information
> that should not be leaked to other future users of the same memory
> objects.
>
> Rename kzfree() to kfree_sensitive() to follow the example of the
> recently added kvfree_sensitive() and make the intention of the API
> more explicit. In addition, memzero_explicit() is used to clear the
> memory to make sure that it won't get optimized away by the compiler.
>
> The renaming is done by using the command sequence:
>
> git grep -w --name-only kzfree |\
> xargs sed -i 's/\bkzfree\b/kfree_sensitive/'
>
> followed by some editing of the kfree_sensitive() kerneldoc and the
> use of memzero_explicit() instead of memset().
>
> Suggested-by: Joe Perches <joe@perches.com>
> Signed-off-by: Waiman Long <longman@redhat.com>
Acked-by: David Rientjes <rientjes@google.com>
^ permalink raw reply
* [PATCH v7 2/7] ASoC: dt-bindings: fsl_asrc: Add new property fsl, asrc-format
From: Shengjiu Wang @ 2020-04-14 0:43 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.1586747728.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 v7 0/7] ASoC: Add new module driver for new ASRC
From: Shengjiu Wang @ 2020-04-14 0:43 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 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 | 310 +--
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 | 2119 +++++++++++++++++
sound/soc/fsl/fsl_easrc.h | 651 +++++
11 files changed, 3222 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 v7 3/7] ASoC: fsl-asoc-card: Support new property fsl, asrc-format
From: Shengjiu Wang @ 2020-04-14 0:43 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.1586747728.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 v7 1/7] ASoC: fsl_asrc: rename asrc_priv to asrc
From: Shengjiu Wang @ 2020-04-14 0:43 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.1586747728.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, ®);
+ regmap_read(asrc->regmap, REG_ASRCFG, ®);
reg &= ASRCFG_INIRQi_MASK(index);
} while (!reg && --retry);
/* Make the input fifo to ASRC STALL level */
- regmap_read(asrc_priv->regmap, REG_ASRCNCR, ®);
+ regmap_read(asrc->regmap, REG_ASRCNCR, ®);
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
* Re: [PATCH v2] qtpm2: Export tpm2_get_cc_attrs_tbl for ibmvtpm driver as module
From: Michael Ellerman @ 2020-04-14 0:51 UTC (permalink / raw)
To: Jarkko Sakkinen, Sachin Sant
Cc: Stefan Berger, LKML, linux-next, linux-integrity, linuxppc-dev,
Stefan Berger
In-Reply-To: <20200402193134.GC10314@linux.intel.com>
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
^ permalink raw reply
* [PATCH v7 4/7] ASoC: fsl_asrc: Support new property fsl,asrc-format
From: Shengjiu Wang @ 2020-04-14 0:43 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.1586747728.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>
---
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 v7 6/7] ASoC: dt-bindings: fsl_easrc: Add document for EASRC
From: Shengjiu Wang @ 2020-04-14 0:43 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.1586747728.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 v7 5/7] ASoC: fsl_asrc: Move common definition to fsl_asrc_common
From: Shengjiu Wang @ 2020-04-14 0:43 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.1586747728.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>
---
sound/soc/fsl/fsl_asrc.c | 87 +++++++++++++++++---------
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, 183 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..ca9e766f7c69 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,20 @@ 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 size_t fsl_asrc_get_pair_priv_size(void)
+{
+ return sizeof(struct fsl_asrc_pair_priv);
+}
+
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 +961,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 +1012,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->get_pair_priv_size = fsl_asrc_get_pair_priv_size;
+
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 +1051,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 +1120,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 +1135,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 +1144,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 +1157,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 +1175,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 +1189,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 +1203,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..b15244e027d0
--- /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
+ * @get_pair_priv_size: function pointer
+ * @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 (*get_pair_priv_size)(void);
+
+ 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..4f5fb2c67472 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->get_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 v7 7/7] ASoC: fsl_easrc: Add EASRC ASoC CPU DAI drivers
From: Shengjiu Wang @ 2020-04-14 0:43 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.1586747728.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 | 2119 +++++++++++++++++++++++++++++++++++++
sound/soc/fsl/fsl_easrc.h | 651 ++++++++++++
4 files changed, 2783 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..2e639ebcd15b
--- /dev/null
+++ b/sound/soc/fsl/fsl_easrc.c
@@ -0,0 +1,2119 @@
+// 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, ®val);
+ 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 size_t fsl_easrc_get_ctx_priv_size(void)
+{
+ return sizeof(struct fsl_easrc_ctx_priv);
+}
+
+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->get_pair_priv_size = fsl_easrc_get_ctx_priv_size;
+
+ 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 v7 4/7] ASoC: fsl_asrc: Support new property fsl,asrc-format
From: Nicolin Chen @ 2020-04-14 1:52 UTC (permalink / raw)
To: Shengjiu Wang
Cc: mark.rutland, devicetree, alsa-devel, timur, Xiubo.Lee,
linuxppc-dev, tiwai, lgirdwood, robh+dt, perex, broonie, festevam,
linux-kernel
In-Reply-To: <d10df72d2e9985fede7969b5da1f579627f5e821.1586747728.git.shengjiu.wang@nxp.com>
On Tue, Apr 14, 2020 at 08:43:06AM +0800, Shengjiu Wang wrote:
> 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>
^ permalink raw reply
* Re: [PATCH v7 5/7] ASoC: fsl_asrc: Move common definition to fsl_asrc_common
From: Shengjiu Wang @ 2020-04-14 2:21 UTC (permalink / raw)
To: Nicolin Chen
Cc: Mark Rutland,
open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
Linux-ALSA, Timur Tabi, Xiubo Li, Fabio Estevam, Shengjiu Wang,
Takashi Iwai, Liam Girdwood, Rob Herring, Mark Brown,
linuxppc-dev, linux-kernel
In-Reply-To: <20200414020748.GB10195@Asurada-Nvidia.nvidia.com>
On Tue, Apr 14, 2020 at 10:09 AM Nicolin Chen <nicoleotsuka@gmail.com> wrote:
>
> On Tue, Apr 14, 2020 at 08:43:07AM +0800, Shengjiu Wang wrote:
> > 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>
>
> > diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c
> > +static size_t fsl_asrc_get_pair_priv_size(void)
> > +{
> > + return sizeof(struct fsl_asrc_pair_priv);
> > +}
>
> Perhaps we haven't understood completely each other's point.
>
> Yet, would the following change work?
Should work, almost same, or do you want me to use variable to
replace function pointer?
best regards
wang shengjiu
^ permalink raw reply
* Re: [RFC/PATCH 2/3] pseries/kvm: Clear PSSCR[ESL|EC] bits before guest entry
From: David Gibson @ 2020-04-14 2:17 UTC (permalink / raw)
To: Gautham R Shenoy
Cc: Michael Neuling, Nicholas Piggin, Bharata B Rao, linuxppc-dev,
kvm-ppc, Vaidyanathan Srinivasan, linuxppc-dev
In-Reply-To: <20200413102549.GA22532@in.ibm.com>
[-- Attachment #1: Type: text/plain, Size: 9541 bytes --]
On Mon, Apr 13, 2020 at 03:55:49PM +0530, Gautham R Shenoy wrote:
> Hello David,
>
> On Wed, Apr 08, 2020 at 12:29:57PM +1000, David Gibson wrote:
> > On Tue, Apr 07, 2020 at 06:55:26PM +0530, Gautham R Shenoy wrote:
> > > Hello David,
> > >
> > > On Mon, Apr 06, 2020 at 07:58:19PM +1000, David Gibson wrote:
> > > > On Fri, Apr 03, 2020 at 03:01:03PM +0530, Gautham R Shenoy wrote:
> > > > > On Fri, Apr 03, 2020 at 12:20:26PM +1000, Nicholas Piggin wrote:
> > > > > > Gautham R. Shenoy's on March 31, 2020 10:10 pm:
> > > > > > > From: "Gautham R. Shenoy" <ego@linux.vnet.ibm.com>
> > > > > > >
> > > > > > > ISA v3.0 allows the guest to execute a stop instruction. For this, the
> > > > > > > PSSCR[ESL|EC] bits need to be cleared by the hypervisor before
> > > > > > > scheduling in the guest vCPU.
> > > > > > >
> > > > > > > Currently we always schedule in a vCPU with PSSCR[ESL|EC] bits
> > > > > > > set. This patch changes the behaviour to enter the guest with
> > > > > > > PSSCR[ESL|EC] bits cleared. This is a RFC patch where we
> > > > > > > unconditionally clear these bits. Ideally this should be done
> > > > > > > conditionally on platforms where the guest stop instruction has no
> > > > > > > Bugs (starting POWER9 DD2.3).
> > > > > >
> > > > > > How will guests know that they can use this facility safely after your
> > > > > > series? You need both DD2.3 and a patched KVM.
> > > > >
> > > > >
> > > > > Yes, this is something that isn't addressed in this series (mentioned
> > > > > in the cover letter), which is a POC demonstrating that the stop0lite
> > > > > state in guest works.
> > > > >
> > > > > However, to answer your question, this is the scheme that I had in
> > > > > mind :
> > > > >
> > > > > OPAL:
> > > > > On Procs >= DD2.3 : we publish a dt-cpu-feature "idle-stop-guest"
> > > > >
> > > > > Hypervisor Kernel:
> > > > > 1. If "idle-stop-guest" dt-cpu-feature is discovered, then
> > > > > we set bool enable_guest_stop = true;
> > > > >
> > > > > 2. During KVM guest entry, clear PSSCR[ESL|EC] iff
> > > > > enable_guest_stop == true.
> > > > >
> > > > > 3. In kvm_vm_ioctl_check_extension(), for a new capability
> > > > > KVM_CAP_STOP, return true iff enable_guest_top == true.
> > > > >
> > > > > QEMU:
> > > > > Check with the hypervisor if KVM_CAP_STOP is present. If so,
> > > > > indicate the presence to the guest via device tree.
> > > >
> > > > Nack. Presenting different capabilities to the guest depending on
> > > > host capabilities (rather than explicit options) is never ok. It
> > > > means that depending on the system you start on you may or may not be
> > > > able to migrate to other systems that you're supposed to be able to,
> > >
> > > I agree that blocking migration for the unavailability of this feature
> > > is not desirable. Could you point me to some other capabilities in KVM
> > > which have been implemented via explicit options?
> >
> > TBH, most of the options for the 'pseries' machine type are in this
> > category: cap-vsx, cap-dfp, cap-htm, a bunch related to various
> > Spectre mitigations, cap-hpt-max-page-size (maximum page size for hash
> > guests), cap-nested-hv, cap-large-decr, cap-fwnmi, resize-hpt (HPT
> > resizing extension), ic-mode (which irq controllers are available to
> > the guest).
>
>
> Thanks. I will follow this suit.
>
> >
> > > The ISA 3.0 allows the guest to execute the "stop" instruction.
> >
> > So, this was a bug in DD2.2's implementation of the architecture?
>
> Yes, the previous versions could miss wakeup events when stop was
> executed in HV=0,PR=0 mode. So, the hypervisor had to block that.
>
>
> >
> > > If the
> > > Hypervisor hasn't cleared the PSSCR[ESL|EC] then, guest executing the
> > > "stop" instruction in the causes a Hypervisor Facility Unavailable
> > > Exception, thus giving the hypervisor a chance to emulate the
> > > instruction. However, in the current code, when the hypervisor
> > > receives this exception, it sends a PROGKILL to the guest which
> > > results in crashing the guest.
> > >
> > > Patch 1 of this series emulates wakeup from the "stop"
> > > instruction. Would the following scheme be ok?
> > >
> > > OPAL:
> > > On Procs >= DD2.3 : we publish a dt-cpu-feature "idle-stop-guest"
> > >
> > > Hypervisor Kernel:
> > >
> > > If "idle-stop-guest" dt feature is available, then, before
> > > entering the guest, the hypervisor clears the PSSCR[EC|ESL]
> > > bits allowing the guest to safely execute stop instruction.
> > >
> > > If "idle-stop-guest" dt feature is not available, then, the
> > > Hypervisor sets the PSSCR[ESL|EC] bits, thereby causing a
> > > guest "stop" instruction execution to trap back into the
> > > hypervisor. We then emulate a wakeup from the stop
> > > instruction (Patch 1 of this series).
> > >
> > > Guest Kernel:
> > > If (cpu_has_feature(CPU_FTR_ARCH_300)) only then use the
> > > stop0lite cpuidle state.
> > >
> > > This allows us to migrate the KVM guest across any POWER9
> > > Hypervisor. The minimal addition that the Hypervisor would need is
> > > Patch 1 of this series.
> >
> > That could be workable. Some caveats, though:
> >
> > * How does the latency of the trap-and-emulate compare to the guest
> > using H_CEDE in the first place? i.e. how big a negative impact
> > will this have for guests running on DD2.2 hosts?
>
>
> The wakeup latency of trap-and-emulated stop0lite (referred to as
> "stop0lite Emulated" in the tables below) the compares favorably
> compared to H_CEDE. It is in the order of 5-6us while the wakeup
> latency of H_CEDE is ~25-30us.
Ok. So allowing the guest to use stop0lite everywhere, but having it
emulated on the older CPUs should work reasonably well.
>
> ======================================================================
> Wakeup Latency measured using a timer (in ns) [Lower is better]
> ======================================================================
> Idle state | Nr samples | Min | Max | Median | Avg | Stddev|
> ----------------------------------------------------------------------
> snooze | 60 | 787 | 1059 | 938 | 937.4 | 42.27 |
> ----------------------------------------------------------------------
> stop0lite | 60 | 770 | 1182 | 948 | 946.4 | 67.41 |
> ----------------------------------------------------------------------
> stop0lite | 60 | 2378 | 7659 | 5006 |5093.6 |1578.7 |
> Emulated | | | | | | |
> ----------------------------------------------------------------------
> Shared CEDE| 60 | 9550 | 36694 | 29219 |28564.1|3545.9 |
> ======================================================================
>
>
> ======================================================================
> Wakeup latency measured using an IPI (in ns) [Lower is better]
> ======================================================================
> Idle state | Nr | Min | Max | Median | Avg | Stddev |
> |samples | | | | | |
> ----------------------------------------------------------------------
> snooze | 60 | 2089| 4228| 2259| 2342.31| 316.56|
> ----------------------------------------------------------------------
> stop0lite | 60 | 1947| 3674| 2653| 2610.57| 266.73|
> ----------------------------------------------------------------------
> stop0lite | 60 | 3580| 8154| 5596| 5644.95| 1368.44|
> Emulated | | | | | | |
> ----------------------------------------------------------------------
> Shared CEDE| 60 | 20147| 36305| 21827| 26762.65| 6875.01|
> ======================================================================
>
> >
> > * We'll only be able to enable this in a new qemu machine type
> > version (say, pseries-5.1.0). Otherwise a guest could start
> > thinking it can use stop states, then be migrated to an older qemu
> > or host kernel without the support and crash.
>
> That makese sense. In fact in the case of not being able to backport
> Patch 1 to all the older hypervisor kernels, we will need a way of
> gating the guest from using stop-states and then migrating onto an
> older hypervisor kernel. Associating this with a new qemu machine type
> version should solve this problem, assuming that all the newer qemus
> will also be running on newer hypervisor kernels.
We can't assume that automatically, but we can enforce it with a
pretty standard mechanism. The way to do it is this:
* Make a new spapr capability flag that enables guest use of the lite
stop instructions
* In the capability's '.apply' hook, verify that the host kernel can
support this, and if not fail
* Enable the new capability by default in the new machine type
So, running the new machine type with default options on an old kernel
will fail with a meaningful error, but existing setups with an old
qemu, or old machine type.
--
David Gibson | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_
| _way_ _around_!
http://www.ozlabs.org/~dgibson
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply
* Re: Boot flakiness with QEMU 3.1.0 and Clang built kernels
From: David Gibson @ 2020-04-14 2:05 UTC (permalink / raw)
To: Nicholas Piggin
Cc: qemu-devel, clang-built-linux, Cédric Le Goater, qemu-ppc,
Nathan Chancellor, linuxppc-dev
In-Reply-To: <1586612535.6kk4az03np.astroid@bobo.none>
[-- Attachment #1: Type: text/plain, Size: 4056 bytes --]
On Sat, Apr 11, 2020 at 11:57:23PM +1000, Nicholas Piggin wrote:
> Nicholas Piggin's on April 11, 2020 7:32 pm:
> > Nathan Chancellor's on April 11, 2020 10:53 am:
> >> The tt.config values are needed to reproduce but I did not verify that
> >> ONLY tt.config was needed. Other than that, no, we are just building
> >> either pseries_defconfig or powernv_defconfig with those configs and
> >> letting it boot up with a simple initramfs, which prints the version
> >> string then shuts the machine down.
> >>
> >> Let me know if you need any more information, cheers!
> >
> > Okay I can reproduce it. Sometimes it eventually recovers after a long
> > pause, and some keyboard input often helps it along. So that seems like
> > it might be a lost interrupt.
> >
> > POWER8 vs POWER9 might just be a timing thing if P9 is still hanging
> > sometimes. I wasn't able to reproduce it with defconfig+tt.config, I
> > needed your other config with various other debug options.
> >
> > Thanks for the very good report. I'll let you know what I find.
>
> It looks like a qemu bug. Booting with '-d int' shows the decrementer
> simply stops firing at the point of the hang, even though MSR[EE]=1 and
> the DEC register is wrapping. Linux appears to be doing the right thing
> as far as I can tell (not losing interrupts).
>
> This qemu patch fixes the boot hang for me. I don't know that qemu
> really has the right idea of "context synchronizing" as defined in the
> powerpc architecture -- mtmsrd L=1 is not context synchronizing but that
> does not mean it can avoid looking at exceptions until the next such
> event. It looks like the decrementer exception goes high but the
> execution of mtmsrd L=1 is ignoring it.
>
> Prior to the Linux patch 3282a3da25b you bisected to, interrupt replay
> code would return with an 'rfi' instruction as part of interrupt return,
> which probably helped to get things moving along a bit. However it would
> not be foolproof, and Cedric did say he encountered some mysterious
> lockups under load with qemu powernv before that patch was merged, so
> maybe it's the same issue?
>
> Thanks,
> Nick
>
> The patch is a bit of a hack, but if you can run it and verify it fixes
> your boot hang would be good.
So a bug in this handling wouldn't surprise me at all. However a
report against QEMU 3.1 isn't particularly useful.
* Does the problem occur with current upstream master qemu?
* Does the problem occur with qemu-2.12 (a pretty widely deployed
"stable" qemu, e.g. in RHEL)?
> ---
>
> diff --git a/target/ppc/translate.c b/target/ppc/translate.c
> index b207fb5386..1d997f5c32 100644
> --- a/target/ppc/translate.c
> +++ b/target/ppc/translate.c
> @@ -4364,12 +4364,21 @@ static void gen_mtmsrd(DisasContext *ctx)
> if (ctx->opcode & 0x00010000) {
> /* Special form that does not need any synchronisation */
> TCGv t0 = tcg_temp_new();
> + TCGv t1 = tcg_temp_new();
> tcg_gen_andi_tl(t0, cpu_gpr[rS(ctx->opcode)],
> (1 << MSR_RI) | (1 << MSR_EE));
> - tcg_gen_andi_tl(cpu_msr, cpu_msr,
> + tcg_gen_andi_tl(t1, cpu_msr,
> ~(target_ulong)((1 << MSR_RI) | (1 << MSR_EE)));
> - tcg_gen_or_tl(cpu_msr, cpu_msr, t0);
> + tcg_gen_or_tl(t1, t1, t0);
> +
> + gen_update_nip(ctx, ctx->base.pc_next);
> + gen_helper_store_msr(cpu_env, t1);
> tcg_temp_free(t0);
> + tcg_temp_free(t1);
> + /* Must stop the translation as machine state (may have) changed */
> + /* Note that mtmsr is not always defined as context-synchronizing */
> + gen_stop_exception(ctx);
> +
> } else {
> /*
> * XXX: we need to update nip before the store if we enter
>
--
David Gibson | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_
| _way_ _around_!
http://www.ozlabs.org/~dgibson
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply
* [PATCH] vhost: do not enable VHOST_MENU by default
From: Jason Wang @ 2020-04-14 2:44 UTC (permalink / raw)
To: mst, jasowang
Cc: linux-s390, Thomas Bogendoerfer, Vasily Gorbik, kvm, linux-kernel,
Heiko Carstens, linux-mips, virtualization, Christian Borntraeger,
geert, netdev, Paul Mackerras, linuxppc-dev
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>
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
--
2.20.1
^ permalink raw reply related
* Re: [PATCH v7 5/7] ASoC: fsl_asrc: Move common definition to fsl_asrc_common
From: Nicolin Chen @ 2020-04-14 3:00 UTC (permalink / raw)
To: Shengjiu Wang
Cc: Mark Rutland,
open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
Linux-ALSA, Timur Tabi, Xiubo Li, Fabio Estevam, Shengjiu Wang,
Takashi Iwai, Liam Girdwood, Rob Herring, Mark Brown,
linuxppc-dev, linux-kernel
In-Reply-To: <CAA+D8AN8OUtTftc_So-Z0_sjWt4RXq6fr4GpSy3Xh+YbkryfpQ@mail.gmail.com>
On Tue, Apr 14, 2020 at 10:21:29AM +0800, Shengjiu Wang wrote:
> On Tue, Apr 14, 2020 at 10:09 AM Nicolin Chen <nicoleotsuka@gmail.com> wrote:
> >
> > On Tue, Apr 14, 2020 at 08:43:07AM +0800, Shengjiu Wang wrote:
> > > 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>
> >
> > > diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c
> > > +static size_t fsl_asrc_get_pair_priv_size(void)
> > > +{
> > > + return sizeof(struct fsl_asrc_pair_priv);
> > > +}
> >
> > Perhaps we haven't understood completely each other's point.
> >
> > Yet, would the following change work?
>
> Should work, almost same
Function call involving branch instruction may fail CPU's branch
prediction and hurt performance, depending on the CPU arch. If a
variable simply does the job, we should avoid doing that.
> or do you want me to use variable to replace function pointer?
Yes. And please add my ack once you change it as the reset LGTM:
Acked-by: Nicolin Chen <nicoleotsuka@gmail.com>
^ permalink raw reply
* Re: [PATCH v7 5/7] ASoC: fsl_asrc: Move common definition to fsl_asrc_common
From: Nicolin Chen @ 2020-04-14 2:07 UTC (permalink / raw)
To: Shengjiu Wang
Cc: mark.rutland, devicetree, alsa-devel, timur, Xiubo.Lee,
linuxppc-dev, tiwai, lgirdwood, robh+dt, perex, broonie, festevam,
linux-kernel
In-Reply-To: <6d2bed91bcdbc3f75a9d12ac4ebf6c34c9bb9c3f.1586747728.git.shengjiu.wang@nxp.com>
On Tue, Apr 14, 2020 at 08:43:07AM +0800, Shengjiu Wang wrote:
> 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>
> diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c
> +static size_t fsl_asrc_get_pair_priv_size(void)
> +{
> + return sizeof(struct fsl_asrc_pair_priv);
> +}
Perhaps we haven't understood completely each other's point.
Yet, would the following change work?
> diff --git a/sound/soc/fsl/fsl_asrc_common.h b/sound/soc/fsl/fsl_asrc_common.h
> new file mode 100644
> index 000000000000..b15244e027d0
> --- /dev/null
> +++ b/sound/soc/fsl/fsl_asrc_common.h
> +struct fsl_asrc {
> + size_t (*get_pair_priv_size)(void);
+ size_t pair_priv_size;
> diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c
> @@ -992,25 +1012,32 @@ static int fsl_asrc_probe(struct platform_device *pdev)
> + asrc->get_pair_priv_size = fsl_asrc_get_pair_priv_size;
+ asrc->pair_priv_size = sizeof(struct fsl_asrc_pair_priv);
> diff --git a/sound/soc/fsl/fsl_asrc_dma.c b/sound/soc/fsl/fsl_asrc_dma.c
> @@ -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->get_pair_priv_size(), GFP_KERNEL);
+ pair = kzalloc(sizeof(*pair) + asrc->pair_priv_size, GFP_KERNEL);
^ permalink raw reply
* [PATCH v3 00/16] powerpc/watchpoint: Preparation for more than one watchpoint
From: Ravi Bangoria @ 2020-04-14 3:16 UTC (permalink / raw)
To: mpe, mikey
Cc: apopple, ravi.bangoria, peterz, fweisbec, oleg, npiggin,
linux-kernel, paulus, jolsa, naveen.n.rao, linuxppc-dev, mingo
So far, powerpc Book3S code has been written with an assumption of only
one watchpoint. But future power architecture is introducing second
watchpoint register (DAWR). Even though this patchset does not enable
2nd DAWR, it make the infrastructure ready so that enabling 2nd DAWR
should just be a matter of changing count.
Existing functionality works fine with the patchset. I've tested it with
perf, ptrace(gdb), xmon. All hw-breakpoint selftests are passing as well.
And I've build tested for 8xx and 'AMCC 44x, 46x or 47x'.
Note: kvm or PowerVM guest is not enabled yet.
v2:
https://lore.kernel.org/linuxppc-dev/20200401061309.92442-1-ravi.bangoria@linux.ibm.com
v2->v3:
- Few minor improvements as suggested by Christophe
- Rebased to powerpc/next
Ravi Bangoria (16):
powerpc/watchpoint: Rename current DAWR macros
powerpc/watchpoint: Add SPRN macros for second DAWR
powerpc/watchpoint: Introduce function to get nr watchpoints
dynamically
powerpc/watchpoint/ptrace: Return actual num of available watchpoints
powerpc/watchpoint: Provide DAWR number to set_dawr
powerpc/watchpoint: Provide DAWR number to __set_breakpoint
powerpc/watchpoint: Get watchpoint count dynamically while disabling
them
powerpc/watchpoint: Disable all available watchpoints when
!dawr_force_enable
powerpc/watchpoint: Convert thread_struct->hw_brk to an array
powerpc/watchpoint: Use loop for thread_struct->ptrace_bps
powerpc/watchpoint: Introduce is_ptrace_bp() function
powerpc/watchpoint: Use builtin ALIGN*() macros
powerpc/watchpoint: Prepare handler to handle more than one
watcnhpoint
powerpc/watchpoint: Don't allow concurrent perf and ptrace events
powerpc/watchpoint/xmon: Don't allow breakpoint overwriting
powerpc/watchpoint/xmon: Support 2nd dawr
arch/powerpc/include/asm/cputable.h | 6 +-
arch/powerpc/include/asm/debug.h | 2 +-
arch/powerpc/include/asm/hw_breakpoint.h | 32 +-
arch/powerpc/include/asm/processor.h | 6 +-
arch/powerpc/include/asm/reg.h | 6 +-
arch/powerpc/include/asm/sstep.h | 2 +
arch/powerpc/kernel/dawr.c | 23 +-
arch/powerpc/kernel/hw_breakpoint.c | 646 ++++++++++++++++++----
arch/powerpc/kernel/process.c | 85 +--
arch/powerpc/kernel/ptrace/ptrace-noadv.c | 72 ++-
arch/powerpc/kernel/ptrace/ptrace32.c | 4 +-
arch/powerpc/kernel/signal.c | 12 +-
arch/powerpc/kvm/book3s_hv.c | 12 +-
arch/powerpc/kvm/book3s_hv_rmhandlers.S | 18 +-
arch/powerpc/xmon/xmon.c | 99 +++-
kernel/events/hw_breakpoint.c | 16 +
16 files changed, 814 insertions(+), 227 deletions(-)
--
2.21.1
^ permalink raw reply
* [PATCH v3 01/16] powerpc/watchpoint: Rename current DAWR macros
From: Ravi Bangoria @ 2020-04-14 3:16 UTC (permalink / raw)
To: mpe, mikey
Cc: apopple, ravi.bangoria, peterz, fweisbec, oleg, npiggin,
linux-kernel, paulus, jolsa, naveen.n.rao, linuxppc-dev, mingo
In-Reply-To: <20200414031659.58875-1-ravi.bangoria@linux.ibm.com>
Future Power architecture is introducing second DAWR. Use real
register names from ISA for current macros:
s/SPRN_DAWR/SPRN_DAWR0/
s/SPRN_DAWRX/SPRN_DAWRX0/
Signed-off-by: Ravi Bangoria <ravi.bangoria@linux.ibm.com>
---
arch/powerpc/include/asm/reg.h | 4 ++--
arch/powerpc/kernel/dawr.c | 4 ++--
arch/powerpc/kvm/book3s_hv.c | 12 ++++++------
arch/powerpc/kvm/book3s_hv_rmhandlers.S | 18 +++++++++---------
arch/powerpc/xmon/xmon.c | 2 +-
5 files changed, 20 insertions(+), 20 deletions(-)
diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h
index da5cab038e25..156ee89fa9be 100644
--- a/arch/powerpc/include/asm/reg.h
+++ b/arch/powerpc/include/asm/reg.h
@@ -283,14 +283,14 @@
#define CTRL_CT1 0x40000000 /* thread 1 */
#define CTRL_TE 0x00c00000 /* thread enable */
#define CTRL_RUNLATCH 0x1
-#define SPRN_DAWR 0xB4
+#define SPRN_DAWR0 0xB4
#define SPRN_RPR 0xBA /* Relative Priority Register */
#define SPRN_CIABR 0xBB
#define CIABR_PRIV 0x3
#define CIABR_PRIV_USER 1
#define CIABR_PRIV_SUPER 2
#define CIABR_PRIV_HYPER 3
-#define SPRN_DAWRX 0xBC
+#define SPRN_DAWRX0 0xBC
#define DAWRX_USER __MASK(0)
#define DAWRX_KERNEL __MASK(1)
#define DAWRX_HYP __MASK(2)
diff --git a/arch/powerpc/kernel/dawr.c b/arch/powerpc/kernel/dawr.c
index cc14aa6c4a1b..e91b613bf137 100644
--- a/arch/powerpc/kernel/dawr.c
+++ b/arch/powerpc/kernel/dawr.c
@@ -39,8 +39,8 @@ int set_dawr(struct arch_hw_breakpoint *brk)
if (ppc_md.set_dawr)
return ppc_md.set_dawr(dawr, dawrx);
- mtspr(SPRN_DAWR, dawr);
- mtspr(SPRN_DAWRX, dawrx);
+ mtspr(SPRN_DAWR0, dawr);
+ mtspr(SPRN_DAWRX0, dawrx);
return 0;
}
diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c
index 33be4d93248a..498c57e1f5c9 100644
--- a/arch/powerpc/kvm/book3s_hv.c
+++ b/arch/powerpc/kvm/book3s_hv.c
@@ -3383,8 +3383,8 @@ static int kvmhv_load_hv_regs_and_go(struct kvm_vcpu *vcpu, u64 time_limit,
int trap;
unsigned long host_hfscr = mfspr(SPRN_HFSCR);
unsigned long host_ciabr = mfspr(SPRN_CIABR);
- unsigned long host_dawr = mfspr(SPRN_DAWR);
- unsigned long host_dawrx = mfspr(SPRN_DAWRX);
+ unsigned long host_dawr = mfspr(SPRN_DAWR0);
+ unsigned long host_dawrx = mfspr(SPRN_DAWRX0);
unsigned long host_psscr = mfspr(SPRN_PSSCR);
unsigned long host_pidr = mfspr(SPRN_PID);
@@ -3413,8 +3413,8 @@ static int kvmhv_load_hv_regs_and_go(struct kvm_vcpu *vcpu, u64 time_limit,
mtspr(SPRN_SPURR, vcpu->arch.spurr);
if (dawr_enabled()) {
- mtspr(SPRN_DAWR, vcpu->arch.dawr);
- mtspr(SPRN_DAWRX, vcpu->arch.dawrx);
+ mtspr(SPRN_DAWR0, vcpu->arch.dawr);
+ mtspr(SPRN_DAWRX0, vcpu->arch.dawrx);
}
mtspr(SPRN_CIABR, vcpu->arch.ciabr);
mtspr(SPRN_IC, vcpu->arch.ic);
@@ -3466,8 +3466,8 @@ static int kvmhv_load_hv_regs_and_go(struct kvm_vcpu *vcpu, u64 time_limit,
(local_paca->kvm_hstate.fake_suspend << PSSCR_FAKE_SUSPEND_LG));
mtspr(SPRN_HFSCR, host_hfscr);
mtspr(SPRN_CIABR, host_ciabr);
- mtspr(SPRN_DAWR, host_dawr);
- mtspr(SPRN_DAWRX, host_dawrx);
+ mtspr(SPRN_DAWR0, host_dawr);
+ mtspr(SPRN_DAWRX0, host_dawrx);
mtspr(SPRN_PID, host_pidr);
/*
diff --git a/arch/powerpc/kvm/book3s_hv_rmhandlers.S b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
index 780a499c7114..70de3325d0e9 100644
--- a/arch/powerpc/kvm/book3s_hv_rmhandlers.S
+++ b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
@@ -707,8 +707,8 @@ BEGIN_FTR_SECTION
END_FTR_SECTION_IFSET(CPU_FTR_ARCH_300)
BEGIN_FTR_SECTION
mfspr r5, SPRN_CIABR
- mfspr r6, SPRN_DAWR
- mfspr r7, SPRN_DAWRX
+ mfspr r6, SPRN_DAWR0
+ mfspr r7, SPRN_DAWRX0
mfspr r8, SPRN_IAMR
std r5, STACK_SLOT_CIABR(r1)
std r6, STACK_SLOT_DAWR(r1)
@@ -803,8 +803,8 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_207S)
beq 1f
ld r5, VCPU_DAWR(r4)
ld r6, VCPU_DAWRX(r4)
- mtspr SPRN_DAWR, r5
- mtspr SPRN_DAWRX, r6
+ mtspr SPRN_DAWR0, r5
+ mtspr SPRN_DAWRX0, r6
1:
ld r7, VCPU_CIABR(r4)
ld r8, VCPU_TAR(r4)
@@ -1766,8 +1766,8 @@ BEGIN_FTR_SECTION
* If the DAWR doesn't work, it's ok to write these here as
* this value should always be zero
*/
- mtspr SPRN_DAWR, r6
- mtspr SPRN_DAWRX, r7
+ mtspr SPRN_DAWR0, r6
+ mtspr SPRN_DAWRX0, r7
END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
BEGIN_FTR_SECTION
ld r5, STACK_SLOT_TID(r1)
@@ -2577,8 +2577,8 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
mfmsr r6
andi. r6, r6, MSR_DR /* in real mode? */
bne 4f
- mtspr SPRN_DAWR, r4
- mtspr SPRN_DAWRX, r5
+ mtspr SPRN_DAWR0, r4
+ mtspr SPRN_DAWRX0, r5
4: li r3, 0
blr
@@ -3329,7 +3329,7 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_300)
mtspr SPRN_AMR, r0
mtspr SPRN_IAMR, r0
mtspr SPRN_CIABR, r0
- mtspr SPRN_DAWRX, r0
+ mtspr SPRN_DAWRX0, r0
BEGIN_MMU_FTR_SECTION
b 4f
diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c
index 7af840c0fc93..d4dba8ea8995 100644
--- a/arch/powerpc/xmon/xmon.c
+++ b/arch/powerpc/xmon/xmon.c
@@ -1939,7 +1939,7 @@ static void dump_207_sprs(void)
printf("hfscr = %.16lx dhdes = %.16lx rpr = %.16lx\n",
mfspr(SPRN_HFSCR), mfspr(SPRN_DHDES), mfspr(SPRN_RPR));
printf("dawr = %.16lx dawrx = %.16lx ciabr = %.16lx\n",
- mfspr(SPRN_DAWR), mfspr(SPRN_DAWRX), mfspr(SPRN_CIABR));
+ mfspr(SPRN_DAWR0), mfspr(SPRN_DAWRX0), mfspr(SPRN_CIABR));
#endif
}
--
2.21.1
^ permalink raw reply related
* [PATCH v3 02/16] powerpc/watchpoint: Add SPRN macros for second DAWR
From: Ravi Bangoria @ 2020-04-14 3:16 UTC (permalink / raw)
To: mpe, mikey
Cc: apopple, ravi.bangoria, peterz, fweisbec, oleg, npiggin,
linux-kernel, paulus, jolsa, naveen.n.rao, linuxppc-dev, mingo
In-Reply-To: <20200414031659.58875-1-ravi.bangoria@linux.ibm.com>
Future Power architecture is introducing second DAWR. Add SPRN_ macros
for the same.
Signed-off-by: Ravi Bangoria <ravi.bangoria@linux.ibm.com>
---
arch/powerpc/include/asm/reg.h | 2 ++
1 file changed, 2 insertions(+)
diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h
index 156ee89fa9be..062e74cf41fd 100644
--- a/arch/powerpc/include/asm/reg.h
+++ b/arch/powerpc/include/asm/reg.h
@@ -284,6 +284,7 @@
#define CTRL_TE 0x00c00000 /* thread enable */
#define CTRL_RUNLATCH 0x1
#define SPRN_DAWR0 0xB4
+#define SPRN_DAWR1 0xB5
#define SPRN_RPR 0xBA /* Relative Priority Register */
#define SPRN_CIABR 0xBB
#define CIABR_PRIV 0x3
@@ -291,6 +292,7 @@
#define CIABR_PRIV_SUPER 2
#define CIABR_PRIV_HYPER 3
#define SPRN_DAWRX0 0xBC
+#define SPRN_DAWRX1 0xBD
#define DAWRX_USER __MASK(0)
#define DAWRX_KERNEL __MASK(1)
#define DAWRX_HYP __MASK(2)
--
2.21.1
^ permalink raw reply related
* [PATCH v3 03/16] powerpc/watchpoint: Introduce function to get nr watchpoints dynamically
From: Ravi Bangoria @ 2020-04-14 3:16 UTC (permalink / raw)
To: mpe, mikey
Cc: apopple, ravi.bangoria, peterz, fweisbec, oleg, npiggin,
linux-kernel, paulus, jolsa, naveen.n.rao, linuxppc-dev, mingo
In-Reply-To: <20200414031659.58875-1-ravi.bangoria@linux.ibm.com>
So far we had only one watchpoint, so we have hardcoded HBP_NUM to 1.
But future Power architecture is introducing 2nd DAWR and thus kernel
should be able to dynamically find actual number of watchpoints
supported by hw it's running on. Introduce function for the same.
Also convert HBP_NUM macro to HBP_NUM_MAX, which will now represent
maximum number of watchpoints supported by Powerpc.
Signed-off-by: Ravi Bangoria <ravi.bangoria@linux.ibm.com>
---
arch/powerpc/include/asm/cputable.h | 6 +++++-
arch/powerpc/include/asm/hw_breakpoint.h | 5 +++++
arch/powerpc/include/asm/processor.h | 2 +-
arch/powerpc/kernel/hw_breakpoint.c | 2 +-
4 files changed, 12 insertions(+), 3 deletions(-)
diff --git a/arch/powerpc/include/asm/cputable.h b/arch/powerpc/include/asm/cputable.h
index 40a4d3c6fd99..c67b94f3334c 100644
--- a/arch/powerpc/include/asm/cputable.h
+++ b/arch/powerpc/include/asm/cputable.h
@@ -614,7 +614,11 @@ enum {
};
#endif /* __powerpc64__ */
-#define HBP_NUM 1
+/*
+ * Maximum number of hw breakpoint supported on powerpc. Number of
+ * breakpoints supported by actual hw might be less than this.
+ */
+#define HBP_NUM_MAX 1
#endif /* !__ASSEMBLY__ */
diff --git a/arch/powerpc/include/asm/hw_breakpoint.h b/arch/powerpc/include/asm/hw_breakpoint.h
index f2f8d8aa8e3b..518b41eef924 100644
--- a/arch/powerpc/include/asm/hw_breakpoint.h
+++ b/arch/powerpc/include/asm/hw_breakpoint.h
@@ -43,6 +43,11 @@ struct arch_hw_breakpoint {
#define DABR_MAX_LEN 8
#define DAWR_MAX_LEN 512
+static inline int nr_wp_slots(void)
+{
+ return HBP_NUM_MAX;
+}
+
#ifdef CONFIG_HAVE_HW_BREAKPOINT
#include <linux/kdebug.h>
#include <asm/reg.h>
diff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h
index eedcbfb9a6ff..90f6dbc7ff00 100644
--- a/arch/powerpc/include/asm/processor.h
+++ b/arch/powerpc/include/asm/processor.h
@@ -180,7 +180,7 @@ struct thread_struct {
int fpexc_mode; /* floating-point exception mode */
unsigned int align_ctl; /* alignment handling control */
#ifdef CONFIG_HAVE_HW_BREAKPOINT
- struct perf_event *ptrace_bps[HBP_NUM];
+ struct perf_event *ptrace_bps[HBP_NUM_MAX];
/*
* Helps identify source of single-step exception and subsequent
* hw-breakpoint enablement
diff --git a/arch/powerpc/kernel/hw_breakpoint.c b/arch/powerpc/kernel/hw_breakpoint.c
index 72f461bd70fb..4120349e2abe 100644
--- a/arch/powerpc/kernel/hw_breakpoint.c
+++ b/arch/powerpc/kernel/hw_breakpoint.c
@@ -38,7 +38,7 @@ static DEFINE_PER_CPU(struct perf_event *, bp_per_reg);
int hw_breakpoint_slots(int type)
{
if (type == TYPE_DATA)
- return HBP_NUM;
+ return nr_wp_slots();
return 0; /* no instruction breakpoints available */
}
--
2.21.1
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox