mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: "Sheetal ." <sheetal@nvidia.com>
To: Thierry Reding <thierry.reding@kernel.org>
Cc: Liam Girdwood <lgirdwood@gmail.com>,
	Mark Brown <broonie@kernel.org>, Jaroslav Kysela <perex@perex.cz>,
	Takashi Iwai <tiwai@suse.com>,
	Jonathan Hunter <jonathanh@nvidia.com>,
	Sameer Pujar <spujar@nvidia.com>,
	Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>,
	Mohan Kumar <mkumard@nvidia.com>,
	linux-sound@vger.kernel.org, linux-tegra@vger.kernel.org,
	linux-kernel@vger.kernel.org
Subject: Re: [RFC PATCH 2/3] ASoC: tegra: Update ASRC ratio controls
Date: Mon, 28 Sep 2026 17:59:10 +0530	[thread overview]
Message-ID: <0b9d5bb0-2fac-4106-90cf-ecab1e80109b@nvidia.com> (raw)
In-Reply-To: <arEYfjIHa4w--rTE@orome>



On 21-09-2026 17:20, Thierry Reding wrote:
> On Mon, Sep 21, 2026 at 08:57:03AM +0000, Sheetal wrote:
>> Replace the separate integer and fractional ASRC ratio controls with a
>> single two-value control for each stream. This is a userspace-visible
>> control ABI change, but:
>>
>> 1. Keeping writable compatibility controls would preserve the non-atomic
>>     update path that can expose a transient mixed ratio to hardware.
>> 2. This is limited to only the Tegra ASRC driver.
>>
>> Validate both values before programming hardware. The fractional field
>> keeps the existing 32-bit maximum, while the integer field is rejected
>> when it exceeds the hardware field width.
>>
>> ALSA exposes one min and max range for all values in an integer-array
>> control, so the paired ratio controls advertise the fractional field's
>> full 32-bit range. The put callback validates the integer part separately
>> against the hardware field width.
>>
>> Serialize ratio-source changes, stream setup, and ratio updates with a
>> driver mutex so cached ratio state and paired hardware programming remain
>> consistent.
>>
>> Unlock and re-lock the ASRC stream before programming a software ratio
>> when the new ratio differs from the cached ratio by more than 20%.
>> Large ratio jumps require the hardware lock to be refreshed around the
>> paired integer/fractional update.
>>
>> Roll back the previous hardware pair and lock state if a paired ratio
>> update fails after partially programming the hardware.
>>
>> Signed-off-by: Sheetal <sheetal@nvidia.com>
>> ---
>>   sound/soc/tegra/tegra186_asrc.c | 443 ++++++++++++++++++++------------
>>   sound/soc/tegra/tegra186_asrc.h |   4 +
>>   2 files changed, 276 insertions(+), 171 deletions(-)
>>
>> diff --git a/sound/soc/tegra/tegra186_asrc.c b/sound/soc/tegra/tegra186_asrc.c
>> index d8ae5d997615..2b67d23f5fa7 100644
>> --- a/sound/soc/tegra/tegra186_asrc.c
>> +++ b/sound/soc/tegra/tegra186_asrc.c
>> @@ -19,6 +19,9 @@
>>   #include "tegra186_asrc.h"
>>   #include "tegra_cif.h"
>>   
>> +#define TEGRA186_ASRC_RATIO_PERCENT_SCALE		100
>> +#define TEGRA186_ASRC_RATIO_UNLOCK_THRESHOLD_PERCENT	20
>> +
>>   #define ASRC_STREAM_SOURCE_SELECT(id)					       \
>>   	(TEGRA186_ASRC_CFG + ((id) * TEGRA186_ASRC_STREAM_STRIDE))
>>   
>> @@ -65,13 +68,125 @@ static const struct reg_default tegra186_asrc_reg_defaults[] = {
>>   	{ TEGRA186_ASRC_CYA, 0x0},
>>   };
>>   
>> -static void tegra186_asrc_lock_stream(struct tegra186_asrc *asrc,
>> -				      unsigned int id)
>> +static int tegra186_asrc_set_stream_lock(struct tegra186_asrc *asrc,
>> +					 unsigned int id, bool lock)
>>   {
>> -	regmap_write(asrc->regmap,
>> -		     ASRC_STREAM_REG(TEGRA186_ASRC_RATIO_LOCK_STATUS,
>> -				     id),
>> -		     1);
>> +	return regmap_write(asrc->regmap,
>> +			    ASRC_STREAM_REG(TEGRA186_ASRC_RATIO_LOCK_STATUS,
>> +					    id),
>> +			    lock);
>> +}
>> +
>> +static int tegra186_asrc_write_ratio_pair(struct tegra186_asrc *asrc,
>> +					  unsigned int id,
>> +					  unsigned int int_part,
>> +					  unsigned int frac_part)
>> +{
>> +	int ret;
>> +
>> +	ret = regmap_write(asrc->regmap,
>> +			   ASRC_STREAM_REG(TEGRA186_ASRC_RATIO_INT_PART, id),
>> +			   int_part);
>> +	if (ret)
>> +		return ret;
>> +
>> +	return regmap_write(asrc->regmap,
>> +			    ASRC_STREAM_REG(TEGRA186_ASRC_RATIO_FRAC_PART, id),
>> +			    frac_part);
>> +}
>> +
>> +static int tegra186_asrc_read_ratio_pair(struct tegra186_asrc *asrc,
>> +					 unsigned int id, unsigned int *int_part,
>> +					 unsigned int *frac_part)
>> +{
>> +	int ret;
>> +
>> +	ret = regmap_read(asrc->regmap,
>> +			  ASRC_STREAM_REG(TEGRA186_ASRC_RATIO_INT_PART, id),
>> +			  int_part);
>> +	if (ret)
>> +		return ret;
>> +
>> +	return regmap_read(asrc->regmap,
>> +			   ASRC_STREAM_REG(TEGRA186_ASRC_RATIO_FRAC_PART, id),
>> +			   frac_part);
>> +}
>> +
>> +static void tegra186_asrc_cache_ratio(struct tegra186_asrc *asrc,
>> +				      unsigned int id, unsigned int int_part,
>> +				      unsigned int frac_part)
>> +{
>> +	asrc->lane[id].int_part = int_part;
>> +	asrc->lane[id].frac_part = frac_part;
>> +}
>> +
>> +static int tegra186_asrc_apply_ratio(struct tegra186_asrc *asrc,
>> +				     unsigned int id, unsigned int int_part,
>> +				     unsigned int frac_part, bool unlock)
>> +{
>> +	unsigned int old_int_part, old_frac_part, old_lock;
>> +	int ret, restore_ret;
>> +
>> +	ret = tegra186_asrc_read_ratio_pair(asrc, id, &old_int_part,
>> +					    &old_frac_part);
>> +	if (ret)
>> +		return ret;
>> +
>> +	ret = regmap_read(asrc->regmap,
>> +			  ASRC_STREAM_REG(TEGRA186_ASRC_RATIO_LOCK_STATUS, id),
>> +			  &old_lock);
>> +	if (ret)
>> +		return ret;
>> +
>> +	if (unlock) {
>> +		ret = tegra186_asrc_set_stream_lock(asrc, id, false);
>> +		if (ret)
>> +			return ret;
>> +	}
>> +
>> +	ret = tegra186_asrc_write_ratio_pair(asrc, id, int_part, frac_part);
>> +	if (ret)
>> +		goto restore_ratio;
>> +
>> +	ret = tegra186_asrc_set_stream_lock(asrc, id, true);
>> +	if (!ret)
>> +		return 0;
>> +
>> +restore_ratio:
>> +	restore_ret = tegra186_asrc_write_ratio_pair(asrc, id,
>> +						     old_int_part,
>> +						     old_frac_part);
>> +	if (!restore_ret) {
>> +		if (old_lock)
>> +			restore_ret = tegra186_asrc_set_stream_lock(asrc, id,
>> +								    true);
>> +		else
>> +			restore_ret = tegra186_asrc_set_stream_lock(asrc, id,
>> +								    false);
>> +	}
>> +
>> +	return ret ?: restore_ret;
>> +}
>> +
>> +static int tegra186_asrc_apply_cached_ratio(struct tegra186_asrc *asrc,
>> +					    unsigned int id)
>> +{
>> +	return tegra186_asrc_apply_ratio(asrc, id, asrc->lane[id].int_part,
>> +					asrc->lane[id].frac_part, false);
>> +}
>> +
>> +static bool tegra186_asrc_need_unlock(u64 old_ratio, u64 new_ratio)
>> +{
>> +	u64 ratio_diff;
>> +
>> +	if (!old_ratio || !new_ratio)
>> +		return false;
>> +
>> +	ratio_diff = (old_ratio > new_ratio) ?
>> +		     (old_ratio - new_ratio) : (new_ratio - old_ratio);
>> +
>> +	return ((ratio_diff * TEGRA186_ASRC_RATIO_PERCENT_SCALE) >
>> +		(old_ratio * TEGRA186_ASRC_RATIO_UNLOCK_THRESHOLD_PERCENT));
>>   }
> 
> There's a fair bit of complication introduced by the concept of locking
> here, so I wonder what the impact of this is. The function name implies
> that sometimes unlocking is needed and sometimes it isn't.
> 
> What if we unlock unconditionally? That doesn't get rid of all the
> locking and unlocking, but at least it would avoid the need to track the
> current locking status.
> 
> The unlock operation doesn't seem overly expensive, so maybe it isn't
> worth trying to avoid it?
> 
> [...]


This follows the ASRC hardware programming sequence. SW can update 
ratios directly for changes below 20%, but must unlock/relock the stream 
for changes above 20%. I would prefer not to unlock/relock for every 
ratio change because stream locking takes some time and would delay 
configuration unnecessarily for small ratio updates.


>> diff --git a/sound/soc/tegra/tegra186_asrc.h b/sound/soc/tegra/tegra186_asrc.h
>> index 0c98e26d5e72..9cc8cec6c204 100644
>> --- a/sound/soc/tegra/tegra186_asrc.h
>> +++ b/sound/soc/tegra/tegra186_asrc.h
>> @@ -7,6 +7,8 @@
>>   #ifndef __TEGRA186_ASRC_H__
>>   #define __TEGRA186_ASRC_H__
>>   
>> +#include <linux/mutex.h>
>> +
>>   /* ASRC stream related offset */
>>   #define TEGRA186_ASRC_CFG				0x0
>>   #define TEGRA186_ASRC_RATIO_INT_PART			0x4
>> @@ -111,6 +113,8 @@ struct tegra186_asrc {
>>   	const struct tegra_asrc_soc_data *soc_data;
>>   	struct tegra186_asrc_lane lane[TEGRA186_ASRC_STREAM_MAX];
>>   	struct regmap *regmap;
>> +	/* Serializes ratio source, cache, and paired register updates. */
>> +	struct mutex ratio_lock;
> 
> All of the operations that are serialized by this lock seem to be non-
> sleeping register or cache updates. Could the lock be turned into a
> spinlock instead?


I think this should remain a mutex. The protected paths call regmap and 
runtime PM helpers, which can sleep.


> 
> Thierry


  reply	other threads:[~2026-09-28 12:29 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-21  8:57 [RFC PATCH 0/3] ASoC: tegra: ASRC control fixes and ratio caching Sheetal
2026-09-21  8:57 ` [RFC PATCH 1/3] ASoC: tegra: Fix ASRC Stream6 input threshold control Sheetal
2026-09-21 11:38   ` Thierry Reding
2026-09-21  8:57 ` [RFC PATCH 2/3] ASoC: tegra: Update ASRC ratio controls Sheetal
2026-09-21 11:50   ` Thierry Reding
2026-09-28 12:29     ` Sheetal . [this message]
2026-09-21  8:57 ` [RFC PATCH 3/3] ASoC: tegra: Cache ASRC ratios until streams are active Sheetal
2026-09-21 12:07 ` [RFC PATCH 0/3] ASoC: tegra: ASRC control fixes and ratio caching Thierry Reding
2026-09-21 12:51   ` Mark Brown

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=0b9d5bb0-2fac-4106-90cf-ecab1e80109b@nvidia.com \
    --to=sheetal@nvidia.com \
    --cc=broonie@kernel.org \
    --cc=jonathanh@nvidia.com \
    --cc=kuninori.morimoto.gx@renesas.com \
    --cc=lgirdwood@gmail.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-sound@vger.kernel.org \
    --cc=linux-tegra@vger.kernel.org \
    --cc=mkumard@nvidia.com \
    --cc=perex@perex.cz \
    --cc=spujar@nvidia.com \
    --cc=thierry.reding@kernel.org \
    --cc=tiwai@suse.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®