Merge branches 'x86-fixes-for-linus', 'sched-fixes-for-linus', 'timers-fixes-for...
[pandora-kernel.git] / drivers / mmc / core / mmc.c
index 16006ef..772d0d0 100644 (file)
@@ -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,
 };
 
@@ -378,6 +421,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
        int err, ddr = 0;
        u32 cid[4];
        unsigned int max_dtr;
+       u32 rocr;
 
        BUG_ON(!host);
        WARN_ON(!host->claimed);
@@ -391,7 +435,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
        mmc_go_idle(host);
 
        /* The extra bit indicates that we support high capacity */
-       err = mmc_send_op_cond(host, ocr | (1 << 30), NULL);
+       err = mmc_send_op_cond(host, ocr | (1 << 30), &rocr);
        if (err)
                goto err;
 
@@ -479,10 +523,50 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
                err = mmc_read_ext_csd(card);
                if (err)
                        goto free_card;
+
+               /* If doing byte addressing, check if required to do sector
+                * addressing.  Handle the case of <2GB cards needing sector
+                * addressing.  See section 8.1 JEDEC Standard JED84-A441;
+                * ocr register has bit 30 set for sector addressing.
+                */
+               if (!(mmc_card_blockaddr(card)) && (rocr & (1<<30)))
+                       mmc_card_set_blockaddr(card);
+
                /* Erase size depends on CSD and Extended CSD */
                mmc_set_erase_size(card);
        }
 
+       /*
+        * If enhanced_area_en is TRUE, host needs to enable ERASE_GRP_DEF
+        * bit.  This bit will be lost every time 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)
         */