feat(fwu): add a function to obtain an alternate FWU bank to boot

Add a function fwu_get_alternate_boot_bank() to return a valid bank to
boot from. This function can be called by a platform to get an
alternate bank to try to boot the platform in the unlikely scenario of
the active bank being in an invalid state, or if the number of times
the platform boots in trial state exceeds a pre-set count.

Change-Id: I4bcd88e68e334c452882255bf028e01b090369d1
Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
diff --git a/drivers/fwu/fwu.c b/drivers/fwu/fwu.c
index 5c3ccf8..b6f06e0 100644
--- a/drivers/fwu/fwu.c
+++ b/drivers/fwu/fwu.c
@@ -182,6 +182,63 @@
 }
 
 /*******************************************************************************
+ * Check for an alternate bank for the platform to boot from. This function will
+ * mostly be called whenever the count of the number of times a platform boots
+ * in the Trial State exceeds a pre-set limit.
+ * The function first checks if the platform can boot from the previously active
+ * bank. If not, it tries to find another bank in the accepted state.
+ * And finally, if both the checks fail, as a last resort, it tries to find
+ * a valid bank.
+ *
+ * Returns the index of a bank to boot, else returns invalid index
+ * INVALID_BOOT_IDX.
+ ******************************************************************************/
+uint32_t fwu_get_alternate_boot_bank(void)
+{
+	uint32_t i;
+
+	/* First check if the previously active bank can be used */
+	if (metadata.bank_state[metadata.previous_active_index] ==
+	    FWU_BANK_STATE_ACCEPTED) {
+		return metadata.previous_active_index;
+	}
+
+	/* Now check for any other bank in the accepted state */
+	for (i = 0U; i < NR_OF_FW_BANKS; i++) {
+		if (i == metadata.active_index ||
+		    i == metadata.previous_active_index) {
+			continue;
+		}
+
+		if (metadata.bank_state[i] == FWU_BANK_STATE_ACCEPTED) {
+			return i;
+		}
+	}
+
+	/*
+	 * No accepted bank found. Now try booting from a valid bank.
+	 * Give priority to the previous active bank.
+	 */
+	if (metadata.bank_state[metadata.previous_active_index] ==
+	    FWU_BANK_STATE_VALID) {
+		return metadata.previous_active_index;
+	}
+
+	for (i = 0U; i < NR_OF_FW_BANKS; i++) {
+		if (i == metadata.active_index ||
+		    i == metadata.previous_active_index) {
+			continue;
+		}
+
+		if (metadata.bank_state[i] == FWU_BANK_STATE_VALID) {
+			return i;
+		}
+	}
+
+	return INVALID_BOOT_IDX;
+}
+
+/*******************************************************************************
  * The platform can be in one of Valid, Invalid or Accepted states.
  *
  * Invalid - One or more images in the bank are corrupted, or partially
diff --git a/include/drivers/fwu/fwu.h b/include/drivers/fwu/fwu.h
index 489d4a1..18e8a31 100644
--- a/include/drivers/fwu/fwu.h
+++ b/include/drivers/fwu/fwu.h
@@ -13,8 +13,11 @@
 #define FWU_BANK_STATE_VALID		0xFEU
 #define FWU_BANK_STATE_INVALID		0xFFU
 
+#define INVALID_BOOT_IDX		0xFFFFFFFFU
+
 void fwu_init(void);
 uint32_t fwu_get_active_bank_state(void);
+uint32_t fwu_get_alternate_boot_bank(void);
 const struct fwu_metadata *fwu_get_metadata(void);
 
 #endif /* FWU_H */