/* * Decode extended CSD. */ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) { int err = 0, idx; unsigned int part_size; u8 hc_erase_grp_sz = 0, hc_wp_grp_sz = 0; BUG_ON(!card); if (!ext_csd) return 0; /* Version is coded in the CSD_STRUCTURE byte in the EXT_CSD register */ card->ext_csd.raw_ext_csd_structure = ext_csd[EXT_CSD_STRUCTURE]; if (card->csd.structure == 3) { if (card->ext_csd.raw_ext_csd_structure > 2) { pr_err("%s: unrecognised EXT_CSD structure " "version %d\n", mmc_hostname(card->host), card->ext_csd.raw_ext_csd_structure); err = -EINVAL; goto out; } } card->ext_csd.rev = ext_csd[EXT_CSD_REV]; if (card->ext_csd.rev > 6) { printk(KERN_ERR "%s: unrecognised EXT_CSD revision %d\n", mmc_hostname(card->host), card->ext_csd.rev); err = -EINVAL; goto out; } card->ext_csd.raw_sectors[0] = ext_csd[EXT_CSD_SEC_CNT + 0]; card->ext_csd.raw_sectors[1] = ext_csd[EXT_CSD_SEC_CNT + 1]; card->ext_csd.raw_sectors[2] = ext_csd[EXT_CSD_SEC_CNT + 2]; card->ext_csd.raw_sectors[3] = ext_csd[EXT_CSD_SEC_CNT + 3]; if (card->ext_csd.rev >= 2) { card->ext_csd.sectors = ext_csd[EXT_CSD_SEC_CNT + 0] << 0 | ext_csd[EXT_CSD_SEC_CNT + 1] << 8 | ext_csd[EXT_CSD_SEC_CNT + 2] << 16 | ext_csd[EXT_CSD_SEC_CNT + 3] << 24; /* Cards with density > 2GiB are sector addressed */ if (card->ext_csd.sectors > (2u * 1024 * 1024 * 1024) / 512) mmc_card_set_blockaddr(card); } card->ext_csd.raw_card_type = ext_csd[EXT_CSD_CARD_TYPE]; mmc_select_card_type(card); card->ext_csd.raw_s_a_timeout = ext_csd[EXT_CSD_S_A_TIMEOUT]; card->ext_csd.raw_erase_timeout_mult = ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT]; card->ext_csd.raw_hc_erase_grp_size = ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]; if (card->ext_csd.rev >= 3) { u8 sa_shift = ext_csd[EXT_CSD_S_A_TIMEOUT]; card->ext_csd.part_config = ext_csd[EXT_CSD_PART_CONFIG]; /* EXT_CSD value is in units of 10ms, but we store in ms */ card->ext_csd.part_time = 10 * ext_csd[EXT_CSD_PART_SWITCH_TIME]; /* Sleep / awake timeout in 100ns units */ if (sa_shift > 0 && sa_shift <= 0x17) card->ext_csd.sa_timeout = 1 << ext_csd[EXT_CSD_S_A_TIMEOUT]; card->ext_csd.erase_group_def = ext_csd[EXT_CSD_ERASE_GROUP_DEF]; card->ext_csd.hc_erase_timeout = 300 * ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT]; card->ext_csd.hc_erase_size = ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] << 10; card->ext_csd.rel_sectors = ext_csd[EXT_CSD_REL_WR_SEC_C]; /* * There are two boot regions of equal size, defined in * multiples of 128K. */ if (ext_csd[EXT_CSD_BOOT_MULT] && mmc_boot_partition_access(card->host)) { for (idx = 0; idx < MMC_NUM_BOOT_PARTITION; idx++) { part_size = ext_csd[EXT_CSD_BOOT_MULT] << 17; mmc_part_add(card, part_size, EXT_CSD_PART_CONFIG_ACC_BOOT0 + idx, "boot%d", idx, true, MMC_BLK_DATA_AREA_BOOT); } } } card->ext_csd.raw_hc_erase_gap_size = ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; card->ext_csd.raw_sec_trim_mult = ext_csd[EXT_CSD_SEC_TRIM_MULT]; card->ext_csd.raw_sec_erase_mult = ext_csd[EXT_CSD_SEC_ERASE_MULT]; card->ext_csd.raw_sec_feature_support = ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT]; card->ext_csd.raw_trim_mult = ext_csd[EXT_CSD_TRIM_MULT]; card->ext_csd.raw_partition_support = ext_csd[EXT_CSD_PARTITION_SUPPORT]; 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)) { hc_erase_grp_sz = ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]; 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; } /* * General purpose partition feature support -- * If ext_csd has the size of general purpose partitions, * set size, part_cfg, partition name in mmc_part. */ if (ext_csd[EXT_CSD_PARTITION_SUPPORT] & EXT_CSD_PART_SUPPORT_PART_EN) { if (card->ext_csd.enhanced_area_en != 1) { hc_erase_grp_sz = ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]; hc_wp_grp_sz = ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; card->ext_csd.enhanced_area_en = 1; } for (idx = 0; idx < MMC_NUM_GP_PARTITION; idx++) { if (!ext_csd[EXT_CSD_GP_SIZE_MULT + idx * 3] && !ext_csd[EXT_CSD_GP_SIZE_MULT + idx * 3 + 1] && !ext_csd[EXT_CSD_GP_SIZE_MULT + idx * 3 + 2]) continue; part_size = (ext_csd[EXT_CSD_GP_SIZE_MULT + idx * 3 + 2] << 16) + (ext_csd[EXT_CSD_GP_SIZE_MULT + idx * 3 + 1] << 8) + ext_csd[EXT_CSD_GP_SIZE_MULT + idx * 3]; part_size *= (size_t)(hc_erase_grp_sz * hc_wp_grp_sz); mmc_part_add(card, part_size << 19, EXT_CSD_PART_CONFIG_ACC_GP0 + idx, "gp%d", idx, false, MMC_BLK_DATA_AREA_GP); } } card->ext_csd.sec_trim_mult = ext_csd[EXT_CSD_SEC_TRIM_MULT]; card->ext_csd.sec_erase_mult = ext_csd[EXT_CSD_SEC_ERASE_MULT]; card->ext_csd.sec_feature_support = ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT]; card->ext_csd.trim_timeout = 300 * ext_csd[EXT_CSD_TRIM_MULT]; /* * Note that the call to mmc_part_add above defaults to read * only. If this default assumption is changed, the call must * take into account the value of boot_locked below. */ card->ext_csd.boot_ro_lock = ext_csd[EXT_CSD_BOOT_WP]; card->ext_csd.boot_ro_lockable = true; } if (card->ext_csd.rev >= 5) { /* check whether the eMMC card support BKOPS */ if (ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1) { card->ext_csd.bkops = 1; card->ext_csd.bkops_en = ext_csd[EXT_CSD_BKOPS_EN]; card->ext_csd.raw_bkops_status = ext_csd[EXT_CSD_BKOPS_STATUS]; if (!card->ext_csd.bkops_en && card->host->caps2 & MMC_CAP2_INIT_BKOPS) { err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BKOPS_EN, 1, 0); if (err) pr_warning("%s: Enabling BKOPS failed\n", mmc_hostname(card->host)); else card->ext_csd.bkops_en = 1; } } /* check whether the eMMC card supports HPI */ if (ext_csd[EXT_CSD_HPI_FEATURES] & 0x1) { card->ext_csd.hpi = 1; if (ext_csd[EXT_CSD_HPI_FEATURES] & 0x2) card->ext_csd.hpi_cmd = MMC_STOP_TRANSMISSION; else card->ext_csd.hpi_cmd = MMC_SEND_STATUS; /* * Indicate the maximum timeout to close * a command interrupted by HPI */ card->ext_csd.out_of_int_time = ext_csd[EXT_CSD_OUT_OF_INTERRUPT_TIME] * 10; } card->ext_csd.rel_param = ext_csd[EXT_CSD_WR_REL_PARAM]; card->ext_csd.rst_n_function = ext_csd[EXT_CSD_RST_N_FUNCTION]; } card->ext_csd.raw_erased_mem_count = ext_csd[EXT_CSD_ERASED_MEM_CONT]; if (ext_csd[EXT_CSD_ERASED_MEM_CONT]) card->erased_byte = 0xFF; else card->erased_byte = 0x0; /* eMMC v4.5 or later */ if (card->ext_csd.rev >= 6) { card->ext_csd.feature_support |= MMC_DISCARD_FEATURE; card->ext_csd.generic_cmd6_time = 10 * ext_csd[EXT_CSD_GENERIC_CMD6_TIME]; card->ext_csd.power_off_longtime = 10 * ext_csd[EXT_CSD_POWER_OFF_LONG_TIME]; card->ext_csd.cache_size = ext_csd[EXT_CSD_CACHE_SIZE + 0] << 0 | ext_csd[EXT_CSD_CACHE_SIZE + 1] << 8 | ext_csd[EXT_CSD_CACHE_SIZE + 2] << 16 | ext_csd[EXT_CSD_CACHE_SIZE + 3] << 24; if (ext_csd[EXT_CSD_DATA_SECTOR_SIZE] == 1) card->ext_csd.data_sector_size = 4096; else card->ext_csd.data_sector_size = 512; if ((ext_csd[EXT_CSD_DATA_TAG_SUPPORT] & 1) && (ext_csd[EXT_CSD_TAG_UNIT_SIZE] <= 8)) { card->ext_csd.data_tag_unit_size = ((unsigned int) 1 << ext_csd[EXT_CSD_TAG_UNIT_SIZE]) * (card->ext_csd.data_sector_size); } else { card->ext_csd.data_tag_unit_size = 0; } card->ext_csd.max_packed_writes = ext_csd[EXT_CSD_MAX_PACKED_WRITES]; card->ext_csd.max_packed_reads = ext_csd[EXT_CSD_MAX_PACKED_READS]; } /* [LGE_CHANGE_S] [email protected] * samsung support discard option on version 4.41+ * Enable discard only for V3, also check manufacture id in case of V3 support both memory(Hynix, Samsung). * DO NOT add feature for v7/u0/m4/etc without firm reason on emmc spec or vendor confirm */ #if defined (CONFIG_MACH_MSM7X25A_V3) && defined (CONFIG_MACH_FEATURE_DISCARD) #define MANUFACTURE_ID_SAMSUNG 0x15 if (card->cid.manfid == MANUFACTURE_ID_SAMSUNG) { card->ext_csd.feature_support |= MMC_DISCARD_FEATURE; pr_info("%s: !!! card->cid.manfid:%d, prod_name:%s !!! \n", mmc_hostname(card->host), card->cid.manfid, card->cid.prod_name); } #endif out: return err; }
static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) { int err = 0, idx; unsigned int part_size; u8 hc_erase_grp_sz = 0, hc_wp_grp_sz = 0; BUG_ON(!card); if (!ext_csd) return 0; /* Version is coded in the CSD_STRUCTURE byte in the EXT_CSD register */ card->ext_csd.raw_ext_csd_structure = ext_csd[EXT_CSD_STRUCTURE]; if (card->csd.structure == 3) { if (card->ext_csd.raw_ext_csd_structure > 2) { pr_err("%s: unrecognised EXT_CSD structure " "version %d\n", mmc_hostname(card->host), card->ext_csd.raw_ext_csd_structure); err = -EINVAL; goto out; } } card->ext_csd.rev = ext_csd[EXT_CSD_REV]; if (card->ext_csd.rev > 7) { pr_err("%s: unrecognised EXT_CSD revision %d\n", mmc_hostname(card->host), card->ext_csd.rev); err = -EINVAL; goto out; } card->ext_csd.raw_sectors[0] = ext_csd[EXT_CSD_SEC_CNT + 0]; card->ext_csd.raw_sectors[1] = ext_csd[EXT_CSD_SEC_CNT + 1]; card->ext_csd.raw_sectors[2] = ext_csd[EXT_CSD_SEC_CNT + 2]; card->ext_csd.raw_sectors[3] = ext_csd[EXT_CSD_SEC_CNT + 3]; if (card->ext_csd.rev >= 2) { card->ext_csd.sectors = ext_csd[EXT_CSD_SEC_CNT + 0] << 0 | ext_csd[EXT_CSD_SEC_CNT + 1] << 8 | ext_csd[EXT_CSD_SEC_CNT + 2] << 16 | ext_csd[EXT_CSD_SEC_CNT + 3] << 24; /* Cards with density > 2GiB are sector addressed */ if (card->ext_csd.sectors > (2u * 1024 * 1024 * 1024) / 512) mmc_card_set_blockaddr(card); } card->ext_csd.raw_card_type = ext_csd[EXT_CSD_CARD_TYPE]; switch (ext_csd[EXT_CSD_CARD_TYPE] & EXT_CSD_CARD_TYPE_MASK) { case EXT_CSD_CARD_TYPE_SDR_ALL: case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_8V: case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_2V: case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_52: card->ext_csd.hs_max_dtr = 200000000; card->ext_csd.card_type = EXT_CSD_CARD_TYPE_SDR_200; break; case EXT_CSD_CARD_TYPE_SDR_1_2V_ALL: case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_8V: case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_2V: case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_52: card->ext_csd.hs_max_dtr = 200000000; card->ext_csd.card_type = EXT_CSD_CARD_TYPE_SDR_1_2V; break; case EXT_CSD_CARD_TYPE_SDR_1_8V_ALL: case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_8V: case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_2V: case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_52: card->ext_csd.hs_max_dtr = 200000000; card->ext_csd.card_type = EXT_CSD_CARD_TYPE_SDR_1_8V; break; case EXT_CSD_CARD_TYPE_DDR_52 | EXT_CSD_CARD_TYPE_52 | EXT_CSD_CARD_TYPE_26: card->ext_csd.hs_max_dtr = 52000000; card->ext_csd.card_type = EXT_CSD_CARD_TYPE_DDR_52; break; case EXT_CSD_CARD_TYPE_DDR_1_2V | EXT_CSD_CARD_TYPE_52 | EXT_CSD_CARD_TYPE_26: card->ext_csd.hs_max_dtr = 52000000; card->ext_csd.card_type = EXT_CSD_CARD_TYPE_DDR_1_2V; break; case EXT_CSD_CARD_TYPE_DDR_1_8V | EXT_CSD_CARD_TYPE_52 | EXT_CSD_CARD_TYPE_26: card->ext_csd.hs_max_dtr = 52000000; card->ext_csd.card_type = EXT_CSD_CARD_TYPE_DDR_1_8V; break; case EXT_CSD_CARD_TYPE_52 | EXT_CSD_CARD_TYPE_26: card->ext_csd.hs_max_dtr = 52000000; break; case EXT_CSD_CARD_TYPE_26: card->ext_csd.hs_max_dtr = 26000000; break; default: /* MMC v4 spec says this cannot happen */ pr_warning("%s: card is mmc v4 but doesn't " "support any high-speed modes.\n", mmc_hostname(card->host)); } card->ext_csd.raw_s_a_timeout = ext_csd[EXT_CSD_S_A_TIMEOUT]; card->ext_csd.raw_erase_timeout_mult = ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT]; card->ext_csd.raw_hc_erase_grp_size = ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]; if (card->ext_csd.rev >= 3) { u8 sa_shift = ext_csd[EXT_CSD_S_A_TIMEOUT]; card->ext_csd.part_config = ext_csd[EXT_CSD_PART_CONFIG]; /* EXT_CSD value is in units of 10ms, but we store in ms */ card->ext_csd.part_time = 10 * ext_csd[EXT_CSD_PART_SWITCH_TIME]; /* Sleep / awake timeout in 100ns units */ if (sa_shift > 0 && sa_shift <= 0x17) card->ext_csd.sa_timeout = 1 << ext_csd[EXT_CSD_S_A_TIMEOUT]; card->ext_csd.erase_group_def = ext_csd[EXT_CSD_ERASE_GROUP_DEF]; card->ext_csd.hc_erase_timeout = 300 * ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT]; card->ext_csd.hc_erase_size = ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] << 10; card->ext_csd.rel_sectors = ext_csd[EXT_CSD_REL_WR_SEC_C]; /* * There are two boot regions of equal size, defined in * multiples of 128K. */ if (ext_csd[EXT_CSD_BOOT_MULT] && mmc_boot_partition_access(card->host)) { for (idx = 0; idx < MMC_NUM_BOOT_PARTITION; idx++) { part_size = ext_csd[EXT_CSD_BOOT_MULT] << 17; mmc_part_add(card, part_size, EXT_CSD_PART_CONFIG_ACC_BOOT0 + idx, "boot%d", idx, true, MMC_BLK_DATA_AREA_BOOT); } } } card->ext_csd.raw_hc_erase_gap_size = ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; card->ext_csd.raw_sec_trim_mult = ext_csd[EXT_CSD_SEC_TRIM_MULT]; card->ext_csd.raw_sec_erase_mult = ext_csd[EXT_CSD_SEC_ERASE_MULT]; card->ext_csd.raw_sec_feature_support = ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT]; card->ext_csd.raw_trim_mult = ext_csd[EXT_CSD_TRIM_MULT]; 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. */ card->ext_csd.raw_partition_support = ext_csd[EXT_CSD_PARTITION_SUPPORT]; if ((ext_csd[EXT_CSD_PARTITION_SUPPORT] & 0x2) && (ext_csd[EXT_CSD_PARTITION_ATTRIBUTE] & 0x1)) { hc_erase_grp_sz = ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]; 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; } /* * General purpose partition feature support -- * If ext_csd has the size of general purpose partitions, * set size, part_cfg, partition name in mmc_part. */ if (ext_csd[EXT_CSD_PARTITION_SUPPORT] & EXT_CSD_PART_SUPPORT_PART_EN) { if (card->ext_csd.enhanced_area_en != 1) { hc_erase_grp_sz = ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]; hc_wp_grp_sz = ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; card->ext_csd.enhanced_area_en = 1; } for (idx = 0; idx < MMC_NUM_GP_PARTITION; idx++) { if (!ext_csd[EXT_CSD_GP_SIZE_MULT + idx * 3] && !ext_csd[EXT_CSD_GP_SIZE_MULT + idx * 3 + 1] && !ext_csd[EXT_CSD_GP_SIZE_MULT + idx * 3 + 2]) continue; part_size = (ext_csd[EXT_CSD_GP_SIZE_MULT + idx * 3 + 2] << 16) + (ext_csd[EXT_CSD_GP_SIZE_MULT + idx * 3 + 1] << 8) + ext_csd[EXT_CSD_GP_SIZE_MULT + idx * 3]; part_size *= (size_t)(hc_erase_grp_sz * hc_wp_grp_sz); mmc_part_add(card, part_size << 19, EXT_CSD_PART_CONFIG_ACC_GP0 + idx, "gp%d", idx, false, MMC_BLK_DATA_AREA_GP); } } card->ext_csd.sec_trim_mult = ext_csd[EXT_CSD_SEC_TRIM_MULT]; card->ext_csd.sec_erase_mult = ext_csd[EXT_CSD_SEC_ERASE_MULT]; card->ext_csd.sec_feature_support = ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT]; card->ext_csd.trim_timeout = 300 * ext_csd[EXT_CSD_TRIM_MULT]; /* * Note that the call to mmc_part_add above defaults to read * only. If this default assumption is changed, the call must * take into account the value of boot_locked below. */ card->ext_csd.boot_ro_lock = ext_csd[EXT_CSD_BOOT_WP]; card->ext_csd.boot_ro_lockable = true; } if (card->ext_csd.rev >= 5) { /* check whether the eMMC card supports HPI */ if (ext_csd[EXT_CSD_HPI_FEATURES] & 0x1) { card->ext_csd.hpi = 1; if (ext_csd[EXT_CSD_HPI_FEATURES] & 0x2) card->ext_csd.hpi_cmd = MMC_STOP_TRANSMISSION; else card->ext_csd.hpi_cmd = MMC_SEND_STATUS; /* * Indicate the maximum timeout to close * a command interrupted by HPI */ card->ext_csd.out_of_int_time = ext_csd[EXT_CSD_OUT_OF_INTERRUPT_TIME] * 10; } card->ext_csd.rel_param = ext_csd[EXT_CSD_WR_REL_PARAM]; card->ext_csd.rst_n_function = ext_csd[EXT_CSD_RST_N_FUNCTION]; } card->ext_csd.raw_erased_mem_count = ext_csd[EXT_CSD_ERASED_MEM_CONT]; if (ext_csd[EXT_CSD_ERASED_MEM_CONT]) card->erased_byte = 0xFF; else card->erased_byte = 0x0; /* for samsung emmc4.41 plus spec */ if ((card->cid.manfid == VENDOR_SAMSUNG) && (card->ext_csd.rev == 5) && (1 == (0x1 & ext_csd[EXT_CSD_SAMSUNG_FEATURE]))){ printk("set to support discard\n"); card->ext_csd.feature_support |= MMC_DISCARD_FEATURE; } /* eMMC v4.5 or later */ if (card->ext_csd.rev >= 6) { card->ext_csd.feature_support |= MMC_DISCARD_FEATURE; card->ext_csd.generic_cmd6_time = 10 * ext_csd[EXT_CSD_GENERIC_CMD6_TIME]; card->ext_csd.power_off_longtime = 10 * ext_csd[EXT_CSD_POWER_OFF_LONG_TIME]; card->ext_csd.cache_size = ext_csd[EXT_CSD_CACHE_SIZE + 0] << 0 | ext_csd[EXT_CSD_CACHE_SIZE + 1] << 8 | ext_csd[EXT_CSD_CACHE_SIZE + 2] << 16 | ext_csd[EXT_CSD_CACHE_SIZE + 3] << 24; if (ext_csd[EXT_CSD_DATA_SECTOR_SIZE] == 1) card->ext_csd.data_sector_size = 4096; else card->ext_csd.data_sector_size = 512; if ((ext_csd[EXT_CSD_DATA_TAG_SUPPORT] & 1) && (ext_csd[EXT_CSD_TAG_UNIT_SIZE] <= 8)) { card->ext_csd.data_tag_unit_size = ((unsigned int) 1 << ext_csd[EXT_CSD_TAG_UNIT_SIZE]) * (card->ext_csd.data_sector_size); } else { card->ext_csd.data_tag_unit_size = 0; } } out: return err; }
/* * Decode extended CSD. */ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) { int err = 0, idx; unsigned int part_size; u8 hc_erase_grp_sz = 0, hc_wp_grp_sz = 0; BUG_ON(!card); if (!ext_csd) return 0; /* Version is coded in the CSD_STRUCTURE byte in the EXT_CSD register */ card->ext_csd.raw_ext_csd_structure = ext_csd[EXT_CSD_STRUCTURE]; if (card->csd.structure == 3) { if (card->ext_csd.raw_ext_csd_structure > 2) { pr_err("%s: unrecognised EXT_CSD structure " "version %d\n", mmc_hostname(card->host), card->ext_csd.raw_ext_csd_structure); err = -EINVAL; goto out; } } card->ext_csd.rev = ext_csd[EXT_CSD_REV]; if (card->ext_csd.rev > 7) { pr_err("%s: unrecognised EXT_CSD revision %d\n", mmc_hostname(card->host), card->ext_csd.rev); err = -EINVAL; goto out; } card->ext_csd.raw_sectors[0] = ext_csd[EXT_CSD_SEC_CNT + 0]; card->ext_csd.raw_sectors[1] = ext_csd[EXT_CSD_SEC_CNT + 1]; card->ext_csd.raw_sectors[2] = ext_csd[EXT_CSD_SEC_CNT + 2]; card->ext_csd.raw_sectors[3] = ext_csd[EXT_CSD_SEC_CNT + 3]; if (card->ext_csd.rev >= 2) { card->ext_csd.sectors = ext_csd[EXT_CSD_SEC_CNT + 0] << 0 | ext_csd[EXT_CSD_SEC_CNT + 1] << 8 | ext_csd[EXT_CSD_SEC_CNT + 2] << 16 | ext_csd[EXT_CSD_SEC_CNT + 3] << 24; /* Cards with density > 2GiB are sector addressed */ if (card->ext_csd.sectors > (2u * 1024 * 1024 * 1024) / 512) mmc_card_set_blockaddr(card); } card->ext_csd.raw_card_type = ext_csd[EXT_CSD_CARD_TYPE]; mmc_select_card_type(card); card->ext_csd.raw_s_a_timeout = ext_csd[EXT_CSD_S_A_TIMEOUT]; card->ext_csd.raw_erase_timeout_mult = ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT]; card->ext_csd.raw_hc_erase_grp_size = ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]; card->ext_csd.part_set_complete = ext_csd[EXT_CSD_PART_SET_COMPLETE]; if (card->ext_csd.rev >= 3) { u8 sa_shift = ext_csd[EXT_CSD_S_A_TIMEOUT]; card->ext_csd.part_config = ext_csd[EXT_CSD_PART_CONFIG]; /* EXT_CSD value is in units of 10ms, but we store in ms */ card->ext_csd.part_time = 10 * ext_csd[EXT_CSD_PART_SWITCH_TIME]; /* Sleep / awake timeout in 100ns units */ if (sa_shift > 0 && sa_shift <= 0x17) card->ext_csd.sa_timeout = 1 << ext_csd[EXT_CSD_S_A_TIMEOUT]; card->ext_csd.erase_group_def = ext_csd[EXT_CSD_ERASE_GROUP_DEF]; card->ext_csd.hc_erase_timeout = 300 * ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT]; card->ext_csd.hc_erase_size = ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] << 10; card->ext_csd.rel_sectors = ext_csd[EXT_CSD_REL_WR_SEC_C]; /* * There are two boot regions of equal size, defined in * multiples of 128K. */ if (ext_csd[EXT_CSD_BOOT_MULT] && mmc_boot_partition_access(card->host)) { for (idx = 0; idx < MMC_NUM_BOOT_PARTITION; idx++) { part_size = ext_csd[EXT_CSD_BOOT_MULT] << 17; mmc_part_add(card, part_size, EXT_CSD_PART_CONFIG_ACC_BOOT0 + idx, "boot%d", idx, true, MMC_BLK_DATA_AREA_BOOT); } } } card->ext_csd.raw_hc_erase_gap_size = ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; card->ext_csd.raw_sec_trim_mult = ext_csd[EXT_CSD_SEC_TRIM_MULT]; card->ext_csd.raw_sec_erase_mult = ext_csd[EXT_CSD_SEC_ERASE_MULT]; card->ext_csd.raw_sec_feature_support = ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT]; card->ext_csd.raw_trim_mult = ext_csd[EXT_CSD_TRIM_MULT]; card->ext_csd.raw_partition_support = ext_csd[EXT_CSD_PARTITION_SUPPORT]; 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)) { hc_erase_grp_sz = ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]; 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; } /* * General purpose partition feature support -- * If ext_csd has the size of general purpose partitions, * set size, part_cfg, partition name in mmc_part. */ if (ext_csd[EXT_CSD_PARTITION_SUPPORT] & EXT_CSD_PART_SUPPORT_PART_EN) { if (card->ext_csd.enhanced_area_en != 1) { hc_erase_grp_sz = ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]; hc_wp_grp_sz = ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; card->ext_csd.enhanced_area_en = 1; } for (idx = 0; idx < MMC_NUM_GP_PARTITION; idx++) { if (!ext_csd[EXT_CSD_GP_SIZE_MULT + idx * 3] && !ext_csd[EXT_CSD_GP_SIZE_MULT + idx * 3 + 1] && !ext_csd[EXT_CSD_GP_SIZE_MULT + idx * 3 + 2]) continue; part_size = (ext_csd[EXT_CSD_GP_SIZE_MULT + idx * 3 + 2] << 16) + (ext_csd[EXT_CSD_GP_SIZE_MULT + idx * 3 + 1] << 8) + ext_csd[EXT_CSD_GP_SIZE_MULT + idx * 3]; part_size *= (size_t)(hc_erase_grp_sz * hc_wp_grp_sz); card->ext_csd.gpp_sz[idx] = part_size << 10; mmc_part_add(card, part_size << 19, EXT_CSD_PART_CONFIG_ACC_GP0 + idx, "gp%d", idx, false, MMC_BLK_DATA_AREA_GP); } card->ext_csd.wpg_sz = (size_t)(hc_erase_grp_sz * hc_wp_grp_sz); } card->ext_csd.sec_trim_mult = ext_csd[EXT_CSD_SEC_TRIM_MULT]; card->ext_csd.sec_erase_mult = ext_csd[EXT_CSD_SEC_ERASE_MULT]; card->ext_csd.sec_feature_support = ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT]; card->ext_csd.trim_timeout = 300 * ext_csd[EXT_CSD_TRIM_MULT]; /* * Note that the call to mmc_part_add above defaults to read * only. If this default assumption is changed, the call must * take into account the value of boot_locked below. */ card->ext_csd.boot_ro_lock = ext_csd[EXT_CSD_BOOT_WP]; card->ext_csd.boot_ro_lockable = true; } if (card->ext_csd.rev >= 5) { /* check whether the eMMC card supports BKOPS */ if (ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1) { card->ext_csd.bkops = 1; card->ext_csd.bkops_en = ext_csd[EXT_CSD_BKOPS_EN]; card->ext_csd.raw_bkops_status = ext_csd[EXT_CSD_BKOPS_STATUS]; if (!card->ext_csd.bkops_en) pr_info("%s: BKOPS_EN bit is not set\n", mmc_hostname(card->host)); } /* check whether the eMMC card supports HPI */ if (ext_csd[EXT_CSD_HPI_FEATURES] & 0x1) { card->ext_csd.hpi = 1; if (ext_csd[EXT_CSD_HPI_FEATURES] & 0x2) card->ext_csd.hpi_cmd = MMC_STOP_TRANSMISSION; else card->ext_csd.hpi_cmd = MMC_SEND_STATUS; /* * Indicate the maximum timeout to close * a command interrupted by HPI */ card->ext_csd.out_of_int_time = ext_csd[EXT_CSD_OUT_OF_INTERRUPT_TIME] * 10; } card->ext_csd.rel_param = ext_csd[EXT_CSD_WR_REL_PARAM]; card->ext_csd.rst_n_function = ext_csd[EXT_CSD_RST_N_FUNCTION]; /* * RPMB regions are defined in multiples of 128K. */ card->ext_csd.raw_rpmb_size_mult = ext_csd[EXT_CSD_RPMB_MULT]; card->ext_csd.rpmb_size = 128 * card->ext_csd.raw_rpmb_size_mult; card->ext_csd.rpmb_size <<= 2; /* Unit: half sector */ if (ext_csd[EXT_CSD_RPMB_MULT] && mmc_host_cmd23(card->host) && mmc_rpmb_partition_access(card->host)) { mmc_part_add(card, ext_csd[EXT_CSD_RPMB_MULT] << 17, EXT_CSD_PART_CONFIG_ACC_RPMB, "rpmb", 0, false, MMC_BLK_DATA_AREA_RPMB); } } card->ext_csd.raw_erased_mem_count = ext_csd[EXT_CSD_ERASED_MEM_CONT]; if (ext_csd[EXT_CSD_ERASED_MEM_CONT]) card->erased_byte = 0xFF; else card->erased_byte = 0x0; /* eMMC v4.5 or later */ if (card->ext_csd.rev >= 6) { card->ext_csd.feature_support |= MMC_DISCARD_FEATURE; card->ext_csd.generic_cmd6_time = 10 * ext_csd[EXT_CSD_GENERIC_CMD6_TIME]; card->ext_csd.power_off_longtime = 10 * ext_csd[EXT_CSD_POWER_OFF_LONG_TIME]; card->ext_csd.cache_size = ext_csd[EXT_CSD_CACHE_SIZE + 0] << 0 | ext_csd[EXT_CSD_CACHE_SIZE + 1] << 8 | ext_csd[EXT_CSD_CACHE_SIZE + 2] << 16 | ext_csd[EXT_CSD_CACHE_SIZE + 3] << 24; if (ext_csd[EXT_CSD_DATA_SECTOR_SIZE] == 1) card->ext_csd.data_sector_size = 4096; else card->ext_csd.data_sector_size = 512; if ((ext_csd[EXT_CSD_DATA_TAG_SUPPORT] & 1) && (ext_csd[EXT_CSD_TAG_UNIT_SIZE] <= 8)) { card->ext_csd.data_tag_unit_size = ((unsigned int) 1 << ext_csd[EXT_CSD_TAG_UNIT_SIZE]) * (card->ext_csd.data_sector_size); } else { card->ext_csd.data_tag_unit_size = 0; } card->ext_csd.max_packed_writes = ext_csd[EXT_CSD_MAX_PACKED_WRITES]; card->ext_csd.max_packed_reads = ext_csd[EXT_CSD_MAX_PACKED_READS]; } else { card->ext_csd.data_sector_size = 512; } /* * If use legacy relaible write, then the blk counts must not * big than the relaible write sectors */ if (!(card->ext_csd.rel_param & EXT_CSD_WR_REL_PARAM_EN)) { if (card->ext_csd.rel_sectors < RPMB_AVALIABLE_SECTORS) card->rpmb_max_req = card->ext_csd.rel_sectors; else card->rpmb_max_req = RPMB_AVALIABLE_SECTORS; } else card->rpmb_max_req = RPMB_AVALIABLE_SECTORS; out: return err; }
static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) { int err = 0, idx; unsigned int part_size; u8 hc_erase_grp_sz = 0, hc_wp_grp_sz = 0; BUG_ON(!card); if (!ext_csd) return 0; card->ext_csd.raw_ext_csd_structure = ext_csd[EXT_CSD_STRUCTURE]; if (card->csd.structure == 3) { if (card->ext_csd.raw_ext_csd_structure > 2) { pr_err("%s: unrecognised EXT_CSD structure " "version %d\n", mmc_hostname(card->host), card->ext_csd.raw_ext_csd_structure); err = -EINVAL; goto out; } } card->ext_csd.rev = ext_csd[EXT_CSD_REV]; if (card->ext_csd.rev > 6) { printk(KERN_ERR "%s: unrecognised EXT_CSD revision %d\n", mmc_hostname(card->host), card->ext_csd.rev); err = -EINVAL; goto out; } card->ext_csd.raw_sectors[0] = ext_csd[EXT_CSD_SEC_CNT + 0]; card->ext_csd.raw_sectors[1] = ext_csd[EXT_CSD_SEC_CNT + 1]; card->ext_csd.raw_sectors[2] = ext_csd[EXT_CSD_SEC_CNT + 2]; card->ext_csd.raw_sectors[3] = ext_csd[EXT_CSD_SEC_CNT + 3]; if (card->ext_csd.rev >= 2) { card->ext_csd.sectors = ext_csd[EXT_CSD_SEC_CNT + 0] << 0 | ext_csd[EXT_CSD_SEC_CNT + 1] << 8 | ext_csd[EXT_CSD_SEC_CNT + 2] << 16 | ext_csd[EXT_CSD_SEC_CNT + 3] << 24; if (card->ext_csd.sectors > (2u * 1024 * 1024 * 1024) / 512) mmc_card_set_blockaddr(card); } card->ext_csd.raw_card_type = ext_csd[EXT_CSD_CARD_TYPE]; mmc_select_card_type(card); card->ext_csd.raw_s_a_timeout = ext_csd[EXT_CSD_S_A_TIMEOUT]; card->ext_csd.raw_erase_timeout_mult = ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT]; card->ext_csd.raw_hc_erase_grp_size = ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]; if (card->ext_csd.rev >= 3) { u8 sa_shift = ext_csd[EXT_CSD_S_A_TIMEOUT]; card->ext_csd.part_config = ext_csd[EXT_CSD_PART_CONFIG]; card->ext_csd.part_time = 10 * ext_csd[EXT_CSD_PART_SWITCH_TIME]; if (sa_shift > 0 && sa_shift <= 0x17) card->ext_csd.sa_timeout = 1 << ext_csd[EXT_CSD_S_A_TIMEOUT]; card->ext_csd.erase_group_def = ext_csd[EXT_CSD_ERASE_GROUP_DEF]; card->ext_csd.hc_erase_timeout = 300 * ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT]; card->ext_csd.hc_erase_size = ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] << 10; card->ext_csd.rel_sectors = ext_csd[EXT_CSD_REL_WR_SEC_C]; if (ext_csd[EXT_CSD_BOOT_MULT] && mmc_boot_partition_access(card->host)) { for (idx = 0; idx < MMC_NUM_BOOT_PARTITION; idx++) { part_size = ext_csd[EXT_CSD_BOOT_MULT] << 17; mmc_part_add(card, part_size, EXT_CSD_PART_CONFIG_ACC_BOOT0 + idx, "boot%d", idx, true, MMC_BLK_DATA_AREA_BOOT); } } } card->ext_csd.raw_hc_erase_gap_size = ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; card->ext_csd.raw_sec_trim_mult = ext_csd[EXT_CSD_SEC_TRIM_MULT]; card->ext_csd.raw_sec_erase_mult = ext_csd[EXT_CSD_SEC_ERASE_MULT]; card->ext_csd.raw_sec_feature_support = ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT]; card->ext_csd.raw_trim_mult = ext_csd[EXT_CSD_TRIM_MULT]; if (card->ext_csd.rev >= 4) { card->ext_csd.raw_partition_support = ext_csd[EXT_CSD_PARTITION_SUPPORT]; if ((ext_csd[EXT_CSD_PARTITION_SUPPORT] & 0x2) && (ext_csd[EXT_CSD_PARTITION_ATTRIBUTE] & 0x1)) { hc_erase_grp_sz = ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]; hc_wp_grp_sz = ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; card->ext_csd.enhanced_area_en = 1; 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; 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 { card->ext_csd.enhanced_area_offset = -EINVAL; card->ext_csd.enhanced_area_size = -EINVAL; } if (ext_csd[EXT_CSD_PARTITION_SUPPORT] & EXT_CSD_PART_SUPPORT_PART_EN) { if (card->ext_csd.enhanced_area_en != 1) { hc_erase_grp_sz = ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]; hc_wp_grp_sz = ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; card->ext_csd.enhanced_area_en = 1; } for (idx = 0; idx < MMC_NUM_GP_PARTITION; idx++) { if (!ext_csd[EXT_CSD_GP_SIZE_MULT + idx * 3] && !ext_csd[EXT_CSD_GP_SIZE_MULT + idx * 3 + 1] && !ext_csd[EXT_CSD_GP_SIZE_MULT + idx * 3 + 2]) continue; part_size = (ext_csd[EXT_CSD_GP_SIZE_MULT + idx * 3 + 2] << 16) + (ext_csd[EXT_CSD_GP_SIZE_MULT + idx * 3 + 1] << 8) + ext_csd[EXT_CSD_GP_SIZE_MULT + idx * 3]; part_size *= (size_t)(hc_erase_grp_sz * hc_wp_grp_sz); mmc_part_add(card, part_size << 19, EXT_CSD_PART_CONFIG_ACC_GP0 + idx, "gp%d", idx, false, MMC_BLK_DATA_AREA_GP); } } card->ext_csd.sec_trim_mult = ext_csd[EXT_CSD_SEC_TRIM_MULT]; card->ext_csd.sec_erase_mult = ext_csd[EXT_CSD_SEC_ERASE_MULT]; card->ext_csd.sec_feature_support = ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT]; card->ext_csd.trim_timeout = 300 * ext_csd[EXT_CSD_TRIM_MULT]; card->ext_csd.boot_ro_lock = ext_csd[EXT_CSD_BOOT_WP]; card->ext_csd.boot_ro_lockable = true; } if (card->ext_csd.rev >= 5) { if (ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1) { card->ext_csd.bkops = 1; card->ext_csd.bkops_en = ext_csd[EXT_CSD_BKOPS_EN]; pr_info("[HTC_KER_ADD]%s: ext_csd[EXT_CSD_BKOPS_EN] = %d\n", mmc_hostname(card->host), ext_csd[EXT_CSD_BKOPS_EN]); card->ext_csd.raw_bkops_status = ext_csd[EXT_CSD_BKOPS_STATUS]; if (!card->ext_csd.bkops_en && card->host->caps2 & MMC_CAP2_INIT_BKOPS) { err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BKOPS_EN, 1, 0); if (err) pr_warning("%s: Enabling BKOPS failed\n", mmc_hostname(card->host)); else { card->ext_csd.bkops_en = 1; pr_info("[HTC_KER_ADD]%s: Enabled BKOPs\n", mmc_hostname(card->host)); } } } if (ext_csd[EXT_CSD_HPI_FEATURES] & 0x1) { card->ext_csd.hpi = 1; if (ext_csd[EXT_CSD_HPI_FEATURES] & 0x2) card->ext_csd.hpi_cmd = MMC_STOP_TRANSMISSION; else card->ext_csd.hpi_cmd = MMC_SEND_STATUS; card->ext_csd.out_of_int_time = ext_csd[EXT_CSD_OUT_OF_INTERRUPT_TIME] * 10; } card->ext_csd.rel_param = ext_csd[EXT_CSD_WR_REL_PARAM]; card->ext_csd.rst_n_function = ext_csd[EXT_CSD_RST_N_FUNCTION]; } card->ext_csd.raw_erased_mem_count = ext_csd[EXT_CSD_ERASED_MEM_CONT]; if (ext_csd[EXT_CSD_ERASED_MEM_CONT]) card->erased_byte = 0xFF; else card->erased_byte = 0x0; if (card->ext_csd.rev >= 6) { card->ext_csd.feature_support |= MMC_DISCARD_FEATURE; card->ext_csd.generic_cmd6_time = 10 * ext_csd[EXT_CSD_GENERIC_CMD6_TIME]; card->ext_csd.power_off_longtime = 10 * ext_csd[EXT_CSD_POWER_OFF_LONG_TIME]; card->ext_csd.cache_size = ext_csd[EXT_CSD_CACHE_SIZE + 0] << 0 | ext_csd[EXT_CSD_CACHE_SIZE + 1] << 8 | ext_csd[EXT_CSD_CACHE_SIZE + 2] << 16 | ext_csd[EXT_CSD_CACHE_SIZE + 3] << 24; if (ext_csd[EXT_CSD_DATA_SECTOR_SIZE] == 1) card->ext_csd.data_sector_size = 4096; else card->ext_csd.data_sector_size = 512; if ((ext_csd[EXT_CSD_DATA_TAG_SUPPORT] & 1) && (ext_csd[EXT_CSD_TAG_UNIT_SIZE] <= 8)) { card->ext_csd.data_tag_unit_size = ((unsigned int) 1 << ext_csd[EXT_CSD_TAG_UNIT_SIZE]) * (card->ext_csd.data_sector_size); } else { card->ext_csd.data_tag_unit_size = 0; } card->ext_csd.max_packed_writes = ext_csd[EXT_CSD_MAX_PACKED_WRITES]; card->ext_csd.max_packed_reads = ext_csd[EXT_CSD_MAX_PACKED_READS]; } if (card->cid.manfid == SANDISK_MMC) { char buf[7] = {0}; sprintf(buf, "%c%c%c%c%c%c", ext_csd[73], ext_csd[74], ext_csd[75], ext_csd[76], ext_csd[77], ext_csd[78]); strncpy(card->ext_csd.fwrev, buf, strlen(buf)); } if (mmc_card_mmc(card)) { char *buf; int i, j; ssize_t n = 0; pr_info("%s: cid %08x%08x%08x%08x\n", mmc_hostname(card->host), card->raw_cid[0], card->raw_cid[1], card->raw_cid[2], card->raw_cid[3]); pr_info("%s: csd %08x%08x%08x%08x\n", mmc_hostname(card->host), card->raw_csd[0], card->raw_csd[1], card->raw_csd[2], card->raw_csd[3]); buf = kmalloc(512, GFP_KERNEL); if (buf) { for (i = 0; i < 32; i++) { for (j = 511 - (16 * i); j >= 496 - (16 * i); j--) n += sprintf(buf + n, "%02x", ext_csd[j]); n += sprintf(buf + n, "\n"); pr_info("%s: ext_csd %s", mmc_hostname(card->host), buf); n = 0; } } if (buf) kfree(buf); } out: return err; }