soundwire: intel/cadence: update hardware reset sequence

Combining hardware reset with the multi-link mode leads to a shortened
hardware reset pattern observed on the bus.

The updated hardware programming sequence is to first enable the clock
with the sync_arm/sync_go pattern, and only in a second step to issue
the hardware reset sequence. Since there is no longer a dependency
between sync_arm/sync_go and hw_reset, the behavior of
sdw_cdns_exit_reset() is changed to wait for the self-clearing
CONFIG_UPDATE to go back to zero,

Link: https://github.com/thesofproject/linux/issues/4170
Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Reviewed-by: Rander Wang <rander.wang@intel.com>
Signed-off-by: Bard Liao <yung-chuan.liao@linux.intel.com>
Link: https://lore.kernel.org/r/20230518024119.164160-3-yung-chuan.liao@linux.intel.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>
This commit is contained in:
Pierre-Louis Bossart 2023-05-18 10:41:18 +08:00 committed by Vinod Koul
parent 46b56a5cd2
commit ffc363d970
3 changed files with 53 additions and 17 deletions

View File

@ -283,6 +283,29 @@ static int cdns_config_update(struct sdw_cdns *cdns)
return ret;
}
/**
* sdw_cdns_config_update() - Update configurations
* @cdns: Cadence instance
*/
void sdw_cdns_config_update(struct sdw_cdns *cdns)
{
/* commit changes */
cdns_writel(cdns, CDNS_MCP_CONFIG_UPDATE, CDNS_MCP_CONFIG_UPDATE_BIT);
}
EXPORT_SYMBOL(sdw_cdns_config_update);
/**
* sdw_cdns_config_update_set_wait() - wait until configuration update bit is self-cleared
* @cdns: Cadence instance
*/
int sdw_cdns_config_update_set_wait(struct sdw_cdns *cdns)
{
/* the hardware recommendation is to wait at least 300us */
return cdns_set_wait(cdns, CDNS_MCP_CONFIG_UPDATE,
CDNS_MCP_CONFIG_UPDATE_BIT, 0);
}
EXPORT_SYMBOL(sdw_cdns_config_update_set_wait);
/*
* debugfs
*/
@ -1116,13 +1139,7 @@ int sdw_cdns_exit_reset(struct sdw_cdns *cdns)
CDNS_MCP_CONTROL_HW_RST);
/* commit changes */
cdns_updatel(cdns, CDNS_MCP_CONFIG_UPDATE,
CDNS_MCP_CONFIG_UPDATE_BIT,
CDNS_MCP_CONFIG_UPDATE_BIT);
/* don't wait here */
return 0;
return cdns_config_update(cdns);
}
EXPORT_SYMBOL(sdw_cdns_exit_reset);

View File

@ -199,4 +199,7 @@ int cdns_set_sdw_stream(struct snd_soc_dai *dai,
void sdw_cdns_check_self_clearing_bits(struct sdw_cdns *cdns, const char *string,
bool initial_delay, int reset_iterations);
void sdw_cdns_config_update(struct sdw_cdns *cdns);
int sdw_cdns_config_update_set_wait(struct sdw_cdns *cdns);
#endif /* __SDW_CADENCE_H */

View File

@ -29,11 +29,7 @@ int intel_start_bus(struct sdw_intel *sdw)
return ret;
}
ret = sdw_cdns_exit_reset(cdns);
if (ret < 0) {
dev_err(dev, "%s: unable to exit bus reset sequence: %d\n", __func__, ret);
return ret;
}
sdw_cdns_config_update(cdns);
if (bus->multi_link) {
ret = sdw_intel_sync_go(sdw);
@ -43,6 +39,18 @@ int intel_start_bus(struct sdw_intel *sdw)
}
}
ret = sdw_cdns_config_update_set_wait(cdns);
if (ret < 0) {
dev_err(dev, "%s: CONFIG_UPDATE BIT still set\n", __func__);
return ret;
}
ret = sdw_cdns_exit_reset(cdns);
if (ret < 0) {
dev_err(dev, "%s: unable to exit bus reset sequence: %d\n", __func__, ret);
return ret;
}
ret = sdw_cdns_enable_interrupt(cdns, true);
if (ret < 0) {
dev_err(dev, "%s: cannot enable interrupts: %d\n", __func__, ret);
@ -112,11 +120,7 @@ int intel_start_bus_after_reset(struct sdw_intel *sdw)
}
if (!clock_stop0) {
ret = sdw_cdns_exit_reset(cdns);
if (ret < 0) {
dev_err(dev, "unable to exit bus reset sequence during resume\n");
return ret;
}
sdw_cdns_config_update(cdns);
if (bus->multi_link) {
ret = sdw_intel_sync_go(sdw);
@ -126,6 +130,18 @@ int intel_start_bus_after_reset(struct sdw_intel *sdw)
}
}
ret = sdw_cdns_config_update_set_wait(cdns);
if (ret < 0) {
dev_err(dev, "%s: CONFIG_UPDATE BIT still set\n", __func__);
return ret;
}
ret = sdw_cdns_exit_reset(cdns);
if (ret < 0) {
dev_err(dev, "unable to exit bus reset sequence during resume\n");
return ret;
}
ret = sdw_cdns_enable_interrupt(cdns, true);
if (ret < 0) {
dev_err(dev, "cannot enable interrupts during resume\n");