CHROMIUM: ASoC: SOF: harden the FW boot sequence for SKL+

It is recommended to attempt FW boot more than once to
harden the FW boot sequence for SKL+ platforms.

TEST=run suspend_stress_test on bobba for 2500 iterations
BUG=b:117130615

Change-Id: I63d1c2bf4191b3dd88ad59f039260a9be36a2710
Signed-off-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
Reviewed-on: https://chromium-review.googlesource.com/c/1366405
Reviewed-by: Curtis Malainey <cujomalainey@chromium.org>
Tested-by: Curtis Malainey <cujomalainey@chromium.org>
(cherry picked from commit ce30e4931524ab8f30f7d753f7d39cebb1bf4ac1)
Reviewed-on: https://chromium-review.googlesource.com/c/1372573
Reviewed-by: Justin TerAvest <teravest@chromium.org>
Commit-Queue: Justin TerAvest <teravest@chromium.org>
Tested-by: Justin TerAvest <teravest@chromium.org>
Trybot-Ready: Justin TerAvest <teravest@chromium.org>
diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c
index 61aceb2..be86ff3 100644
--- a/sound/soc/sof/intel/hda-loader.c
+++ b/sound/soc/sof/intel/hda-loader.c
@@ -34,6 +34,8 @@
 #include "../ops.h"
 #include "hda.h"
 
+#define HDA_FW_BOOT_ATTEMPTS	3
+
 static int cl_stream_prepare(struct snd_sof_dev *sdev, unsigned int format,
 			     unsigned int size, struct snd_dma_buffer *dmab,
 			     int direction)
@@ -313,54 +315,53 @@
 {
 	struct snd_sof_pdata *plat_data = dev_get_platdata(sdev->dev);
 	struct firmware stripped_firmware;
-	int ret, tag;
+	int ret, tag, i;
 
 	stripped_firmware.data = plat_data->fw->data;
 	stripped_firmware.size = plat_data->fw->size;
 
-	tag = cl_dsp_init(sdev, stripped_firmware.data,
-			  stripped_firmware.size);
+	/* init for booting wait */
+	init_waitqueue_head(&sdev->boot_wait);
+	sdev->boot_complete = false;
 
-	/* retry enabling core and ROM load. seemed to help */
-	if (tag < 0) {
+	/* try attempting fw boot a few times before giving up */
+	for (i = 0; i < HDA_FW_BOOT_ATTEMPTS; i++) {
 		tag = cl_dsp_init(sdev, stripped_firmware.data,
 				  stripped_firmware.size);
+
 		if (tag <= 0) {
 			dev_err(sdev->dev, "Error code=0x%x: FW status=0x%x\n",
 				snd_sof_dsp_read(sdev, HDA_DSP_BAR,
 						 HDA_DSP_SRAM_REG_ROM_ERROR),
 				snd_sof_dsp_read(sdev, HDA_DSP_BAR,
 						 HDA_DSP_SRAM_REG_ROM_STATUS));
-			dev_err(sdev->dev, "Core En/ROM load fail:%d\n",
-				tag);
+			dev_err(sdev->dev, "iteration %d of Core En/ROM load fail:%d\n",
+				i, tag);
 			ret = tag;
-			goto irq_err;
+			continue;
 		}
+
+		/* at this point DSP ROM has been initialized and
+		 * should be ready for code loading and firmware boot
+		 */
+		ret = cl_copy_fw(sdev, tag);
+		if (ret < 0) {
+			dev_err(sdev->dev, "error: iteration %d of load fw failed err: %d\n",
+				i, ret);
+			continue;
+		}
+
+
+		dev_dbg(sdev->dev, "Firmware download successful, booting...\n");
+		return ret;
 	}
 
-	/* init for booting wait */
-	init_waitqueue_head(&sdev->boot_wait);
-	sdev->boot_complete = false;
-
-	/* at this point DSP ROM has been initialized and should be ready for
-	 * code loading and firmware boot
-	 */
-	ret = cl_copy_fw(sdev, tag);
-	if (ret < 0) {
-		dev_err(sdev->dev, "error: load fw failed err: %d\n", ret);
-		goto irq_err;
-	}
-
-	dev_dbg(sdev->dev, "Firmware download successful, booting...\n");
-
-	return ret;
-
-irq_err:
 	hda_dsp_dump(sdev, SOF_DBG_REGS | SOF_DBG_PCI | SOF_DBG_MBOX);
 
 	/* disable DSP */
 	snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL,
 				SOF_HDA_PPCTL_GPROCEN, 0);
-	dev_err(sdev->dev, "error: load fw failed err: %d\n", ret);
+	dev_err(sdev->dev, "error: load fw failed after %d attempts with err: %d\n",
+		HDA_FW_BOOT_ATTEMPTS, ret);
 	return ret;
 }