soundwire: bus: add CLOCK_STOP_MODE1 support back#5624
soundwire: bus: add CLOCK_STOP_MODE1 support back#5624bardliao wants to merge 2 commits intothesofproject:topic/sof-devfrom
Conversation
|
@bardliao how would you test this? In practice the intel host does a bus reset after restarting the clock which forces the device to lose context anyways. |
|
@plbossart Indeed, we will do bus reset after restarting the clock. Using mode 1 is just for power consumption during clock stop. On the other hands, the peripheral will need to restore the context anyway, why don't we use mode 1 If the peripheral supports it? |
|
I don't disagree @bardliao, if the host does a bus reset we would benefit from the MODE1 on the device side. |
The existing code is using MODE0. I would expect that the behavior will not change on MODE0.
No, the codec driver can implement the get_clk_stop_mode ops to set the condition of using MODE1
sdw_get_clk_stop_mode() will set the clock mode before clock stops. I guess it should be enough? |
|
@vijendarmukunda Do you mind testing this PR on AMD platforms? |
@bardliao : Most of my team members are OOO. Is it okay if we can update the valiadation results some time early next week? |
Yeah, same as us. It is totally fine to get the test result next week. |
|
@bardliao : Validated ClockStop Mode1 on AMD platform using RTK codec. It's working fine. |
|
Problem with this is that it only issues clock-stop in runtime_suspend. |
|
In intel_suspend() maybe change it like this: |
6de6e7b to
5789c69
Compare
Yes, you are right. @rfvirgil We didn't stop SDW clock in system suspend. I wonder if it is Intentional or not? @plbossart any idea? |
|
Tested with MTL and PTL |
drivers/soundwire/bus.c
Outdated
| mode = SDW_CLK_STOP_MODE0; | ||
| } | ||
|
|
||
| return mode; |
There was a problem hiding this comment.
Could be as simple as:
if (drv->ops && drv->ops->get_clk_stop_mode)
return drv->ops->get_clk_stop_mode(slave);
return slave->prop.clk_stop_mode1 ? SDW_CLK_STOP_MODE1 : SDW_CLK_STOP_MODE0;
drivers/soundwire/bus.c
Outdated
| ret = sdw_slave_clk_stop_callback(slave, | ||
| SDW_CLK_STOP_MODE0, | ||
| ret = sdw_slave_clk_stop_callback(slave, mode, | ||
| SDW_CLK_POST_PREPARE); |
There was a problem hiding this comment.
Since you have introduced a member to store the mode slave->curr_clk_stop_mode, why not modify the sdw_slave_clk_stop_callback() and sdw_slave_clk_stop_prepare() to use this new member and drop the mode parameter?
include/linux/soundwire/sdw.h
Outdated
| struct list_head node; | ||
| struct completion port_ready[SDW_MAX_PORTS]; | ||
| unsigned int m_port_map[SDW_MAX_PORTS]; | ||
| enum sdw_clk_stop_mode curr_clk_stop_mode; |
There was a problem hiding this comment.
Update the struct doc as well.
But, is there a prev_clk_stop_mode or next_clk_stop_mode? Should this be just a simple clk_stop_mode ?
CLOCK_STOP_MODE1 is used when the Peripheral might have entered a deeper power-saving mode that does not retain state while the Clock is stopped. It is useful when the device is more power consumption sensitive. Add it back to allow the Peripheral use CLOCK_STOP_MODE1. Signed-off-by: Bard Liao <yung-chuan.liao@linux.intel.com>
There is no need to keep the SoundWire clock active in system suspend. Signed-off-by: Bard Liao <yung-chuan.liao@linux.intel.com>
5789c69 to
3f923b6
Compare
There was a problem hiding this comment.
Pull request overview
This PR reintroduces support for SoundWire CLOCK_STOP_MODE1, enabling peripherals to request a deeper clock-stop mode (useful when device state is not retained during clock stop and power consumption sensitivity is higher).
Changes:
- Adds a Slave driver hook to query the desired clock-stop mode and stores the mode in the
sdw_slavestructure. - Updates clock-stop prepare/callback flows to use the stored per-Slave clock-stop mode.
- Switches Intel SoundWire system suspend to stop the bus using the clock-stop flow.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| include/linux/soundwire/sdw.h | Extends sdw_slave_ops and sdw_slave to support querying/storing clock-stop mode. |
| drivers/soundwire/intel_auxdevice.c | Changes system suspend behavior to stop the bus with clock stop enabled. |
| drivers/soundwire/bus.c | Introduces mode query helper and propagates per-Slave clock-stop mode through prepare/callback logic. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| struct sdw_driver *drv = drv_to_sdw_driver(dev->driver); | ||
|
|
||
| /* | ||
| * Query for clock stop mode if Slave implements | ||
| * ops->get_clk_stop_mode, else read from property. | ||
| */ | ||
| if (drv->ops && drv->ops->get_clk_stop_mode) | ||
| return drv->ops->get_clk_stop_mode(slave); | ||
| else | ||
| return slave->prop.clk_stop_mode1 ? SDW_CLK_STOP_MODE1 : SDW_CLK_STOP_MODE0; |
There was a problem hiding this comment.
sdw_get_clk_stop_mode() unconditionally calls drv_to_sdw_driver(dev->driver). If the Slave is enumerated but has no bound driver (dev->driver == NULL / slave->probed == false), this will dereference a NULL pointer via container_of and crash. Consider first checking slave->probed (and/or dev->driver) before accessing drv->ops, and falling back to the property-based default when no driver is bound. Also consider validating the returned value to ensure it is a supported sdw_clk_stop_mode (e.g., MODE0/MODE1) and falling back safely on unexpected/negative values.
| struct sdw_driver *drv = drv_to_sdw_driver(dev->driver); | |
| /* | |
| * Query for clock stop mode if Slave implements | |
| * ops->get_clk_stop_mode, else read from property. | |
| */ | |
| if (drv->ops && drv->ops->get_clk_stop_mode) | |
| return drv->ops->get_clk_stop_mode(slave); | |
| else | |
| return slave->prop.clk_stop_mode1 ? SDW_CLK_STOP_MODE1 : SDW_CLK_STOP_MODE0; | |
| struct sdw_driver *drv; | |
| enum sdw_clk_stop_mode mode; | |
| /* | |
| * Default to the property-based value. This is used when no | |
| * driver is bound or when the driver returns an unsupported | |
| * clock stop mode. | |
| */ | |
| mode = slave->prop.clk_stop_mode1 ? SDW_CLK_STOP_MODE1 : SDW_CLK_STOP_MODE0; | |
| /* | |
| * If the Slave is not yet probed or has no bound driver, fall back | |
| * to the property-based default without dereferencing dev->driver. | |
| */ | |
| if (!slave->probed || !dev->driver) | |
| return mode; | |
| drv = drv_to_sdw_driver(dev->driver); | |
| /* | |
| * Query for clock stop mode if the Slave driver implements | |
| * ops->get_clk_stop_mode. Validate the returned value and | |
| * fall back to the property-based default on unexpected values. | |
| */ | |
| if (drv->ops && drv->ops->get_clk_stop_mode) { | |
| enum sdw_clk_stop_mode drv_mode; | |
| drv_mode = drv->ops->get_clk_stop_mode(slave); | |
| if (drv_mode == SDW_CLK_STOP_MODE0 || | |
| drv_mode == SDW_CLK_STOP_MODE1) | |
| return drv_mode; | |
| } | |
| return mode; |
| int (*port_prep)(struct sdw_slave *slave, | ||
| struct sdw_prepare_ch *prepare_ch, | ||
| enum sdw_port_prep_ops pre_ops); | ||
| int (*get_clk_stop_mode)(struct sdw_slave *slave); |
There was a problem hiding this comment.
The new get_clk_stop_mode callback is declared as returning int, but the core treats it as an sdw_clk_stop_mode and uses the returned value to program hardware state. Using int makes it ambiguous whether negative error codes are allowed; if a driver returns -errno it could be propagated into mode handling unexpectedly. Consider changing the callback return type to enum sdw_clk_stop_mode (or documenting/handling errors explicitly in the core, e.g., treat negative as fallback to properties/default).
| int (*get_clk_stop_mode)(struct sdw_slave *slave); | |
| enum sdw_clk_stop_mode (*get_clk_stop_mode)(struct sdw_slave *slave); |
| return 0; | ||
| } | ||
|
|
||
| ret = sdw_intel_stop_bus(sdw, false); | ||
| ret = sdw_intel_stop_bus(sdw, true); | ||
| if (ret < 0) { | ||
| dev_err(dev, "%s: cannot stop bus: %d\n", __func__, ret); | ||
| return ret; |
There was a problem hiding this comment.
intel_suspend() now always calls sdw_intel_stop_bus(sdw, true) when the device is runtime-active. This bypasses the clock_stop_quirks handling used in intel_suspend_runtime() (e.g., SDW_INTEL_CLK_STOP_TEARDOWN), and may attempt a clock-stop flow on platforms that explicitly require teardown/no clock-stop. Consider selecting the stop mode based on clock_stop_quirks here as well (matching the runtime suspend logic), or clearly justifying why system suspend must always use clock_stop=true.
| */ | ||
| if (drv->ops && drv->ops->get_clk_stop_mode) | ||
| return drv->ops->get_clk_stop_mode(slave); | ||
| else |
CLOCK_STOP_MODE1 is used when the Peripheral might have entered a deeper power-saving mode that does not retain state while the Clock is stopped. It is useful when the device is more power consumption sensitive. Add it back to allow the Peripheral use CLOCK_STOP_MODE1.