diff mbox series

[09/13] soundwire: intel: add CLK_STOP_BUS_RESET support

Message ID 20200721203723.18305-10-yung-chuan.liao@linux.intel.com (mailing list archive)
State New, archived
Headers show
Series soundwire: intel: add power management support | expand

Commit Message

Bard Liao July 21, 2020, 8:37 p.m. UTC
From: Rander Wang <rander.wang@intel.com>

Move existing pm_runtime suspend under the CLK_STOP_TEARDOWN case.

In this mode the Master IP will lose all context but in-band wakes are
supported.

On pm_runtime resume a complete re-enumeration will be performed after
a bus reset.

Signed-off-by: Rander Wang <rander.wang@intel.com>
Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Signed-off-by: Bard Liao <yung-chuan.liao@linux.intel.com>
---
 drivers/soundwire/intel.c | 44 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 44 insertions(+)

Comments

Vinod Koul Aug. 17, 2020, 11:47 a.m. UTC | #1
On 22-07-20, 04:37, Bard Liao wrote:
> From: Rander Wang <rander.wang@intel.com>
> 
> Move existing pm_runtime suspend under the CLK_STOP_TEARDOWN case.
> 
> In this mode the Master IP will lose all context but in-band wakes are
> supported.
> 
> On pm_runtime resume a complete re-enumeration will be performed after
> a bus reset.
> 
> Signed-off-by: Rander Wang <rander.wang@intel.com>
> Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
> Signed-off-by: Bard Liao <yung-chuan.liao@linux.intel.com>
> ---
>  drivers/soundwire/intel.c | 44 +++++++++++++++++++++++++++++++++++++++
>  1 file changed, 44 insertions(+)
> 
> diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c
> index 1954eb48b86c..744fc0a4816a 100644
> --- a/drivers/soundwire/intel.c
> +++ b/drivers/soundwire/intel.c
> @@ -1576,6 +1576,26 @@ static int intel_suspend_runtime(struct device *dev)
>  
>  		intel_shim_wake(sdw, false);
>  
> +	} else if (clock_stop_quirks & SDW_INTEL_CLK_STOP_BUS_RESET) {
> +		ret = sdw_cdns_clock_stop(cdns, true);
> +		if (ret < 0) {
> +			dev_err(dev, "cannot enable clock stop on suspend\n");
> +			return ret;
> +		}
> +
> +		ret = sdw_cdns_enable_interrupt(cdns, false);
> +		if (ret < 0) {
> +			dev_err(dev, "cannot disable interrupts on suspend\n");
> +			return ret;
> +		}
> +
> +		ret = intel_link_power_down(sdw);
> +		if (ret) {
> +			dev_err(dev, "Link power down failed: %d", ret);
> +			return ret;
> +		}

no cleanup on all the error cases here?

> +
> +		intel_shim_wake(sdw, true);
>  	} else {
>  		dev_err(dev, "%s clock_stop_quirks %x unsupported\n",
>  			__func__, clock_stop_quirks);
> @@ -1694,6 +1714,30 @@ static int intel_resume_runtime(struct device *dev)
>  			dev_err(dev, "unable to exit bus reset sequence during resume\n");
>  			return ret;
>  		}
> +	} else if (clock_stop_quirks & SDW_INTEL_CLK_STOP_BUS_RESET) {
> +		ret = intel_init(sdw);
> +		if (ret) {
> +			dev_err(dev, "%s failed: %d", __func__, ret);
> +			return ret;
> +		}
> +
> +		/*
> +		 * make sure all Slaves are tagged as UNATTACHED and
> +		 * provide reason for reinitialization
> +		 */
> +		sdw_clear_slave_status(bus, SDW_UNATTACH_REQUEST_MASTER_RESET);
> +
> +		ret = sdw_cdns_enable_interrupt(cdns, true);
> +		if (ret < 0) {
> +			dev_err(dev, "cannot enable interrupts during resume\n");
> +			return ret;
> +		}
> +
> +		ret = sdw_cdns_clock_restart(cdns, true);
> +		if (ret < 0) {
> +			dev_err(dev, "unable to restart clock during resume\n");
> +			return ret;
> +		}
>  	} else {
>  		dev_err(dev, "%s clock_stop_quirks %x unsupported\n",
>  			__func__, clock_stop_quirks);
> -- 
> 2.17.1
Pierre-Louis Bossart Aug. 17, 2020, 2:30 p.m. UTC | #2
>> +	} else if (clock_stop_quirks & SDW_INTEL_CLK_STOP_BUS_RESET) {
>> +		ret = sdw_cdns_clock_stop(cdns, true);
>> +		if (ret < 0) {
>> +			dev_err(dev, "cannot enable clock stop on suspend\n");
>> +			return ret;
>> +		}
>> +
>> +		ret = sdw_cdns_enable_interrupt(cdns, false);
>> +		if (ret < 0) {
>> +			dev_err(dev, "cannot disable interrupts on suspend\n");
>> +			return ret;
>> +		}
>> +
>> +		ret = intel_link_power_down(sdw);
>> +		if (ret) {
>> +			dev_err(dev, "Link power down failed: %d", ret);
>> +			return ret;
>> +		}
> 
> no cleanup on all the error cases here?

See above the 'else if' test, the clock stop on suspend will be followed 
by a bus reset on resume. this is essentially a complete bus restart.

The only open here is whether we should actually return an error while 
suspending, or just log the error and squelch it. We decided to return 
the status so that the pm_runtime suspend does not proceed: the state 
remains active which is easier to detect than a single line in a dmesg log.
Vinod Koul Aug. 18, 2020, 6:27 a.m. UTC | #3
On 17-08-20, 09:30, Pierre-Louis Bossart wrote:
> 
> 
> 
> > > +	} else if (clock_stop_quirks & SDW_INTEL_CLK_STOP_BUS_RESET) {
> > > +		ret = sdw_cdns_clock_stop(cdns, true);
> > > +		if (ret < 0) {
> > > +			dev_err(dev, "cannot enable clock stop on suspend\n");
> > > +			return ret;
> > > +		}
> > > +
> > > +		ret = sdw_cdns_enable_interrupt(cdns, false);
> > > +		if (ret < 0) {
> > > +			dev_err(dev, "cannot disable interrupts on suspend\n");
> > > +			return ret;
> > > +		}
> > > +
> > > +		ret = intel_link_power_down(sdw);
> > > +		if (ret) {
> > > +			dev_err(dev, "Link power down failed: %d", ret);
> > > +			return ret;
> > > +		}
> > 
> > no cleanup on all the error cases here?
> 
> See above the 'else if' test, the clock stop on suspend will be followed by
> a bus reset on resume. this is essentially a complete bus restart.

ok

> The only open here is whether we should actually return an error while
> suspending, or just log the error and squelch it. We decided to return the
> status so that the pm_runtime suspend does not proceed: the state remains
> active which is easier to detect than a single line in a dmesg log.

right, returning makes sense and is done correctly above
diff mbox series

Patch

diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c
index 1954eb48b86c..744fc0a4816a 100644
--- a/drivers/soundwire/intel.c
+++ b/drivers/soundwire/intel.c
@@ -1576,6 +1576,26 @@  static int intel_suspend_runtime(struct device *dev)
 
 		intel_shim_wake(sdw, false);
 
+	} else if (clock_stop_quirks & SDW_INTEL_CLK_STOP_BUS_RESET) {
+		ret = sdw_cdns_clock_stop(cdns, true);
+		if (ret < 0) {
+			dev_err(dev, "cannot enable clock stop on suspend\n");
+			return ret;
+		}
+
+		ret = sdw_cdns_enable_interrupt(cdns, false);
+		if (ret < 0) {
+			dev_err(dev, "cannot disable interrupts on suspend\n");
+			return ret;
+		}
+
+		ret = intel_link_power_down(sdw);
+		if (ret) {
+			dev_err(dev, "Link power down failed: %d", ret);
+			return ret;
+		}
+
+		intel_shim_wake(sdw, true);
 	} else {
 		dev_err(dev, "%s clock_stop_quirks %x unsupported\n",
 			__func__, clock_stop_quirks);
@@ -1694,6 +1714,30 @@  static int intel_resume_runtime(struct device *dev)
 			dev_err(dev, "unable to exit bus reset sequence during resume\n");
 			return ret;
 		}
+	} else if (clock_stop_quirks & SDW_INTEL_CLK_STOP_BUS_RESET) {
+		ret = intel_init(sdw);
+		if (ret) {
+			dev_err(dev, "%s failed: %d", __func__, ret);
+			return ret;
+		}
+
+		/*
+		 * make sure all Slaves are tagged as UNATTACHED and
+		 * provide reason for reinitialization
+		 */
+		sdw_clear_slave_status(bus, SDW_UNATTACH_REQUEST_MASTER_RESET);
+
+		ret = sdw_cdns_enable_interrupt(cdns, true);
+		if (ret < 0) {
+			dev_err(dev, "cannot enable interrupts during resume\n");
+			return ret;
+		}
+
+		ret = sdw_cdns_clock_restart(cdns, true);
+		if (ret < 0) {
+			dev_err(dev, "unable to restart clock during resume\n");
+			return ret;
+		}
 	} else {
 		dev_err(dev, "%s clock_stop_quirks %x unsupported\n",
 			__func__, clock_stop_quirks);