From: Peng Fan Date: Mon, 20 Jan 2025 04:30:09 +0000 (+0800) Subject: mmc: Optimize eMMC erase speed X-Git-Tag: v2025.07-rc1~81^2~3 X-Git-Url: http://git.openpandora.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=674a0498e9b15a84524a0187f1d80ba30029a470;p=pandora-u-boot.git mmc: Optimize eMMC erase speed Per JESD84-B51 6.6.9 Erase: The host can erase a contiguous range of Erase Groups. Starting the erase process is a three steps sequence. First the host defines the start address of the range using the ERASE_GROUP_START (CMD35) command, next it defines the last address of the range using the ERASE_GROUP_END (CMD36) command and finally it starts the erase process by issuing the ERASE (CMD38) command with argument bits set to zero. See Table 11 for the arguments supported by CMD38. The address field in the erase commands is an Erase Group address, in byte units for densities up to 2GB, and in sector units for densities greater than 2GB. The Device will ignore all LSB's below the Erase Group size, effectively rounding the address down to the Erase Group boundary. So choose 2GB bytes as check condition. If the erase size is larger that 2GB, use 2GB to avoid breaking non high capacity cards. If erase size is less than 2GB and larger than a grp, use 'grpcnt * mmc->erase_grp_size' to cover all the sectors, else use the number of sectors. With test erasing 20GB eMMC board: Evk_8ulp Evk_8mm Evk_8mn Evk_8mp Mek_8qxpc0 Mek_8qm kingston sandisk before: 37.683s 112.738s 129.365s 28.238s 112.605s 500.470s 490.708s after: 0.093s 0.111s 0.951s 0.080s 0.121s 6.960s 6.915s Tested-by: Faqiang Zhu Signed-off-by: Peng Fan --- diff --git a/drivers/mmc/mmc_write.c b/drivers/mmc/mmc_write.c index c023d15e52a..90fcf2679bb 100644 --- a/drivers/mmc/mmc_write.c +++ b/drivers/mmc/mmc_write.c @@ -80,6 +80,8 @@ ulong mmc_berase(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt) struct mmc *mmc = find_mmc_device(dev_num); lbaint_t blk = 0, blk_r = 0; int timeout_ms = 1000; + u32 grpcnt; + if (!mmc) return -1; @@ -123,6 +125,15 @@ ulong mmc_berase(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt) } else { blk_r = ((blkcnt - blk) > mmc->erase_grp_size) ? mmc->erase_grp_size : (blkcnt - blk); + + grpcnt = (blkcnt - blk) / mmc->erase_grp_size; + /* Max 2GB per spec */ + if ((blkcnt - blk) > 0x400000) + blk_r = 0x400000; + else if (grpcnt) + blk_r = grpcnt * mmc->erase_grp_size; + else + blk_r = blkcnt - blk; } err = mmc_erase_t(mmc, start + blk, blk_r, erase_args); if (err)