mmc: add a reinit() API
[platform/kernel/u-boot.git] / drivers / mmc / mmc.c
index 3e36566..0727505 100644 (file)
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0+
 /*
  * Copyright 2008, Freescale Semiconductor, Inc
+ * Copyright 2020 NXP
  * Andy Fleming
  *
  * Based vaguely on the Linux code
@@ -8,12 +9,16 @@
 
 #include <config.h>
 #include <common.h>
+#include <blk.h>
 #include <command.h>
 #include <dm.h>
+#include <log.h>
 #include <dm/device-internal.h>
 #include <errno.h>
 #include <mmc.h>
 #include <part.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
 #include <power/regulator.h>
 #include <malloc.h>
 #include <memalign.h>
@@ -409,6 +414,16 @@ static int mmc_read_blocks(struct mmc *mmc, void *dst, lbaint_t start,
        return blkcnt;
 }
 
+#if !CONFIG_IS_ENABLED(DM_MMC)
+static int mmc_get_b_max(struct mmc *mmc, void *dst, lbaint_t blkcnt)
+{
+       if (mmc->cfg->ops->get_b_max)
+               return mmc->cfg->ops->get_b_max(mmc, dst, blkcnt);
+       else
+               return mmc->cfg->b_max;
+}
+#endif
+
 #if CONFIG_IS_ENABLED(BLK)
 ulong mmc_bread(struct udevice *dev, lbaint_t start, lbaint_t blkcnt, void *dst)
 #else
@@ -422,6 +437,7 @@ ulong mmc_bread(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt,
        int dev_num = block_dev->devnum;
        int err;
        lbaint_t cur, blocks_todo = blkcnt;
+       uint b_max;
 
        if (blkcnt == 0)
                return 0;
@@ -451,9 +467,10 @@ ulong mmc_bread(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt,
                return 0;
        }
 
+       b_max = mmc_get_b_max(mmc, dst, blkcnt);
+
        do {
-               cur = (blocks_todo > mmc->cfg->b_max) ?
-                       mmc->cfg->b_max : blocks_todo;
+               cur = (blocks_todo > b_max) ? b_max : blocks_todo;
                if (mmc_read_blocks(mmc, dst, start, cur) != cur) {
                        pr_debug("%s: Failed to read blocks\n", __func__);
                        return 0;
@@ -653,12 +670,15 @@ static int mmc_send_op_cond_iter(struct mmc *mmc, int use_arg)
 static int mmc_send_op_cond(struct mmc *mmc)
 {
        int err, i;
+       int timeout = 1000;
+       uint start;
 
        /* Some cards seem to need this */
        mmc_go_idle(mmc);
 
+       start = get_timer(0);
        /* Asking to the card its capabilities */
-       for (i = 0; i < 2; i++) {
+       for (i = 0; ; i++) {
                err = mmc_send_op_cond_iter(mmc, i != 0);
                if (err)
                        return err;
@@ -666,6 +686,10 @@ static int mmc_send_op_cond(struct mmc *mmc)
                /* exit if not busy (flag seems to be inverted) */
                if (mmc->ocr & OCR_BUSY)
                        break;
+
+               if (get_timer(start) > timeout)
+                       return -ETIMEDOUT;
+               udelay(100);
        }
        mmc->op_cond_pending = 1;
        return 0;
@@ -718,7 +742,7 @@ static int mmc_complete_op_cond(struct mmc *mmc)
 }
 
 
-static int mmc_send_ext_csd(struct mmc *mmc, u8 *ext_csd)
+int mmc_send_ext_csd(struct mmc *mmc, u8 *ext_csd)
 {
        struct mmc_cmd cmd;
        struct mmc_data data;
@@ -810,6 +834,11 @@ int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value)
        return __mmc_switch(mmc, set, index, value, true);
 }
 
+int mmc_boot_wp(struct mmc *mmc)
+{
+       return mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BOOT_WP, 1);
+}
+
 #if !CONFIG_IS_ENABLED(MMC_TINY)
 static int mmc_set_card_speed(struct mmc *mmc, enum bus_mode mode,
                              bool hsdowngrade)
@@ -1725,6 +1754,11 @@ static int sd_select_mode_and_width(struct mmc *mmc, uint card_caps)
                mmc_set_bus_width(mmc, 1);
                mmc_select_mode(mmc, MMC_LEGACY);
                mmc_set_clock(mmc, mmc->tran_speed, MMC_CLK_ENABLE);
+#if CONFIG_IS_ENABLED(MMC_WRITE)
+               err = sd_read_ssr(mmc);
+               if (err)
+                       pr_warn("unable to read ssr\n");
+#endif
                return 0;
        }
 
@@ -2756,9 +2790,6 @@ int mmc_get_op_cond(struct mmc *mmc)
        if (mmc->has_init)
                return 0;
 
-#ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT
-       mmc_adapter_card_type_ident();
-#endif
        err = mmc_power_init(mmc);
        if (err)
                return err;
@@ -2785,13 +2816,17 @@ int mmc_get_op_cond(struct mmc *mmc)
                return err;
 
 #if CONFIG_IS_ENABLED(DM_MMC)
-       /* The device has already been probed ready for use */
+       /*
+        * Re-initialization is needed to clear old configuration for
+        * mmc rescan.
+        */
+       err = mmc_reinit(mmc);
 #else
        /* made sure it's not NULL earlier */
        err = mmc->cfg->ops->init(mmc);
+#endif
        if (err)
                return err;
-#endif
        mmc->ddr_mode = 0;
 
 retry:
@@ -2803,7 +2838,7 @@ retry:
        if (err)
                return err;
 
-       /* The internal partition reset to user partition(0) at every CMD0*/
+       /* The internal partition reset to user partition(0) at every CMD0 */
        mmc_get_blk_desc(mmc)->hwpart = 0;
 
        /* Test for SD version 2 */
@@ -2946,13 +2981,13 @@ int mmc_set_dsr(struct mmc *mmc, u16 val)
 }
 
 /* CPU-specific MMC initializations */
-__weak int cpu_mmc_init(bd_t *bis)
+__weak int cpu_mmc_init(struct bd_info *bis)
 {
        return -1;
 }
 
 /* board-specific MMC initializations. */
-__weak int board_mmc_init(bd_t *bis)
+__weak int board_mmc_init(struct bd_info *bis)
 {
        return -1;
 }
@@ -2963,7 +2998,7 @@ void mmc_set_preinit(struct mmc *mmc, int preinit)
 }
 
 #if CONFIG_IS_ENABLED(DM_MMC)
-static int mmc_probe(bd_t *bis)
+static int mmc_probe(struct bd_info *bis)
 {
        int ret, i;
        struct uclass *uc;
@@ -2992,7 +3027,7 @@ static int mmc_probe(bd_t *bis)
        return 0;
 }
 #else
-static int mmc_probe(bd_t *bis)
+static int mmc_probe(struct bd_info *bis)
 {
        if (board_mmc_init(bis) < 0)
                cpu_mmc_init(bis);
@@ -3001,7 +3036,7 @@ static int mmc_probe(bd_t *bis)
 }
 #endif
 
-int mmc_initialize(bd_t *bis)
+int mmc_initialize(struct bd_info *bis)
 {
        static int initialized = 0;
        int ret;
@@ -3040,9 +3075,6 @@ int mmc_init_device(int num)
        m = mmc_get_mmc_dev(dev);
        if (!m)
                return 0;
-#ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT
-       mmc_set_preinit(m, 1);
-#endif
        if (m->preinit)
                mmc_start_init(m);