From patchwork Sun Nov 8 13:14:08 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andre Przywara X-Patchwork-Id: 1396298 X-Patchwork-Delegate: andre.przywara@arm.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=2a01:238:438b:c500:173d:9f52:ddab:ee01; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=arm.com Received: from phobos.denx.de (phobos.denx.de [IPv6:2a01:238:438b:c500:173d:9f52:ddab:ee01]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4CTZP96v5sz9sTD for ; Mon, 9 Nov 2020 00:15:25 +1100 (AEDT) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id C570082513; Sun, 8 Nov 2020 14:14:42 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=fail (p=none dis=none) header.from=arm.com Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Received: by phobos.denx.de (Postfix, from userid 109) id 860B882496; Sun, 8 Nov 2020 14:14:36 +0100 (CET) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,SPF_HELO_NONE, URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.2 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by phobos.denx.de (Postfix) with ESMTP id 26ACE823EF for ; Sun, 8 Nov 2020 14:14:31 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=arm.com Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=andre.przywara@arm.com Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id D055411FB; Sun, 8 Nov 2020 05:14:29 -0800 (PST) Received: from localhost.localdomain (unknown [172.31.20.19]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 4DBD13F719; Sun, 8 Nov 2020 05:14:28 -0800 (PST) From: Andre Przywara To: Jagan Teki Cc: =?utf-8?q?Petr_=C5=A0tetiar?= , Sunil Mohan Adapa , Samuel Holland , Aleksandr Aleksandrov , Icenowy Zheng , Simon Glass , Tom Rini , linux-sunxi@googlegroups.com, u-boot@lists.denx.de, Andre Przywara Subject: [PATCH 4/5] sunxi: eMMC: Add automatic boot detection Date: Sun, 8 Nov 2020 13:14:08 +0000 Message-Id: <20201108131409.14320-5-andre.przywara@arm.com> X-Mailer: git-send-email 2.14.1 In-Reply-To: <20201108131409.14320-1-andre.przywara@arm.com> References: <20201108131409.14320-1-andre.przywara@arm.com> X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.34 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.102.3 at phobos.denx.de X-Virus-Status: Clean When the Allwinner BROM loads the SPL from an eMMC boot partition, it sets the boot source byte to the same value as when booting from the user data partition. This prevents us from easily determining the boot source to load U-Boot proper from the proper partition. To learn about the boot source anyway, we repeat the algorithm the BROM used to select the boot partition in the first place: - Test EXT_CSD[179] to check if an eMMC boot partition is enabled. - Test EXT_CSD[177] to check for valid MMC interface settings. - Check if BOOT_ACK is enabled. - Check the beginning of the first sector for a valid eGON signature. - Load the whole SPL (limited to be at most 32KB). - Recalculate the checksum to verify the SPL is valid. If one of those steps fails, we bail out and continue loading from the user data partition. Otherwise we load from the selected boot partition, automatically adjusting the sector offset accordingly. Since the boot source is needed twice in the boot process, we cache the result of this test to avoid doing this costly test multiple times. This allows the very same image file to be put onto an SD card, into the eMMC user data partition or into the eMMC boot partition. CONFIG_SUPPORT_EMMC_BOOT needs still to be enabled to activate this feature, but it does not force booting from the eMMC boot partition anymore. Signed-off-by: Andre Przywara --- arch/arm/mach-sunxi/board.c | 86 ++++++++++++++++++++++++++++++++++++- 1 file changed, 85 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-sunxi/board.c b/arch/arm/mach-sunxi/board.c index 586af24535d..a141f24acdd 100644 --- a/arch/arm/mach-sunxi/board.c +++ b/arch/arm/mach-sunxi/board.c @@ -291,7 +291,7 @@ unsigned long spl_mmc_get_uboot_raw_sector(struct mmc *mmc) switch (sunxi_get_boot_source()) { case SUNXI_BOOTED_FROM_MMC2: - if (IS_ENABLED(CONFIG_SUPPORT_EMMC_BOOT)) + if (spl_mmc_boot_mode(mmc, 1) == MMCSD_MODE_EMMCBOOT) sector -= 8 * 2; break; case SUNXI_BOOTED_FROM_MMC0_HIGH: @@ -310,6 +310,90 @@ u32 spl_boot_device(void) return sunxi_get_boot_device(); } +/* + * When booting from an eMMC boot partition, the SPL puts the same boot + * source code into SRAM A1 as when loading the SPL from the normal + * eMMC user data partition: 0x2. So to know where we have been loaded + * from, we repeat the BROM algorithm here: checking for a valid eGON boot + * image at offset 0 of a (potentially) selected boot partition. + * If any of the conditions is not met, it must have been the eMMC user + * data partition. + */ +static bool sunxi_valid_emmc_boot(struct mmc *mmc) +{ + struct blk_desc *bd = mmc_get_blk_desc(mmc); + uint32_t *buffer = (void *)(uintptr_t)CONFIG_SYS_TEXT_BASE; + int bootpart = EXT_CSD_EXTRACT_BOOT_PART(mmc->part_config); + uint32_t spl_size, emmc_checksum, chksum = 0; + ulong count; + + /* The BROM requires BOOT_ACK to be enabled. */ + if (!EXT_CSD_EXTRACT_BOOT_ACK(mmc->part_config)) + return false; + + /* + * The BOOT_BUS_CONDITION register must be 4-bit SDR, with (0x09) + * or without (0x01) high speed timings. + */ + if ((mmc->ext_csd[EXT_CSD_BOOT_BUS_WIDTH] & 0x1b) != 0x01 && + (mmc->ext_csd[EXT_CSD_BOOT_BUS_WIDTH] & 0x1b) != 0x09) + return false; + + /* Partition 0 is the user data partition, bootpart must be 1 or 2. */ + if (bootpart != 1 && bootpart != 2) + return false; + + mmc_switch_part(mmc, bootpart); + + /* Read the first block to do some sanity checks on the eGON header. */ + count = blk_dread(bd, 0, 1, buffer); + if (count != 1 || !is_boot0_magic(buffer + 1)) + return false; + + /* The BROM will only read up to 32KB into SRAM A1. */ + spl_size = buffer[4]; + if ((spl_size & 3) || spl_size > 32768) + return false; + + /* Read the rest of the SPL now we know it's halfway sane. */ + count = blk_dread(bd, 1, DIV_ROUND_UP(spl_size, bd->blksz) - 1, + buffer + bd->blksz / 4); + + /* Save the checksum and replace it with the "stamp value". */ + emmc_checksum = buffer[3]; + buffer[3] = 0x5f0a6c39; + + /* The checksum is a simple ignore-carry addition of all words. */ + for (count = 0; count < spl_size / 4; count++) + chksum += buffer[count]; + + debug("eMMC boot part SPL checksum: stored: 0x%08x, computed: 0x%08x\n", + emmc_checksum, chksum); + + return emmc_checksum == chksum; +} + +u32 spl_mmc_boot_mode(struct mmc *mmc, const u32 boot_device) +{ + static u32 result = ~0; + + if (result != ~0) + return result; + + result = MMCSD_MODE_RAW; + if (!IS_SD(mmc) && IS_ENABLED(CONFIG_SUPPORT_EMMC_BOOT)) { + if (sunxi_valid_emmc_boot(mmc)) + result = MMCSD_MODE_EMMCBOOT; + else + mmc_switch_part(mmc, 0); + } + + debug("%s(): %s part\n", __func__, + result == MMCSD_MODE_RAW ? "user" : "boot"); + + return result; +} + void board_init_f(ulong dummy) { spl_init();