OSDN Git Service

soundwire: intel/cadence: update hardware reset sequence
authorPierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Thu, 18 May 2023 02:41:18 +0000 (10:41 +0800)
committerVinod Koul <vkoul@kernel.org>
Mon, 29 May 2023 05:19:47 +0000 (10:49 +0530)
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>
drivers/soundwire/cadence_master.c
drivers/soundwire/cadence_master.h
drivers/soundwire/intel_bus_common.c

index 39502bc..58686ae 100644 (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);
 
index 86a450b..bc84435 100644 (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 */
index 1e47f44..e5ac3cc 100644 (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");