feat(drivers/mmc): boot partition read support

Added a public function to read blocks from a current boot partition.
switch between partitions has to respect eMMC partition switch timing.

Signed-off-by: Vyacheslav Yurkov <uvv.mail@gmail.com>
Change-Id: I55b0c910314253e5647486609583fd290dadd30a
This commit is contained in:
Vyacheslav Yurkov 2021-03-30 08:16:20 +02:00
parent 0ef419b145
commit 5014b52dec
2 changed files with 84 additions and 3 deletions

View File

@ -105,6 +105,36 @@ static int mmc_device_state(void)
return MMC_GET_STATE(resp_data[0]);
}
static int mmc_send_part_switch_cmd(unsigned int part_config)
{
int ret;
unsigned int part_time = 0;
ret = mmc_send_cmd(MMC_CMD(6),
EXTCSD_WRITE_BYTES |
EXTCSD_CMD(CMD_EXTCSD_PARTITION_CONFIG) |
EXTCSD_VALUE(part_config) |
EXTCSD_CMD_SET_NORMAL,
MMC_RESPONSE_R1B, NULL);
if (ret != 0) {
return ret;
}
/* Partition switch timing is in 10ms units */
part_time = mmc_ext_csd[CMD_EXTCSD_PART_SWITCH_TIME] * 10;
mdelay(part_time);
do {
ret = mmc_device_state();
if (ret < 0) {
return ret;
}
} while (ret == MMC_STATE_PRG);
return 0;
}
static int mmc_set_ext_csd(unsigned int ext_cmd, unsigned int value)
{
int ret;
@ -668,7 +698,7 @@ static inline void mmc_rpmb_enable(void)
{
mmc_set_ext_csd(CMD_EXTCSD_PARTITION_CONFIG,
PART_CFG_BOOT_PARTITION1_ENABLE |
PART_CFG_PARTITION1_ACCESS);
PART_CFG_BOOT_PARTITION1_ACCESS);
}
static inline void mmc_rpmb_disable(void)
@ -710,6 +740,50 @@ size_t mmc_rpmb_erase_blocks(int lba, size_t size)
return size_erased;
}
static int mmc_part_switch(unsigned int part_type)
{
uint8_t part_config = mmc_ext_csd[CMD_EXTCSD_PARTITION_CONFIG];
part_config &= ~EXT_CSD_PART_CONFIG_ACC_MASK;
part_config |= part_type;
return mmc_send_part_switch_cmd(part_config);
}
static unsigned char mmc_current_boot_part(void)
{
return PART_CFG_CURRENT_BOOT_PARTITION(mmc_ext_csd[CMD_EXTCSD_PARTITION_CONFIG]);
}
size_t mmc_boot_part_read_blocks(int lba, uintptr_t buf, size_t size)
{
size_t size_read;
int ret;
unsigned char current_boot_part = mmc_current_boot_part();
if (current_boot_part != 1U &&
current_boot_part != 2U) {
ERROR("Got unexpected value for active boot partition, %u\n", current_boot_part);
return 0;
}
ret = mmc_part_switch(current_boot_part);
if (ret < 0) {
ERROR("Failed to switch to boot partition, %d\n", ret);
return 0;
}
size_read = mmc_read_blocks(lba, buf, size);
ret = mmc_part_switch(0);
if (ret < 0) {
ERROR("Failed to switch back to user partition, %d\n", ret);
return 0;
}
return size_read;
}
int mmc_init(const struct mmc_ops *ops_ptr, unsigned int clk,
unsigned int width, unsigned int flags,
struct mmc_device_info *device_info)

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@ -60,10 +60,16 @@
#define CMD_EXTCSD_PARTITION_CONFIG 179
#define CMD_EXTCSD_BUS_WIDTH 183
#define CMD_EXTCSD_HS_TIMING 185
#define CMD_EXTCSD_PART_SWITCH_TIME 199
#define CMD_EXTCSD_SEC_CNT 212
#define EXT_CSD_PART_CONFIG_ACC_MASK GENMASK(2, 0)
#define PART_CFG_BOOT_PARTITION1_ENABLE (U(1) << 3)
#define PART_CFG_PARTITION1_ACCESS (U(1) << 0)
#define PART_CFG_BOOT_PARTITION1_ACCESS (U(1) << 0)
#define PART_CFG_BOOT_PART_EN_MASK GENMASK(5, 3)
#define PART_CFG_BOOT_PART_EN_SHIFT 3
#define PART_CFG_CURRENT_BOOT_PARTITION(x) (((x) & PART_CFG_BOOT_PART_EN_MASK) >> \
PART_CFG_BOOT_PART_EN_SHIFT)
/* Values in EXT CSD register */
#define MMC_BUS_WIDTH_1 U(0)
@ -230,6 +236,7 @@ size_t mmc_erase_blocks(int lba, size_t size);
size_t mmc_rpmb_read_blocks(int lba, uintptr_t buf, size_t size);
size_t mmc_rpmb_write_blocks(int lba, const uintptr_t buf, size_t size);
size_t mmc_rpmb_erase_blocks(int lba, size_t size);
size_t mmc_boot_part_read_blocks(int lba, uintptr_t buf, size_t size);
int mmc_init(const struct mmc_ops *ops_ptr, unsigned int clk,
unsigned int width, unsigned int flags,
struct mmc_device_info *device_info);