Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Pierre-Louis Bossart and committed by
Vinod Koul
ffc363d9 46b56a5c

+53 -17
+24 -7
drivers/soundwire/cadence_master.c
··· 283 283 return ret; 284 284 } 285 285 286 + /** 287 + * sdw_cdns_config_update() - Update configurations 288 + * @cdns: Cadence instance 289 + */ 290 + void sdw_cdns_config_update(struct sdw_cdns *cdns) 291 + { 292 + /* commit changes */ 293 + cdns_writel(cdns, CDNS_MCP_CONFIG_UPDATE, CDNS_MCP_CONFIG_UPDATE_BIT); 294 + } 295 + EXPORT_SYMBOL(sdw_cdns_config_update); 296 + 297 + /** 298 + * sdw_cdns_config_update_set_wait() - wait until configuration update bit is self-cleared 299 + * @cdns: Cadence instance 300 + */ 301 + int sdw_cdns_config_update_set_wait(struct sdw_cdns *cdns) 302 + { 303 + /* the hardware recommendation is to wait at least 300us */ 304 + return cdns_set_wait(cdns, CDNS_MCP_CONFIG_UPDATE, 305 + CDNS_MCP_CONFIG_UPDATE_BIT, 0); 306 + } 307 + EXPORT_SYMBOL(sdw_cdns_config_update_set_wait); 308 + 286 309 /* 287 310 * debugfs 288 311 */ ··· 1139 1116 CDNS_MCP_CONTROL_HW_RST); 1140 1117 1141 1118 /* commit changes */ 1142 - cdns_updatel(cdns, CDNS_MCP_CONFIG_UPDATE, 1143 - CDNS_MCP_CONFIG_UPDATE_BIT, 1144 - CDNS_MCP_CONFIG_UPDATE_BIT); 1145 - 1146 - /* don't wait here */ 1147 - return 0; 1148 - 1119 + return cdns_config_update(cdns); 1149 1120 } 1150 1121 EXPORT_SYMBOL(sdw_cdns_exit_reset); 1151 1122
+3
drivers/soundwire/cadence_master.h
··· 199 199 void sdw_cdns_check_self_clearing_bits(struct sdw_cdns *cdns, const char *string, 200 200 bool initial_delay, int reset_iterations); 201 201 202 + void sdw_cdns_config_update(struct sdw_cdns *cdns); 203 + int sdw_cdns_config_update_set_wait(struct sdw_cdns *cdns); 204 + 202 205 #endif /* __SDW_CADENCE_H */
+26 -10
drivers/soundwire/intel_bus_common.c
··· 29 29 return ret; 30 30 } 31 31 32 - ret = sdw_cdns_exit_reset(cdns); 33 - if (ret < 0) { 34 - dev_err(dev, "%s: unable to exit bus reset sequence: %d\n", __func__, ret); 35 - return ret; 36 - } 32 + sdw_cdns_config_update(cdns); 37 33 38 34 if (bus->multi_link) { 39 35 ret = sdw_intel_sync_go(sdw); ··· 37 41 dev_err(dev, "%s: sync go failed: %d\n", __func__, ret); 38 42 return ret; 39 43 } 44 + } 45 + 46 + ret = sdw_cdns_config_update_set_wait(cdns); 47 + if (ret < 0) { 48 + dev_err(dev, "%s: CONFIG_UPDATE BIT still set\n", __func__); 49 + return ret; 50 + } 51 + 52 + ret = sdw_cdns_exit_reset(cdns); 53 + if (ret < 0) { 54 + dev_err(dev, "%s: unable to exit bus reset sequence: %d\n", __func__, ret); 55 + return ret; 40 56 } 41 57 42 58 ret = sdw_cdns_enable_interrupt(cdns, true); ··· 120 112 } 121 113 122 114 if (!clock_stop0) { 123 - ret = sdw_cdns_exit_reset(cdns); 124 - if (ret < 0) { 125 - dev_err(dev, "unable to exit bus reset sequence during resume\n"); 126 - return ret; 127 - } 115 + sdw_cdns_config_update(cdns); 128 116 129 117 if (bus->multi_link) { 130 118 ret = sdw_intel_sync_go(sdw); ··· 128 124 dev_err(sdw->cdns.dev, "sync go failed during resume\n"); 129 125 return ret; 130 126 } 127 + } 128 + 129 + ret = sdw_cdns_config_update_set_wait(cdns); 130 + if (ret < 0) { 131 + dev_err(dev, "%s: CONFIG_UPDATE BIT still set\n", __func__); 132 + return ret; 133 + } 134 + 135 + ret = sdw_cdns_exit_reset(cdns); 136 + if (ret < 0) { 137 + dev_err(dev, "unable to exit bus reset sequence during resume\n"); 138 + return ret; 131 139 } 132 140 133 141 ret = sdw_cdns_enable_interrupt(cdns, true);