Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux...
[pandora-kernel.git] / drivers / mmc / core / mmc.c
index 5700b1c..dbf421a 100644 (file)
@@ -12,6 +12,7 @@
 
 #include <linux/err.h>
 #include <linux/slab.h>
+#include <linux/stat.h>
 
 #include <linux/mmc/host.h>
 #include <linux/mmc/card.h>
@@ -101,7 +102,7 @@ static int mmc_decode_cid(struct mmc_card *card)
                break;
 
        default:
-               printk(KERN_ERR "%s: card has unknown MMCA version %d\n",
+               pr_err("%s: card has unknown MMCA version %d\n",
                        mmc_hostname(card->host), card->csd.mmca_vsn);
                return -EINVAL;
        }
@@ -135,7 +136,7 @@ static int mmc_decode_csd(struct mmc_card *card)
         */
        csd->structure = UNSTUFF_BITS(resp, 126, 2);
        if (csd->structure == 0) {
-               printk(KERN_ERR "%s: unrecognised CSD structure version %d\n",
+               pr_err("%s: unrecognised CSD structure version %d\n",
                        mmc_hostname(card->host), csd->structure);
                return -EINVAL;
        }
@@ -195,7 +196,7 @@ static int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd)
         */
        ext_csd = kmalloc(512, GFP_KERNEL);
        if (!ext_csd) {
-               printk(KERN_ERR "%s: could not allocate a buffer to "
+               pr_err("%s: could not allocate a buffer to "
                        "receive the ext_csd.\n", mmc_hostname(card->host));
                return -ENOMEM;
        }
@@ -217,12 +218,12 @@ static int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd)
                 * stored in their CSD.
                 */
                if (card->csd.capacity == (4096 * 512)) {
-                       printk(KERN_ERR "%s: unable to read EXT_CSD "
+                       pr_err("%s: unable to read EXT_CSD "
                                "on a possible high capacity card. "
                                "Card will be ignored.\n",
                                mmc_hostname(card->host));
                } else {
-                       printk(KERN_WARNING "%s: unable to read "
+                       pr_warning("%s: unable to read "
                                "EXT_CSD, performance might "
                                "suffer.\n",
                                mmc_hostname(card->host));
@@ -239,7 +240,9 @@ static int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd)
  */
 static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
 {
-       int err = 0;
+       int err = 0, idx;
+       unsigned int part_size;
+       u8 hc_erase_grp_sz = 0, hc_wp_grp_sz = 0;
 
        BUG_ON(!card);
 
@@ -250,7 +253,7 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
        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) {
-                       printk(KERN_ERR "%s: unrecognised EXT_CSD structure "
+                       pr_err("%s: unrecognised EXT_CSD structure "
                                "version %d\n", mmc_hostname(card->host),
                                        card->ext_csd.raw_ext_csd_structure);
                        err = -EINVAL;
@@ -260,7 +263,7 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
 
        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",
+               pr_err("%s: unrecognised EXT_CSD revision %d\n",
                        mmc_hostname(card->host), card->ext_csd.rev);
                err = -EINVAL;
                goto out;
@@ -306,7 +309,7 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
                break;
        default:
                /* MMC v4 spec says this cannot happen */
-               printk(KERN_WARNING "%s: card is mmc v4 but doesn't "
+               pr_warning("%s: card is mmc v4 but doesn't "
                        "support any high-speed modes.\n",
                        mmc_hostname(card->host));
        }
@@ -340,7 +343,14 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
                 * There are two boot regions of equal size, defined in
                 * multiples of 128K.
                 */
-               card->ext_csd.boot_size = ext_csd[EXT_CSD_BOOT_MULT] << 17;
+               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);
+                       }
+               }
        }
 
        card->ext_csd.raw_hc_erase_gap_size =
@@ -359,11 +369,12 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
                 * 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)) {
-                       u8 hc_erase_grp_sz =
+                       hc_erase_grp_sz =
                                ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
-                       u8 hc_wp_grp_sz =
+                       hc_wp_grp_sz =
                                ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
 
                        card->ext_csd.enhanced_area_en = 1;
@@ -392,6 +403,41 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
                        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);
+                       }
+               }
                card->ext_csd.sec_trim_mult =
                        ext_csd[EXT_CSD_SEC_TRIM_MULT];
                card->ext_csd.sec_erase_mult =
@@ -402,14 +448,48 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
                        ext_csd[EXT_CSD_TRIM_MULT];
        }
 
-       if (card->ext_csd.rev >= 5)
+       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;
 
+       /* 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;
+       }
+
 out:
        return err;
 }
@@ -529,6 +609,86 @@ static struct device_type mmc_type = {
        .groups = mmc_attr_groups,
 };
 
+/*
+ * Select the PowerClass for the current bus width
+ * If power class is defined for 4/8 bit bus in the
+ * extended CSD register, select it by executing the
+ * mmc_switch command.
+ */
+static int mmc_select_powerclass(struct mmc_card *card,
+               unsigned int bus_width, u8 *ext_csd)
+{
+       int err = 0;
+       unsigned int pwrclass_val;
+       unsigned int index = 0;
+       struct mmc_host *host;
+
+       BUG_ON(!card);
+
+       host = card->host;
+       BUG_ON(!host);
+
+       if (ext_csd == NULL)
+               return 0;
+
+       /* Power class selection is supported for versions >= 4.0 */
+       if (card->csd.mmca_vsn < CSD_SPEC_VER_4)
+               return 0;
+
+       /* Power class values are defined only for 4/8 bit bus */
+       if (bus_width == EXT_CSD_BUS_WIDTH_1)
+               return 0;
+
+       switch (1 << host->ios.vdd) {
+       case MMC_VDD_165_195:
+               if (host->ios.clock <= 26000000)
+                       index = EXT_CSD_PWR_CL_26_195;
+               else if (host->ios.clock <= 52000000)
+                       index = (bus_width <= EXT_CSD_BUS_WIDTH_8) ?
+                               EXT_CSD_PWR_CL_52_195 :
+                               EXT_CSD_PWR_CL_DDR_52_195;
+               else if (host->ios.clock <= 200000000)
+                       index = EXT_CSD_PWR_CL_200_195;
+               break;
+       case MMC_VDD_32_33:
+       case MMC_VDD_33_34:
+       case MMC_VDD_34_35:
+       case MMC_VDD_35_36:
+               if (host->ios.clock <= 26000000)
+                       index = EXT_CSD_PWR_CL_26_360;
+               else if (host->ios.clock <= 52000000)
+                       index = (bus_width <= EXT_CSD_BUS_WIDTH_8) ?
+                               EXT_CSD_PWR_CL_52_360 :
+                               EXT_CSD_PWR_CL_DDR_52_360;
+               else if (host->ios.clock <= 200000000)
+                       index = EXT_CSD_PWR_CL_200_360;
+               break;
+       default:
+               pr_warning("%s: Voltage range not supported "
+                          "for power class.\n", mmc_hostname(host));
+               return -EINVAL;
+       }
+
+       pwrclass_val = ext_csd[index];
+
+       if (bus_width & (EXT_CSD_BUS_WIDTH_8 | EXT_CSD_DDR_BUS_WIDTH_8))
+               pwrclass_val = (pwrclass_val & EXT_CSD_PWR_CL_8BIT_MASK) >>
+                               EXT_CSD_PWR_CL_8BIT_SHIFT;
+       else
+               pwrclass_val = (pwrclass_val & EXT_CSD_PWR_CL_4BIT_MASK) >>
+                               EXT_CSD_PWR_CL_4BIT_SHIFT;
+
+       /* If the power class is different from the default value */
+       if (pwrclass_val > 0) {
+               err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+                                EXT_CSD_POWER_CLASS,
+                                pwrclass_val,
+                                card->ext_csd.generic_cmd6_time);
+       }
+
+       return err;
+}
+
 /*
  * Handle the detection and initialisation of a card.
  *
@@ -548,11 +708,16 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
        BUG_ON(!host);
        WARN_ON(!host->claimed);
 
+       /* Set correct bus mode for MMC before attempting init */
+       if (!mmc_host_is_spi(host))
+               mmc_set_bus_mode(host, MMC_BUSMODE_OPENDRAIN);
+
        /*
         * Since we're changing the OCR value, we seem to
         * need to tell some cards to go back to the idle
         * state.  We wait 1ms to give cards time to
         * respond.
+        * mmc_go_idle is needed for eMMC that are asleep
         */
        mmc_go_idle(host);
 
@@ -668,7 +833,8 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
         */
        if (card->ext_csd.enhanced_area_en) {
                err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-                                EXT_CSD_ERASE_GROUP_DEF, 1, 0);
+                                EXT_CSD_ERASE_GROUP_DEF, 1,
+                                card->ext_csd.generic_cmd6_time);
 
                if (err && err != -EBADMSG)
                        goto free_card;
@@ -705,18 +871,36 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
                        goto free_card;
        }
 
+       /*
+        * If the host supports the power_off_notify capability then
+        * set the notification byte in the ext_csd register of device
+        */
+       if ((host->caps2 & MMC_CAP2_POWEROFF_NOTIFY) &&
+           (card->poweroff_notify_state == MMC_NO_POWER_NOTIFICATION)) {
+               err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+                                EXT_CSD_POWER_OFF_NOTIFICATION,
+                                EXT_CSD_POWER_ON,
+                                card->ext_csd.generic_cmd6_time);
+               if (err && err != -EBADMSG)
+                       goto free_card;
+       }
+
+       if (!err)
+               card->poweroff_notify_state = MMC_POWERED_ON;
+
        /*
         * Activate high speed (if supported)
         */
        if ((card->ext_csd.hs_max_dtr != 0) &&
                (host->caps & MMC_CAP_MMC_HIGHSPEED)) {
                err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-                                EXT_CSD_HS_TIMING, 1, 0);
+                                EXT_CSD_HS_TIMING, 1,
+                                card->ext_csd.generic_cmd6_time);
                if (err && err != -EBADMSG)
                        goto free_card;
 
                if (err) {
-                       printk(KERN_WARNING "%s: switch to highspeed failed\n",
+                       pr_warning("%s: switch to highspeed failed\n",
                               mmc_hostname(card->host));
                        err = 0;
                } else {
@@ -725,6 +909,22 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
                }
        }
 
+       /*
+        * Enable HPI feature (if supported)
+        */
+       if (card->ext_csd.hpi) {
+               err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+                       EXT_CSD_HPI_MGMT, 1, 0);
+               if (err && err != -EBADMSG)
+                       goto free_card;
+               if (err) {
+                       pr_warning("%s: Enabling HPI failed\n",
+                                  mmc_hostname(card->host));
+                       err = 0;
+               } else
+                       card->ext_csd.hpi_en = 1;
+       }
+
        /*
         * Compute bus speed.
         */
@@ -780,10 +980,18 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
                        bus_width = bus_widths[idx];
                        if (bus_width == MMC_BUS_WIDTH_1)
                                ddr = 0; /* no DDR for 1-bit width */
+                       err = mmc_select_powerclass(card, ext_csd_bits[idx][0],
+                                                   ext_csd);
+                       if (err)
+                               pr_err("%s: power class selection to "
+                                      "bus width %d failed\n",
+                                      mmc_hostname(card->host),
+                                      1 << bus_width);
+
                        err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
                                         EXT_CSD_BUS_WIDTH,
                                         ext_csd_bits[idx][0],
-                                        0);
+                                        card->ext_csd.generic_cmd6_time);
                        if (!err) {
                                mmc_set_bus_width(card->host, bus_width);
 
@@ -803,13 +1011,21 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
                }
 
                if (!err && ddr) {
+                       err = mmc_select_powerclass(card, ext_csd_bits[idx][1],
+                                                   ext_csd);
+                       if (err)
+                               pr_err("%s: power class selection to "
+                                      "bus width %d ddr %d failed\n",
+                                      mmc_hostname(card->host),
+                                      1 << bus_width, ddr);
+
                        err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
                                         EXT_CSD_BUS_WIDTH,
                                         ext_csd_bits[idx][1],
-                                        0);
+                                        card->ext_csd.generic_cmd6_time);
                }
                if (err) {
-                       printk(KERN_WARNING "%s: switch to bus width %d ddr %d "
+                       pr_warning("%s: switch to bus width %d ddr %d "
                                "failed\n", mmc_hostname(card->host),
                                1 << bus_width, ddr);
                        goto free_card;
@@ -840,6 +1056,23 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
                }
        }
 
+       /*
+        * If cache size is higher than 0, this indicates
+        * the existence of cache and it can be turned on.
+        */
+       if ((host->caps2 & MMC_CAP2_CACHE_CTRL) &&
+                       card->ext_csd.cache_size > 0) {
+               err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+                               EXT_CSD_CACHE_CTRL, 1, 0);
+               if (err && err != -EBADMSG)
+                       goto free_card;
+
+               /*
+                * Only if no error, cache is turned on successfully.
+                */
+               card->ext_csd.cache_ctrl = err ? 0 : 1;
+       }
+
        if (!oldcard)
                host->card = card;
 
@@ -891,6 +1124,7 @@ static void mmc_detect(struct mmc_host *host)
 
                mmc_claim_host(host);
                mmc_detach_bus(host);
+               mmc_power_off(host);
                mmc_release_host(host);
        }
 }
@@ -900,16 +1134,20 @@ static void mmc_detect(struct mmc_host *host)
  */
 static int mmc_suspend(struct mmc_host *host)
 {
+       int err = 0;
+
        BUG_ON(!host);
        BUG_ON(!host->card);
 
        mmc_claim_host(host);
-       if (!mmc_host_is_spi(host))
+       if (mmc_card_can_sleep(host))
+               err = mmc_card_sleep(host);
+       else if (!mmc_host_is_spi(host))
                mmc_deselect_cards(host);
        host->card->state &= ~MMC_STATE_HIGHSPEED;
        mmc_release_host(host);
 
-       return 0;
+       return err;
 }
 
 /*
@@ -1016,6 +1254,10 @@ int mmc_attach_mmc(struct mmc_host *host)
        BUG_ON(!host);
        WARN_ON(!host->claimed);
 
+       /* Set correct bus mode for MMC before attempting attach */
+       if (!mmc_host_is_spi(host))
+               mmc_set_bus_mode(host, MMC_BUSMODE_OPENDRAIN);
+
        err = mmc_send_op_cond(host, 0, &ocr);
        if (err)
                return err;
@@ -1038,7 +1280,7 @@ int mmc_attach_mmc(struct mmc_host *host)
         * support.
         */
        if (ocr & 0x7F) {
-               printk(KERN_WARNING "%s: card claims to support voltages "
+               pr_warning("%s: card claims to support voltages "
                       "below the defined range. These will be ignored.\n",
                       mmc_hostname(host));
                ocr &= ~0x7F;
@@ -1077,7 +1319,7 @@ remove_card:
 err:
        mmc_detach_bus(host);
 
-       printk(KERN_ERR "%s: error %d whilst initialising MMC card\n",
+       pr_err("%s: error %d whilst initialising MMC card\n",
                mmc_hostname(host), err);
 
        return err;