ASoC: da7219: check SRM lock in trigger callback
diff mbox series

Message ID 1581322611-25695-1-git-send-email-brent.lu@intel.com
State New
Headers show
Series
  • ASoC: da7219: check SRM lock in trigger callback
Related show

Commit Message

Lu, Brent Feb. 10, 2020, 8:16 a.m. UTC
Intel sst firmware turns on BCLK/WCLK in START Ioctl call which timing is
later than the DAPM SUPPLY event handler da7219_dai_event is called (in
PREPARED state). Therefore, the SRM lock check always fail.

Moving the check to trigger callback could ensure the SRM is locked before
DSP starts to process data and avoid possisble noise.

Signed-off-by: Brent Lu <brent.lu@intel.com>
---
 sound/soc/codecs/da7219.c | 68 +++++++++++++++++++++++++++++++----------------
 1 file changed, 45 insertions(+), 23 deletions(-)

Comments

Pierre-Louis Bossart Feb. 10, 2020, 2:18 p.m. UTC | #1
On 2/10/20 2:16 AM, Brent Lu wrote:
> Intel sst firmware turns on BCLK/WCLK in START Ioctl call which timing is
> later than the DAPM SUPPLY event handler da7219_dai_event is called (in
> PREPARED state). Therefore, the SRM lock check always fail.
> 
> Moving the check to trigger callback could ensure the SRM is locked before
> DSP starts to process data and avoid possisble noise.

This codec is used quite a bit by Chromebooks across multiple 
generations and with both SST and SOF drivers, we need to be careful 
about changes.
I am personally not aware of any issues and never saw an 'SRM failed to 
lock message'. On which platform did you see a problem?

> 
> Signed-off-by: Brent Lu <brent.lu@intel.com>
> ---
>   sound/soc/codecs/da7219.c | 68 +++++++++++++++++++++++++++++++----------------
>   1 file changed, 45 insertions(+), 23 deletions(-)
> 
> diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c
> index f83a6ea..0fb5ea5 100644
> --- a/sound/soc/codecs/da7219.c
> +++ b/sound/soc/codecs/da7219.c
> @@ -794,9 +794,7 @@ static int da7219_dai_event(struct snd_soc_dapm_widget *w,
>   	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
>   	struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
>   	struct clk *bclk = da7219->dai_clks[DA7219_DAI_BCLK_IDX];
> -	u8 pll_ctrl, pll_status;
> -	int i = 0, ret;
> -	bool srm_lock = false;
> +	int ret;
>   
>   	switch (event) {
>   	case SND_SOC_DAPM_PRE_PMU:
> @@ -820,26 +818,6 @@ static int da7219_dai_event(struct snd_soc_dapm_widget *w,
>   		/* PC synchronised to DAI */
>   		snd_soc_component_update_bits(component, DA7219_PC_COUNT,
>   				    DA7219_PC_FREERUN_MASK, 0);
> -
> -		/* Slave mode, if SRM not enabled no need for status checks */
> -		pll_ctrl = snd_soc_component_read32(component, DA7219_PLL_CTRL);
> -		if ((pll_ctrl & DA7219_PLL_MODE_MASK) != DA7219_PLL_MODE_SRM)
> -			return 0;
> -
> -		/* Check SRM has locked */
> -		do {
> -			pll_status = snd_soc_component_read32(component, DA7219_PLL_SRM_STS);
> -			if (pll_status & DA7219_PLL_SRM_STS_SRM_LOCK) {
> -				srm_lock = true;
> -			} else {
> -				++i;
> -				msleep(50);
> -			}
> -		} while ((i < DA7219_SRM_CHECK_RETRIES) && (!srm_lock));
> -
> -		if (!srm_lock)
> -			dev_warn(component->dev, "SRM failed to lock\n");
> -
>   		return 0;
>   	case SND_SOC_DAPM_POST_PMD:
>   		/* PC free-running */
> @@ -1658,12 +1636,56 @@ static int da7219_hw_params(struct snd_pcm_substream *substream,
>   	return 0;
>   }
>   
> +static int da7219_set_dai_trigger(struct snd_pcm_substream *substream, int cmd,
> +				  struct snd_soc_dai *dai)
> +{
> +	struct snd_soc_component *component = dai->component;
> +	u8 pll_ctrl, pll_status;
> +	int i = 0;
> +	bool srm_lock = false;
> +
> +	switch (cmd) {
> +	case SNDRV_PCM_TRIGGER_START:
> +		/* Slave mode, if SRM not enabled no need for status checks */
> +		pll_ctrl = snd_soc_component_read32(component, DA7219_PLL_CTRL);
> +		if ((pll_ctrl & DA7219_PLL_MODE_MASK) != DA7219_PLL_MODE_SRM)
> +			return 0;
> +
> +		/* Check SRM has locked */
> +		do {
> +			pll_status = snd_soc_component_read32(component,
> +							DA7219_PLL_SRM_STS);
> +			if (pll_status & DA7219_PLL_SRM_STS_SRM_LOCK) {
> +				srm_lock = true;
> +			} else {
> +				++i;
> +				msleep(50);
> +			}
> +		} while ((i < DA7219_SRM_CHECK_RETRIES) && (!srm_lock));
> +
> +		if (!srm_lock)
> +			dev_warn(component->dev, "SRM failed to lock\n");
> +
> +		break;
> +	case SNDRV_PCM_TRIGGER_RESUME:
> +	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
> +	case SNDRV_PCM_TRIGGER_STOP:
> +	case SNDRV_PCM_TRIGGER_SUSPEND:
> +	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
> +	default:
> +		break;
> +	}
> +
> +	return 0;
> +}
> +
>   static const struct snd_soc_dai_ops da7219_dai_ops = {
>   	.hw_params	= da7219_hw_params,
>   	.set_sysclk	= da7219_set_dai_sysclk,
>   	.set_pll	= da7219_set_dai_pll,
>   	.set_fmt	= da7219_set_dai_fmt,
>   	.set_tdm_slot	= da7219_set_dai_tdm_slot,
> +	.trigger	= da7219_set_dai_trigger,
>   };
>   
>   #define DA7219_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
>
Adam Thomson Feb. 10, 2020, 2:32 p.m. UTC | #2
On 10 February 2020 08:17, Brent Lu wrote:

> Intel sst firmware turns on BCLK/WCLK in START Ioctl call which timing is
> later than the DAPM SUPPLY event handler da7219_dai_event is called (in
> PREPARED state). Therefore, the SRM lock check always fail.
> 
> Moving the check to trigger callback could ensure the SRM is locked before
> DSP starts to process data and avoid possisble noise.

Could ensure? This change seems specific to Intel DSP based systems, at least
from the description. Having looked through the core, the trigger code for a
codec is seemingly always called before the trigger for the CPU. How will this
work for other platforms, assuming their clocks are enabled in the CPU DAI
trigger function by default?

Can we always guarantee the CPU side isn't going to send anything other than 0s
until after SRM has locked?

> 
> Signed-off-by: Brent Lu <brent.lu@intel.com>
> ---
>  sound/soc/codecs/da7219.c | 68 +++++++++++++++++++++++++++++++--------
> --------
>  1 file changed, 45 insertions(+), 23 deletions(-)
> 
> diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c
> index f83a6ea..0fb5ea5 100644
> --- a/sound/soc/codecs/da7219.c
> +++ b/sound/soc/codecs/da7219.c
> @@ -794,9 +794,7 @@ static int da7219_dai_event(struct snd_soc_dapm_widget
> *w,
>  	struct snd_soc_component *component =
> snd_soc_dapm_to_component(w->dapm);
>  	struct da7219_priv *da7219 =
> snd_soc_component_get_drvdata(component);
>  	struct clk *bclk = da7219->dai_clks[DA7219_DAI_BCLK_IDX];
> -	u8 pll_ctrl, pll_status;
> -	int i = 0, ret;
> -	bool srm_lock = false;
> +	int ret;
> 
>  	switch (event) {
>  	case SND_SOC_DAPM_PRE_PMU:
> @@ -820,26 +818,6 @@ static int da7219_dai_event(struct
> snd_soc_dapm_widget *w,
>  		/* PC synchronised to DAI */
>  		snd_soc_component_update_bits(component,
> DA7219_PC_COUNT,
>  				    DA7219_PC_FREERUN_MASK, 0);
> -
> -		/* Slave mode, if SRM not enabled no need for status checks */
> -		pll_ctrl = snd_soc_component_read32(component,
> DA7219_PLL_CTRL);
> -		if ((pll_ctrl & DA7219_PLL_MODE_MASK) !=
> DA7219_PLL_MODE_SRM)
> -			return 0;
> -
> -		/* Check SRM has locked */
> -		do {
> -			pll_status = snd_soc_component_read32(component,
> DA7219_PLL_SRM_STS);
> -			if (pll_status & DA7219_PLL_SRM_STS_SRM_LOCK) {
> -				srm_lock = true;
> -			} else {
> -				++i;
> -				msleep(50);
> -			}
> -		} while ((i < DA7219_SRM_CHECK_RETRIES) && (!srm_lock));
> -
> -		if (!srm_lock)
> -			dev_warn(component->dev, "SRM failed to lock\n");
> -
>  		return 0;
>  	case SND_SOC_DAPM_POST_PMD:
>  		/* PC free-running */
> @@ -1658,12 +1636,56 @@ static int da7219_hw_params(struct
> snd_pcm_substream *substream,
>  	return 0;
>  }
> 
> +static int da7219_set_dai_trigger(struct snd_pcm_substream *substream, int
> cmd,
> +				  struct snd_soc_dai *dai)
> +{
> +	struct snd_soc_component *component = dai->component;
> +	u8 pll_ctrl, pll_status;
> +	int i = 0;
> +	bool srm_lock = false;
> +
> +	switch (cmd) {
> +	case SNDRV_PCM_TRIGGER_START:
> +		/* Slave mode, if SRM not enabled no need for status checks */
> +		pll_ctrl = snd_soc_component_read32(component,
> DA7219_PLL_CTRL);

I was under the impression that 'trigger()' was atomic? We'd have to have
some kind of workqueue to do all of this, which means we'd almost certainly lose
some PCM data at the start of a stream.

> +		if ((pll_ctrl & DA7219_PLL_MODE_MASK) !=
> DA7219_PLL_MODE_SRM)
> +			return 0;
> +
> +		/* Check SRM has locked */
> +		do {
> +			pll_status = snd_soc_component_read32(component,
> +							DA7219_PLL_SRM_STS);
> +			if (pll_status & DA7219_PLL_SRM_STS_SRM_LOCK) {
> +				srm_lock = true;
> +			} else {
> +				++i;
> +				msleep(50);
> +			}
> +		} while ((i < DA7219_SRM_CHECK_RETRIES) && (!srm_lock));
> +
> +		if (!srm_lock)
> +			dev_warn(component->dev, "SRM failed to lock\n");
> +
> +		break;
> +	case SNDRV_PCM_TRIGGER_RESUME:
> +	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
> +	case SNDRV_PCM_TRIGGER_STOP:
> +	case SNDRV_PCM_TRIGGER_SUSPEND:
> +	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
> +	default:
> +		break;
> +	}
> +
> +	return 0;
> +}
> +
>  static const struct snd_soc_dai_ops da7219_dai_ops = {
>  	.hw_params	= da7219_hw_params,
>  	.set_sysclk	= da7219_set_dai_sysclk,
>  	.set_pll	= da7219_set_dai_pll,
>  	.set_fmt	= da7219_set_dai_fmt,
>  	.set_tdm_slot	= da7219_set_dai_tdm_slot,
> +	.trigger	= da7219_set_dai_trigger,
>  };
> 
>  #define DA7219_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |
> SNDRV_PCM_FMTBIT_S20_3LE |\
> --
> 2.7.4
Curtis Malainey Feb. 10, 2020, 3:44 p.m. UTC | #3
+Jimmy Cheng-Yi Chiang <cychiang@google.com>

This error is causing pcm_open commands to fail timing requirements,
sometimes taking +500ms to open the PCM as a result. This work around is
required so we can meet the timing requirements. The bug is explained in
detail here https://github.com/thesofproject/sof/issues/2124


On Mon, Feb 10, 2020 at 6:44 AM Pierre-Louis Bossart <
pierre-louis.bossart@linux.intel.com> wrote:

>
>
> On 2/10/20 2:16 AM, Brent Lu wrote:
> > Intel sst firmware turns on BCLK/WCLK in START Ioctl call which timing is
> > later than the DAPM SUPPLY event handler da7219_dai_event is called (in
> > PREPARED state). Therefore, the SRM lock check always fail.
> >
> > Moving the check to trigger callback could ensure the SRM is locked
> before
> > DSP starts to process data and avoid possisble noise.
>
> This codec is used quite a bit by Chromebooks across multiple
> generations and with both SST and SOF drivers, we need to be careful
> about changes.
> I am personally not aware of any issues and never saw an 'SRM failed to
> lock message'. On which platform did you see a problem?
>
> >
> > Signed-off-by: Brent Lu <brent.lu@intel.com>
> > ---
> >   sound/soc/codecs/da7219.c | 68
> +++++++++++++++++++++++++++++++----------------
> >   1 file changed, 45 insertions(+), 23 deletions(-)
> >
> > diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c
> > index f83a6ea..0fb5ea5 100644
> > --- a/sound/soc/codecs/da7219.c
> > +++ b/sound/soc/codecs/da7219.c
> > @@ -794,9 +794,7 @@ static int da7219_dai_event(struct
> snd_soc_dapm_widget *w,
> >       struct snd_soc_component *component =
> snd_soc_dapm_to_component(w->dapm);
> >       struct da7219_priv *da7219 =
> snd_soc_component_get_drvdata(component);
> >       struct clk *bclk = da7219->dai_clks[DA7219_DAI_BCLK_IDX];
> > -     u8 pll_ctrl, pll_status;
> > -     int i = 0, ret;
> > -     bool srm_lock = false;
> > +     int ret;
> >
> >       switch (event) {
> >       case SND_SOC_DAPM_PRE_PMU:
> > @@ -820,26 +818,6 @@ static int da7219_dai_event(struct
> snd_soc_dapm_widget *w,
> >               /* PC synchronised to DAI */
> >               snd_soc_component_update_bits(component, DA7219_PC_COUNT,
> >                                   DA7219_PC_FREERUN_MASK, 0);
> > -
> > -             /* Slave mode, if SRM not enabled no need for status
> checks */
> > -             pll_ctrl = snd_soc_component_read32(component,
> DA7219_PLL_CTRL);
> > -             if ((pll_ctrl & DA7219_PLL_MODE_MASK) !=
> DA7219_PLL_MODE_SRM)
> > -                     return 0;
> > -
> > -             /* Check SRM has locked */
> > -             do {
> > -                     pll_status = snd_soc_component_read32(component,
> DA7219_PLL_SRM_STS);
> > -                     if (pll_status & DA7219_PLL_SRM_STS_SRM_LOCK) {
> > -                             srm_lock = true;
> > -                     } else {
> > -                             ++i;
> > -                             msleep(50);
> > -                     }
> > -             } while ((i < DA7219_SRM_CHECK_RETRIES) && (!srm_lock));
> > -
> > -             if (!srm_lock)
> > -                     dev_warn(component->dev, "SRM failed to lock\n");
> > -
> >               return 0;
> >       case SND_SOC_DAPM_POST_PMD:
> >               /* PC free-running */
> > @@ -1658,12 +1636,56 @@ static int da7219_hw_params(struct
> snd_pcm_substream *substream,
> >       return 0;
> >   }
> >
> > +static int da7219_set_dai_trigger(struct snd_pcm_substream *substream,
> int cmd,
> > +                               struct snd_soc_dai *dai)
> > +{
> > +     struct snd_soc_component *component = dai->component;
> > +     u8 pll_ctrl, pll_status;
> > +     int i = 0;
> > +     bool srm_lock = false;
> > +
> > +     switch (cmd) {
> > +     case SNDRV_PCM_TRIGGER_START:
> > +             /* Slave mode, if SRM not enabled no need for status
> checks */
> > +             pll_ctrl = snd_soc_component_read32(component,
> DA7219_PLL_CTRL);
> > +             if ((pll_ctrl & DA7219_PLL_MODE_MASK) !=
> DA7219_PLL_MODE_SRM)
> > +                     return 0;
> > +
> > +             /* Check SRM has locked */
> > +             do {
> > +                     pll_status = snd_soc_component_read32(component,
> > +
>  DA7219_PLL_SRM_STS);
> > +                     if (pll_status & DA7219_PLL_SRM_STS_SRM_LOCK) {
> > +                             srm_lock = true;
> > +                     } else {
> > +                             ++i;
> > +                             msleep(50);
> > +                     }
> > +             } while ((i < DA7219_SRM_CHECK_RETRIES) && (!srm_lock));
> > +
> > +             if (!srm_lock)
> > +                     dev_warn(component->dev, "SRM failed to lock\n");
> > +
> > +             break;
> > +     case SNDRV_PCM_TRIGGER_RESUME:
> > +     case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
> > +     case SNDRV_PCM_TRIGGER_STOP:
> > +     case SNDRV_PCM_TRIGGER_SUSPEND:
> > +     case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
> > +     default:
> > +             break;
> > +     }
> > +
> > +     return 0;
> > +}
> > +
> >   static const struct snd_soc_dai_ops da7219_dai_ops = {
> >       .hw_params      = da7219_hw_params,
> >       .set_sysclk     = da7219_set_dai_sysclk,
> >       .set_pll        = da7219_set_dai_pll,
> >       .set_fmt        = da7219_set_dai_fmt,
> >       .set_tdm_slot   = da7219_set_dai_tdm_slot,
> > +     .trigger        = da7219_set_dai_trigger,
> >   };
> >
> >   #define DA7219_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |
> SNDRV_PCM_FMTBIT_S20_3LE |\
> >
> _______________________________________________
> Alsa-devel mailing list
> Alsa-devel@alsa-project.org
> https://mailman.alsa-project.org/mailman/listinfo/alsa-devel
>
Pierre-Louis Bossart Feb. 10, 2020, 4:07 p.m. UTC | #4
On 2/10/20 9:44 AM, Curtis Malainey wrote:
> +Jimmy Cheng-Yi Chiang <cychiang@google.com>
> 
> This error is causing pcm_open commands to fail timing requirements,
> sometimes taking +500ms to open the PCM as a result. This work around is
> required so we can meet the timing requirements. The bug is explained in
> detail here https://github.com/thesofproject/sof/issues/2124

Ah, thanks for the pointer, but this still does not tell me if it's a 
GLK-only issue or not. And if yes, there are alternate proposals 
discussed in that issue #2124, which has been idle since November 25.

What I am really worried is side effects on unrelated platforms.
Curtis Malainey Feb. 10, 2020, 4:18 p.m. UTC | #5
+Fletcher Woodruff <fletcherw@google.com>
See comment #3 in the bug. This is not a GLK specific issue. If I remember
correctly Fletcher found that this was occurring on 2-3 platforms. SST has
the ability to turn on clocks on demand which is why this has not been an
issue previously from what I understand on the bug.

And that is a fair point, we do need to consider other users of the codec.


On Mon, Feb 10, 2020 at 8:07 AM Pierre-Louis Bossart <
pierre-louis.bossart@linux.intel.com> wrote:

>
>
> On 2/10/20 9:44 AM, Curtis Malainey wrote:
> > +Jimmy Cheng-Yi Chiang <cychiang@google.com>
> >
> > This error is causing pcm_open commands to fail timing requirements,
> > sometimes taking +500ms to open the PCM as a result. This work around is
> > required so we can meet the timing requirements. The bug is explained in
> > detail here https://github.com/thesofproject/sof/issues/2124
>
> Ah, thanks for the pointer, but this still does not tell me if it's a
> GLK-only issue or not. And if yes, there are alternate proposals
> discussed in that issue #2124, which has been idle since November 25.
>
> What I am really worried is side effects on unrelated platforms.
>
Mark Brown Feb. 10, 2020, 6:59 p.m. UTC | #6
On Mon, Feb 10, 2020 at 04:16:51PM +0800, Brent Lu wrote:

> Intel sst firmware turns on BCLK/WCLK in START Ioctl call which timing is
> later than the DAPM SUPPLY event handler da7219_dai_event is called (in
> PREPARED state). Therefore, the SRM lock check always fail.
> 
> Moving the check to trigger callback could ensure the SRM is locked before
> DSP starts to process data and avoid possisble noise.

Independently of any other discussion trigger is expected to run very
fast so doesn't feel like a good place to do this - given that we're
talking about doing this to avoid noise the mute operation seems like a
more idiomatic place to do this, it exists to avoid playing back
glitches from the digitial interface during startup.
Fletcher Woodruff Feb. 11, 2020, 4 a.m. UTC | #7
On Tue, Feb 11, 2020 at 1:18 AM Curtis Malainey <cujomalainey@google.com> wrote:
>
> +Fletcher Woodruff
> See comment #3 in the bug. This is not a GLK specific issue. If I remember correctly Fletcher found that this was occurring on 2-3 platforms.

Yes, I tested this and saw the same bug on a Pixelbook Go which I
believe is Comet Lake.


>SST has the ability to turn on clocks on demand which is why this has not been an issue previously from what I understand on the bug.
>
> And that is a fair point, we do need to consider other users of the codec.
>
>
> On Mon, Feb 10, 2020 at 8:07 AM Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com> wrote:
>>
>>
>>
>> On 2/10/20 9:44 AM, Curtis Malainey wrote:
>> > +Jimmy Cheng-Yi Chiang <cychiang@google.com>
>> >
>> > This error is causing pcm_open commands to fail timing requirements,
>> > sometimes taking +500ms to open the PCM as a result. This work around is
>> > required so we can meet the timing requirements. The bug is explained in
>> > detail here https://github.com/thesofproject/sof/issues/2124
>>
>> Ah, thanks for the pointer, but this still does not tell me if it's a
>> GLK-only issue or not. And if yes, there are alternate proposals
>> discussed in that issue #2124, which has been idle since November 25.
>>
>> What I am really worried is side effects on unrelated platforms.
Lu, Brent Feb. 11, 2020, 10:08 a.m. UTC | #8
> 
> Could ensure? This change seems specific to Intel DSP based systems, at
> least from the description. Having looked through the core, the trigger code
> for a codec is seemingly always called before the trigger for the CPU. How will
> this work for other platforms, assuming their clocks are enabled in the CPU
> DAI trigger function by default?
> 
> Can we always guarantee the CPU side isn't going to send anything other
> than 0s until after SRM has locked?
> 

I think the patch is for those systems which enable I2S clocks in pcm_start instead
of pcm_prepare. It has no effect on systems already be able to turn on clocks in
supply widgets or set_bias_level() function.

If the trigger type in the DAI link is TRIGGER_PRE, then the trigger function of FE port
(component or CPU DAI) will be called before codec driver's trigger function. In this
case we will be able to turn on the clock in time. However, if the trigger type is
TRIGGER_POST, then the patch does not help because just like what you said, codec
driver's trigger function is called first.

In my experiment with the patch, the SRM is locked in the second read and cost
50ms to wait.

> 
> I was under the impression that 'trigger()' was atomic? We'd have to have
> some kind of workqueue to do all of this, which means we'd almost certainly
> lose some PCM data at the start of a stream.
>
Lu, Brent Feb. 11, 2020, 10:19 a.m. UTC | #9
> 
> Independently of any other discussion trigger is expected to run very fast so
> doesn't feel like a good place to do this - given that we're talking about doing
> this to avoid noise the mute operation seems like a more idiomatic place to
> do this, it exists to avoid playing back glitches from the digitial interface
> during startup.

It still take 50ms waiting for lock on in the trigger so I guess it's not a good
implementation here. And I thought digital mute is called in the pcm_prepare?
I'm afraid it does not work in our case...

Regards,
Brent
Pierre-Louis Bossart Feb. 11, 2020, 4:30 p.m. UTC | #10
>> Could ensure? This change seems specific to Intel DSP based systems, at
>> least from the description. Having looked through the core, the trigger code
>> for a codec is seemingly always called before the trigger for the CPU. How will
>> this work for other platforms, assuming their clocks are enabled in the CPU
>> DAI trigger function by default?
>>
>> Can we always guarantee the CPU side isn't going to send anything other
>> than 0s until after SRM has locked?

Not with the default mode for the SSP, all clocks are enabled at trigger 
time.
We can enable the MCLK and BCLK ahead of time (which would require a 
change in firmware). But if we want to enable the FSYNC (word-clock), 
then we have to trigger DMA transfers with pretend-buffers, this is a 
lot more invasive.

So just to be clear, which of the MCLK, BCLK, FSYNC do you need enabled?

> I think the patch is for those systems which enable I2S clocks in pcm_start instead
> of pcm_prepare. It has no effect on systems already be able to turn on clocks in
> supply widgets or set_bias_level() function.
> 
> If the trigger type in the DAI link is TRIGGER_PRE, then the trigger function of FE port
> (component or CPU DAI) will be called before codec driver's trigger function. In this
> case we will be able to turn on the clock in time. However, if the trigger type is
> TRIGGER_POST, then the patch does not help because just like what you said, codec
> driver's trigger function is called first.

IIRC we recently did a change to deal with underflows. Ranjani, can you 
remind us what the issue was?
Thanks
-Pierre
Sridharan, Ranjani Feb. 11, 2020, 8:37 p.m. UTC | #11
>
>
> > I think the patch is for those systems which enable I2S clocks in
> pcm_start instead
> > of pcm_prepare. It has no effect on systems already be able to turn on
> clocks in
> > supply widgets or set_bias_level() function.
> >
> > If the trigger type in the DAI link is TRIGGER_PRE, then the trigger
> function of FE port
> > (component or CPU DAI) will be called before codec driver's trigger
> function. In this
> > case we will be able to turn on the clock in time. However, if the
> trigger type is
> > TRIGGER_POST, then the patch does not help because just like what you
> said, codec
> > driver's trigger function is called first.
>
> IIRC we recently did a change to deal with underflows. Ranjani, can you
> remind us what the issue was?

Hi Pierre,

Are you talking about the change in this commit acbf27746ecfa96b
"ASoC: pcm: update FE/BE trigger order based on the command"?

We made this change to handle xruns during pause/release particularly on
the Intel HDA platforms.

Thanks,
Ranjani
Pierre-Louis Bossart Feb. 11, 2020, 9:12 p.m. UTC | #12
On 2/11/20 2:37 PM, Sridharan, Ranjani wrote:
> 
>      > I think the patch is for those systems which enable I2S clocks in
>     pcm_start instead
>      > of pcm_prepare. It has no effect on systems already be able to
>     turn on clocks in
>      > supply widgets or set_bias_level() function.
>      >
>      > If the trigger type in the DAI link is TRIGGER_PRE, then the
>     trigger function of FE port
>      > (component or CPU DAI) will be called before codec driver's
>     trigger function. In this
>      > case we will be able to turn on the clock in time. However, if
>     the trigger type is
>      > TRIGGER_POST, then the patch does not help because just like what
>     you said, codec
>      > driver's trigger function is called first.
> 
>     IIRC we recently did a change to deal with underflows. Ranjani, can you
>     remind us what the issue was?
> 
> Hi Pierre,
> 
> Are you talking about the change in this commit acbf27746ecfa96b
> "ASoC: pcm: update FE/BE trigger order based on the command"?
> 
> We made this change to handle xruns during pause/release particularly on 
> the Intel HDA platforms.

this change was just to mirror the behavior between start/stop, I 
thought there was a patch where we moved to TRIGGER_POST by default?

What I am trying to figure out if whether using TRIGGER_PRE is ok or not 
for the SOF firmware.

Thanks!
-Pierre
Sridharan, Ranjani Feb. 11, 2020, 9:37 p.m. UTC | #13
>
>
> >
> > Hi Pierre,
> >
> > Are you talking about the change in this commit acbf27746ecfa96b
> > "ASoC: pcm: update FE/BE trigger order based on the command"?
> >
> > We made this change to handle xruns during pause/release particularly on
> > the Intel HDA platforms.
>
> this change was just to mirror the behavior between start/stop, I
> thought there was a patch where we moved to TRIGGER_POST by default?
>
> What I am trying to figure out if whether using TRIGGER_PRE is ok or not
> for the SOF firmware.
>

Ahh yes, it was part of the same series as this one. fd274c2b7267b  "ASoC:
SOF: topology: set trigger order for FE DAI link"

TRIGGER_PRE won't really work in the case of SOF. We need the BE DAI to be
triggered before the FE DAI during start to prevent the xruns during
pause/release.

Thanks,
Ranjani
Pierre-Louis Bossart Feb. 11, 2020, 9:49 p.m. UTC | #14
>>> Are you talking about the change in this commit acbf27746ecfa96b
>>> "ASoC: pcm: update FE/BE trigger order based on the command"?
>>>
>>> We made this change to handle xruns during pause/release particularly on
>>> the Intel HDA platforms.
>>
>> this change was just to mirror the behavior between start/stop, I
>> thought there was a patch where we moved to TRIGGER_POST by default?
>>
>> What I am trying to figure out if whether using TRIGGER_PRE is ok or not
>> for the SOF firmware.
>>
> 
> Ahh yes, it was part of the same series as this one. fd274c2b7267b  "ASoC:
> SOF: topology: set trigger order for FE DAI link"
> 
> TRIGGER_PRE won't really work in the case of SOF. We need the BE DAI to be
> triggered before the FE DAI during start to prevent the xruns during
> pause/release.

Thanks Ranjani. That information closes the door on the idea of playing 
with the trigger order suggested earlier in the thread, so my guess is 
that we really need to expose the MCLK/BCLK with the clk API and turn 
them on/off from the machine driver as needed. I hope is that we don't 
need the FSYNC as well, that would be rather painful to implement.
Adam Thomson Feb. 12, 2020, 10:16 a.m. UTC | #15
On 11 February 2020 21:49, Pierre-Louis Bossart wrote:

> -----Original Message-----
> From: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
> Sent: 11 February 2020 21:49
> To: Sridharan, Ranjani <ranjani.sridharan@intel.com>
> Cc: alsa-devel@alsa-project.org; Support Opensource
> <Support.Opensource@diasemi.com>; Takashi Iwai <tiwai@suse.com>; Liam
> Girdwood <lgirdwood@gmail.com>; linux-kernel@vger.kernel.org; Chiang, Mac
> <mac.chiang@intel.com>; Mark Brown <broonie@kernel.org>; Ranjani Sridharan
> <ranjani.sridharan@linux.intel.com>; Adam Thomson
> <Adam.Thomson.Opensource@diasemi.com>; Lu, Brent <brent.lu@intel.com>;
> cychiang@google.com
> Subject: Re: [alsa-devel] [PATCH] ASoC: da7219: check SRM lock in trigger callback
> Importance: High
> 
> 
> 
> >>> Are you talking about the change in this commit acbf27746ecfa96b
> >>> "ASoC: pcm: update FE/BE trigger order based on the command"?
> >>>
> >>> We made this change to handle xruns during pause/release particularly on
> >>> the Intel HDA platforms.
> >>
> >> this change was just to mirror the behavior between start/stop, I
> >> thought there was a patch where we moved to TRIGGER_POST by default?
> >>
> >> What I am trying to figure out if whether using TRIGGER_PRE is ok or not
> >> for the SOF firmware.
> >>
> >
> > Ahh yes, it was part of the same series as this one. fd274c2b7267b  "ASoC:
> > SOF: topology: set trigger order for FE DAI link"
> >
> > TRIGGER_PRE won't really work in the case of SOF. We need the BE DAI to be
> > triggered before the FE DAI during start to prevent the xruns during
> > pause/release.
> 
> Thanks Ranjani. That information closes the door on the idea of playing
> with the trigger order suggested earlier in the thread, so my guess is
> that we really need to expose the MCLK/BCLK with the clk API and turn
> them on/off from the machine driver as needed. I hope is that we don't
> need the FSYNC as well, that would be rather painful to implement.

Am not going to make myself popular here. It's MCLK and FSYNC (or WCLK as it's
termed for our device) that is required for SRM to lock in the PLL.

So far I've not found a way in the codec driver to be able to get around this.
I spent a very long time with Sathya in the early days (Apollo Lake) looking at
options but nothing would fit which is why I have the solution that's in place
right now. We could probably reduce the number of rechecks before timeout in the
driver but that's really just papering over the crack and there's still the
possibility of noise later when SRM finally does lock.
Mark Brown Feb. 12, 2020, 11:59 a.m. UTC | #16
On Wed, Feb 12, 2020 at 10:16:54AM +0000, Adam Thomson wrote:

> So far I've not found a way in the codec driver to be able to get around this.
> I spent a very long time with Sathya in the early days (Apollo Lake) looking at
> options but nothing would fit which is why I have the solution that's in place
> right now. We could probably reduce the number of rechecks before timeout in the
> driver but that's really just papering over the crack and there's still the
> possibility of noise later when SRM finally does lock.

This really needs the componentisation refactoring I think, that way we
can annotate individual devices and links with what they need rather
than essentially guessing about what works most of the time which is
more or less what we do at the minute.  Like you say as things are at
the minute there's a lot of crack papering going on.
Pierre-Louis Bossart Feb. 12, 2020, 3:48 p.m. UTC | #17
>> Thanks Ranjani. That information closes the door on the idea of playing
>> with the trigger order suggested earlier in the thread, so my guess is
>> that we really need to expose the MCLK/BCLK with the clk API and turn
>> them on/off from the machine driver as needed. I hope is that we don't
>> need the FSYNC as well, that would be rather painful to implement.
> 
> Am not going to make myself popular here. It's MCLK and FSYNC (or WCLK as it's
> termed for our device) that is required for SRM to lock in the PLL.
> 
> So far I've not found a way in the codec driver to be able to get around this.
> I spent a very long time with Sathya in the early days (Apollo Lake) looking at
> options but nothing would fit which is why I have the solution that's in place
> right now. We could probably reduce the number of rechecks before timeout in the
> driver but that's really just papering over the crack and there's still the
> possibility of noise later when SRM finally does lock.

Sorry, you lost me at "the solution that's in place right now". There is 
nothing in the bxt_da7219_max98357a.c code that deals with clocks or 
defines a trigger order?
Adam Thomson Feb. 12, 2020, 5:01 p.m. UTC | #18
On 12 February 2020 15:48, Pierre-Louis Bossart wrote:

> >> Thanks Ranjani. That information closes the door on the idea of playing
> >> with the trigger order suggested earlier in the thread, so my guess is
> >> that we really need to expose the MCLK/BCLK with the clk API and turn
> >> them on/off from the machine driver as needed. I hope is that we don't
> >> need the FSYNC as well, that would be rather painful to implement.
> >
> > Am not going to make myself popular here. It's MCLK and FSYNC (or WCLK as
> it's
> > termed for our device) that is required for SRM to lock in the PLL.
> >
> > So far I've not found a way in the codec driver to be able to get around this.
> > I spent a very long time with Sathya in the early days (Apollo Lake) looking at
> > options but nothing would fit which is why I have the solution that's in place
> > right now. We could probably reduce the number of rechecks before timeout in
> the
> > driver but that's really just papering over the crack and there's still the
> > possibility of noise later when SRM finally does lock.
> 
> Sorry, you lost me at "the solution that's in place right now". There is
> nothing in the bxt_da7219_max98357a.c code that deals with clocks or
> defines a trigger order?

I meant solution in the context of the codec driver. The approach or
expectation (maybe more suitable wording) for the driver is that the required
clocking can be enabled prior to the DAI widget for the codec being powered via
DAPM as part of an audio path. This approach has been there since the beginning,
for want of a better option, and I've always highlighted this need when
platforms are using our device with SRM.

You're right though that this isn't taken care of in existing mainline Linux
machine files that use this device with SRM.
Lu, Brent Feb. 19, 2020, 5:57 a.m. UTC | #19
> 
> Am not going to make myself popular here. It's MCLK and FSYNC (or WCLK as
> it's termed for our device) that is required for SRM to lock in the PLL.
> 
> So far I've not found a way in the codec driver to be able to get around this.
> I spent a very long time with Sathya in the early days (Apollo Lake) looking at
> options but nothing would fit which is why I have the solution that's in place
> right now. We could probably reduce the number of rechecks before
> timeout in the driver but that's really just papering over the crack and there's
> still the possibility of noise later when SRM finally does lock.

Hi Adam,

For Google CTS requirement (200ms cold output latency), we plan to upload a
patch which reduces the recheck number to 4 and interval to 20ms so the total
delay here would be 80ms for our platform. We think the time is still sufficient
for other platforms to generate a stable WCLK and for the codec SRM to lock but
still needs your confirmation. How do you think?


Regards,
Brent
Adam Thomson Feb. 19, 2020, 10:05 a.m. UTC | #20
On 19 February 2020 05:57, Lu, Brent wrote:

> > Am not going to make myself popular here. It's MCLK and FSYNC (or WCLK as
> > it's termed for our device) that is required for SRM to lock in the PLL.
> >
> > So far I've not found a way in the codec driver to be able to get around this.
> > I spent a very long time with Sathya in the early days (Apollo Lake) looking at
> > options but nothing would fit which is why I have the solution that's in place
> > right now. We could probably reduce the number of rechecks before
> > timeout in the driver but that's really just papering over the crack and there's
> > still the possibility of noise later when SRM finally does lock.
> 
> Hi Adam,
> 
> For Google CTS requirement (200ms cold output latency), we plan to upload a
> patch which reduces the recheck number to 4 and interval to 20ms so the total
> delay here would be 80ms for our platform. We think the time is still sufficient
> for other platforms to generate a stable WCLK and for the codec SRM to lock but
> still needs your confirmation. How do you think?

Hi Brent,

I'm concerned that just setting a timeout to suit the Google CTS requirement
isn't necessarily suitable for all targets, and this doesn't actually fix the
real problem here.

How long do you determine platforms will take to generate a stable WCLK? Do we
have an idea of how long that might be in a worst case scenario? If so then we
can look at adjusting this down, but I'd like to be clear.

> 
> 
> Regards,
> Brent

Patch
diff mbox series

diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c
index f83a6ea..0fb5ea5 100644
--- a/sound/soc/codecs/da7219.c
+++ b/sound/soc/codecs/da7219.c
@@ -794,9 +794,7 @@  static int da7219_dai_event(struct snd_soc_dapm_widget *w,
 	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
 	struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
 	struct clk *bclk = da7219->dai_clks[DA7219_DAI_BCLK_IDX];
-	u8 pll_ctrl, pll_status;
-	int i = 0, ret;
-	bool srm_lock = false;
+	int ret;
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
@@ -820,26 +818,6 @@  static int da7219_dai_event(struct snd_soc_dapm_widget *w,
 		/* PC synchronised to DAI */
 		snd_soc_component_update_bits(component, DA7219_PC_COUNT,
 				    DA7219_PC_FREERUN_MASK, 0);
-
-		/* Slave mode, if SRM not enabled no need for status checks */
-		pll_ctrl = snd_soc_component_read32(component, DA7219_PLL_CTRL);
-		if ((pll_ctrl & DA7219_PLL_MODE_MASK) != DA7219_PLL_MODE_SRM)
-			return 0;
-
-		/* Check SRM has locked */
-		do {
-			pll_status = snd_soc_component_read32(component, DA7219_PLL_SRM_STS);
-			if (pll_status & DA7219_PLL_SRM_STS_SRM_LOCK) {
-				srm_lock = true;
-			} else {
-				++i;
-				msleep(50);
-			}
-		} while ((i < DA7219_SRM_CHECK_RETRIES) && (!srm_lock));
-
-		if (!srm_lock)
-			dev_warn(component->dev, "SRM failed to lock\n");
-
 		return 0;
 	case SND_SOC_DAPM_POST_PMD:
 		/* PC free-running */
@@ -1658,12 +1636,56 @@  static int da7219_hw_params(struct snd_pcm_substream *substream,
 	return 0;
 }
 
+static int da7219_set_dai_trigger(struct snd_pcm_substream *substream, int cmd,
+				  struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	u8 pll_ctrl, pll_status;
+	int i = 0;
+	bool srm_lock = false;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+		/* Slave mode, if SRM not enabled no need for status checks */
+		pll_ctrl = snd_soc_component_read32(component, DA7219_PLL_CTRL);
+		if ((pll_ctrl & DA7219_PLL_MODE_MASK) != DA7219_PLL_MODE_SRM)
+			return 0;
+
+		/* Check SRM has locked */
+		do {
+			pll_status = snd_soc_component_read32(component,
+							DA7219_PLL_SRM_STS);
+			if (pll_status & DA7219_PLL_SRM_STS_SRM_LOCK) {
+				srm_lock = true;
+			} else {
+				++i;
+				msleep(50);
+			}
+		} while ((i < DA7219_SRM_CHECK_RETRIES) && (!srm_lock));
+
+		if (!srm_lock)
+			dev_warn(component->dev, "SRM failed to lock\n");
+
+		break;
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+	default:
+		break;
+	}
+
+	return 0;
+}
+
 static const struct snd_soc_dai_ops da7219_dai_ops = {
 	.hw_params	= da7219_hw_params,
 	.set_sysclk	= da7219_set_dai_sysclk,
 	.set_pll	= da7219_set_dai_pll,
 	.set_fmt	= da7219_set_dai_fmt,
 	.set_tdm_slot	= da7219_set_dai_tdm_slot,
+	.trigger	= da7219_set_dai_trigger,
 };
 
 #define DA7219_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\