diff mbox series

[3/3] imx8: spl: Support booting from secondary container set

Message ID 1591698884-72174-3-git-send-email-ye.li@nxp.com
State New
Headers show
Series [1/3] misc: scu_api: Add SCFW API to get the index of boot container set | expand

Commit Message

Ye Li June 9, 2020, 10:34 a.m. UTC
On i.MX8QM B0 and i.MX8QXP C0, ROM supports to boot from secondary
container set when either booting from primary container set is failed
or secondary container set has higher SW version.

Add the support to SPL to load u-boot container from secondary set
when ROM boots from the secondary set. Using the SCFW API to get current
container set index. If it is the secondary boot, get the offset from
fuse and apply it to the offset of primary container set.

For emmc boot from boot0/1 part, override the emmc boot partition
function to check secondary boot and switch to correct boot part.

Signed-off-by: Ye Li <ye.li at nxp.com>
Reviewed-by: Peng Fan <peng.fan at nxp.com>
---
 arch/arm/mach-imx/imx8/image.c | 81 +++++++++++++++++++++++++++++++++++++++---
 1 file changed, 76 insertions(+), 5 deletions(-)
diff mbox series

Patch

diff --git a/arch/arm/mach-imx/imx8/image.c b/arch/arm/mach-imx/imx8/image.c
index 5abc0d3..bd0e0a2 100644
--- a/arch/arm/mach-imx/imx8/image.c
+++ b/arch/arm/mach-imx/imx8/image.c
@@ -20,6 +20,23 @@ 
 #define NAND_DEV	2
 #define QSPI_NOR_DEV	3
 
+/* The unit of second image offset number which provision by the fuse bits */
+#define SND_IMG_OFF_UNIT    (0x100000UL)
+
+/*
+ * If num = 0, off = (2 ^ 2) * 1MB
+ * else If num = 2, off = (2 ^ 0) * 1MB
+ * else off = (2 ^ num) * 1MB
+ */
+#define SND_IMG_NUM_TO_OFF(num) \
+	((1UL << ((0 == (num)) ? 2 : (2 == (num)) ? 0 : (num))) * SND_IMG_OFF_UNIT)
+
+#if IS_ENABLED(CONFIG_IMX8QM)
+#define FUSE_IMG_SET_OFF_WORD 464
+#elif IS_ENABLED(CONFIG_IMX8QXP)
+#define FUSE_IMG_SET_OFF_WORD 720
+#endif
+
 static int __get_container_size(ulong addr)
 {
 	struct container_hdr *phdr;
@@ -122,15 +139,46 @@  static int get_container_size(void *dev, int dev_type, unsigned long offset)
 	return ret;
 }
 
+static bool check_secondary_cnt_set(unsigned long *set_off)
+{
+	int ret;
+	u8 set_id = 1;
+	u32 fuse_val = 0;
+
+	if (!(is_imx8qxp() && is_soc_rev(CHIP_REV_B))) {
+		ret = sc_misc_get_boot_container(-1, &set_id);
+		if (!ret) {
+			/* Secondary boot */
+			if (set_id == 2) {
+				ret = sc_misc_otp_fuse_read(-1, FUSE_IMG_SET_OFF_WORD, &fuse_val);
+				if (!ret) {
+					if (set_off)
+						*set_off = SND_IMG_NUM_TO_OFF(fuse_val);
+					return true;
+				}
+			}
+		}
+	}
+
+	return false;
+}
+
 static unsigned long get_boot_device_offset(void *dev, int dev_type)
 {
-	unsigned long offset = 0;
+	unsigned long offset = 0, sec_set_off = 0;
+	bool sec_boot = false;
+
+	sec_boot = check_secondary_cnt_set(&sec_set_off);
+	if (sec_boot)
+		printf("Secondary set selected\n");
+	else
+		printf("Primary set selected\n");
 
 	if (dev_type == MMC_DEV) {
 		struct mmc *mmc = (struct mmc *)dev;
 
 		if (IS_SD(mmc) || mmc->part_config == MMCPART_NOAVAILABLE) {
-			offset = CONTAINER_HDR_MMCSD_OFFSET;
+			offset = sec_boot ? sec_set_off : CONTAINER_HDR_MMCSD_OFFSET;
 		} else {
 			u8 part = EXT_CSD_EXTRACT_BOOT_PART(mmc->part_config);
 
@@ -140,17 +188,21 @@  static unsigned long get_boot_device_offset(void *dev, int dev_type)
 				else
 					offset = CONTAINER_HDR_EMMC_OFFSET;
 			} else {
-				offset = CONTAINER_HDR_MMCSD_OFFSET;
+				offset = sec_boot ? sec_set_off : CONTAINER_HDR_MMCSD_OFFSET;
 			}
 		}
 	} else if (dev_type == QSPI_DEV) {
-		offset = CONTAINER_HDR_QSPI_OFFSET;
+		offset = sec_boot ? (sec_set_off + CONTAINER_HDR_QSPI_OFFSET) :
+			CONTAINER_HDR_QSPI_OFFSET;
 	} else if (dev_type == NAND_DEV) {
-		offset = CONTAINER_HDR_NAND_OFFSET;
+		offset = sec_boot ? (sec_set_off + CONTAINER_HDR_NAND_OFFSET) :
+			CONTAINER_HDR_NAND_OFFSET;
 	} else if (dev_type == QSPI_NOR_DEV) {
 		offset = CONTAINER_HDR_QSPI_OFFSET + 0x08000000;
 	}
 
+	debug("container set offset 0x%lx\n", offset);
+
 	return offset;
 }
 
@@ -210,6 +262,25 @@  unsigned long spl_mmc_get_uboot_raw_sector(struct mmc *mmc,
 
 	return end / mmc->read_bl_len;
 }
+
+int spl_mmc_emmc_boot_partition(struct mmc *mmc)
+{
+	int part = 0;
+
+	part = EXT_CSD_EXTRACT_BOOT_PART(mmc->part_config);
+	if (part == 1 || part == 2) {
+		unsigned long sec_set_off = 0;
+		bool sec_boot = false;
+
+		sec_boot = check_secondary_cnt_set(&sec_set_off);
+		if (sec_boot)
+			part = (part == 1) ? 2 : 1;
+	} else if (part == 7) {
+		part = 0;
+	}
+
+	return part;
+}
 #endif
 
 #ifdef CONFIG_SPL_NAND_SUPPORT