|
@@ -302,6 +302,44 @@ static int mmc_read_ext_csd(struct mmc_card *card)
|
|
|
}
|
|
|
|
|
|
if (card->ext_csd.rev >= 4) {
|
|
|
+ /*
|
|
|
+ * Enhanced area feature support -- check whether the eMMC
|
|
|
+ * card has the Enhanced area enabled. If so, export enhanced
|
|
|
+ * area offset and size to user by adding sysfs interface.
|
|
|
+ */
|
|
|
+ if ((ext_csd[EXT_CSD_PARTITION_SUPPORT] & 0x2) &&
|
|
|
+ (ext_csd[EXT_CSD_PARTITION_ATTRIBUTE] & 0x1)) {
|
|
|
+ u8 hc_erase_grp_sz =
|
|
|
+ ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
|
|
|
+ u8 hc_wp_grp_sz =
|
|
|
+ ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
|
|
|
+
|
|
|
+ card->ext_csd.enhanced_area_en = 1;
|
|
|
+ /*
|
|
|
+ * calculate the enhanced data area offset, in bytes
|
|
|
+ */
|
|
|
+ card->ext_csd.enhanced_area_offset =
|
|
|
+ (ext_csd[139] << 24) + (ext_csd[138] << 16) +
|
|
|
+ (ext_csd[137] << 8) + ext_csd[136];
|
|
|
+ if (mmc_card_blockaddr(card))
|
|
|
+ card->ext_csd.enhanced_area_offset <<= 9;
|
|
|
+ /*
|
|
|
+ * calculate the enhanced data area size, in kilobytes
|
|
|
+ */
|
|
|
+ card->ext_csd.enhanced_area_size =
|
|
|
+ (ext_csd[142] << 16) + (ext_csd[141] << 8) +
|
|
|
+ ext_csd[140];
|
|
|
+ card->ext_csd.enhanced_area_size *=
|
|
|
+ (size_t)(hc_erase_grp_sz * hc_wp_grp_sz);
|
|
|
+ card->ext_csd.enhanced_area_size <<= 9;
|
|
|
+ } else {
|
|
|
+ /*
|
|
|
+ * If the enhanced area is not enabled, disable these
|
|
|
+ * device attributes.
|
|
|
+ */
|
|
|
+ card->ext_csd.enhanced_area_offset = -EINVAL;
|
|
|
+ card->ext_csd.enhanced_area_size = -EINVAL;
|
|
|
+ }
|
|
|
card->ext_csd.sec_trim_mult =
|
|
|
ext_csd[EXT_CSD_SEC_TRIM_MULT];
|
|
|
card->ext_csd.sec_erase_mult =
|
|
@@ -336,6 +374,9 @@ MMC_DEV_ATTR(manfid, "0x%06x\n", card->cid.manfid);
|
|
|
MMC_DEV_ATTR(name, "%s\n", card->cid.prod_name);
|
|
|
MMC_DEV_ATTR(oemid, "0x%04x\n", card->cid.oemid);
|
|
|
MMC_DEV_ATTR(serial, "0x%08x\n", card->cid.serial);
|
|
|
+MMC_DEV_ATTR(enhanced_area_offset, "%llu\n",
|
|
|
+ card->ext_csd.enhanced_area_offset);
|
|
|
+MMC_DEV_ATTR(enhanced_area_size, "%u\n", card->ext_csd.enhanced_area_size);
|
|
|
|
|
|
static struct attribute *mmc_std_attrs[] = {
|
|
|
&dev_attr_cid.attr,
|
|
@@ -349,6 +390,8 @@ static struct attribute *mmc_std_attrs[] = {
|
|
|
&dev_attr_name.attr,
|
|
|
&dev_attr_oemid.attr,
|
|
|
&dev_attr_serial.attr,
|
|
|
+ &dev_attr_enhanced_area_offset.attr,
|
|
|
+ &dev_attr_enhanced_area_size.attr,
|
|
|
NULL,
|
|
|
};
|
|
|
|
|
@@ -483,6 +526,37 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
|
|
|
mmc_set_erase_size(card);
|
|
|
}
|
|
|
|
|
|
+ /*
|
|
|
+ * If enhanced_area_en is TRUE, host needs to enable ERASE_GRP_DEF
|
|
|
+ * bit. This bit will be lost everytime after a reset or power off.
|
|
|
+ */
|
|
|
+ if (card->ext_csd.enhanced_area_en) {
|
|
|
+ err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
|
|
|
+ EXT_CSD_ERASE_GROUP_DEF, 1);
|
|
|
+
|
|
|
+ if (err && err != -EBADMSG)
|
|
|
+ goto free_card;
|
|
|
+
|
|
|
+ if (err) {
|
|
|
+ err = 0;
|
|
|
+ /*
|
|
|
+ * Just disable enhanced area off & sz
|
|
|
+ * will try to enable ERASE_GROUP_DEF
|
|
|
+ * during next time reinit
|
|
|
+ */
|
|
|
+ card->ext_csd.enhanced_area_offset = -EINVAL;
|
|
|
+ card->ext_csd.enhanced_area_size = -EINVAL;
|
|
|
+ } else {
|
|
|
+ card->ext_csd.erase_group_def = 1;
|
|
|
+ /*
|
|
|
+ * enable ERASE_GRP_DEF successfully.
|
|
|
+ * This will affect the erase size, so
|
|
|
+ * here need to reset erase size
|
|
|
+ */
|
|
|
+ mmc_set_erase_size(card);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
/*
|
|
|
* Activate high speed (if supported)
|
|
|
*/
|