This adds two new HS400 tuning operations:
* prepare_hs400_tuning_downgrade
* complete_hs400_tuning

These supplement the existing HS400 operation:
* prepare_hs400_tuning

This is motivated by a requirement of Renesas SDHI for the following:
1. Disabling SCC before selecting to HS if selection of HS400 has occurred.
   This can be done in an implementation of prepare_hs400_tuning_downgrade
2. Updating registers after switching to HS400
   This can be done in an implementation of complete_hs400_tuning

After this patch the call sequence is as follows:

* Initial tuning
  i. prepare_hs400_tuning
  2. Tuning procedure
  3. Select HS400
  4. complete_hs400_tuning

* Retune
  1. prepare_hs400_tuning_downgrade
  2. Select HS200
  3. prepare_hs400_tuning
  4. Tuning procedure
  5. Select HS400
  6. complete_hs400_tuning

If prepare_hs400_tuning or complete_hs400_tuning are not implemented they
are not called. And if neither are called the procedure is the same as
before this patch.

Design consideration: In the case of Renesas SDHI it is likely that
prepare_hs400_tuning_downgrade and prepare_hs400_tuning could be combined
if the latter was called before selecting HS200 during tuning. When I say
likely, I believe it matches my understanding of the hardware. However, I
did not test this as I am entirely unsure if moving the
prepare_hs400_tuning call would work for other hardware that uses this
operation and I am in no position to test such hardware.

Signed-off-by: Simon Horman <[email protected]>
---
v4
* New patch
---
 drivers/mmc/core/host.c  | 13 ++++++++++++-
 drivers/mmc/core/mmc.c   | 19 ++++++++++++++-----
 include/linux/mmc/host.h | 26 +++++++++++++++++++++++++-
 3 files changed, 51 insertions(+), 7 deletions(-)

diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index 64b03d6eaf18..5e60df7ca11f 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -138,6 +138,10 @@ int mmc_retune(struct mmc_host *host)
        host->doing_retune = 1;
 
        if (host->ios.timing == MMC_TIMING_MMC_HS400) {
+               if (host->ops->prepare_hs400_tuning_downgrade)
+                       host->ops->prepare_hs400_tuning_downgrade(host,
+                                                                 &host->ios);
+
                err = mmc_hs400_to_hs200(host->card);
                if (err)
                        goto out;
@@ -152,8 +156,15 @@ int mmc_retune(struct mmc_host *host)
        if (err)
                goto out;
 
-       if (return_to_hs400)
+       if (return_to_hs400) {
                err = mmc_hs200_to_hs400(host->card);
+               if (err)
+                       goto out;
+
+               if (host->ops->complete_hs400_tuning)
+                       host->ops->complete_hs400_tuning(host, &host->ios);
+       }
+
 out:
        host->doing_retune = 0;
 
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 099b327e10ca..a108a1a3e27f 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -1508,22 +1508,31 @@ static int mmc_select_timing(struct mmc_card *card)
 static int mmc_hs200_tuning(struct mmc_card *card)
 {
        struct mmc_host *host = card->host;
+       bool run_hs400_ops;
        int err;
 
+       run_hs400_ops = card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400 &&
+               host->ios.bus_width == MMC_BUS_WIDTH_8;
+
        /*
         * Timing should be adjusted to the HS400 target
         * operation frequency for tuning process
         */
-       if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400 &&
-           host->ios.bus_width == MMC_BUS_WIDTH_8)
-               if (host->ops->prepare_hs400_tuning)
-                       host->ops->prepare_hs400_tuning(host, &host->ios);
+       if (run_hs400_ops && host->ops->prepare_hs400_tuning)
+               host->ops->prepare_hs400_tuning(host, &host->ios);
 
        err = mmc_execute_tuning(card);
        if (err)
                return err;
 
-       return mmc_select_hs400(card);
+       err = mmc_select_hs400(card);
+       if (err)
+               return err;
+
+       if (run_hs400_ops && host->ops->complete_hs400_tuning)
+               host->ops->complete_hs400_tuning(host, &host->ios);
+
+       return 0;
 }
 
 /*
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 85146235231e..5d3ae1071d2f 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -143,8 +143,32 @@ struct mmc_host_ops {
        /* The tuning command opcode value is different for SD and eMMC cards */
        int     (*execute_tuning)(struct mmc_host *host, u32 opcode);
 
-       /* Prepare HS400 target operating frequency depending host driver */
+       /* Prepare for HS400 downgrade during tuning of target operating 
frequency depending on host driver
+        * If provided and retuning is in progress, this is called before:
+        * 1. Switching from HS400 to HS200; which preceeds
+        * 2. Calling .prepare_hs400_tuning, if present; which preceeds
+        * 3. The HS400 tuning procedure
+        */
+       void    (*prepare_hs400_tuning_downgrade)(struct mmc_host *host, struct 
mmc_ios *ios);
+
+       /* Prepare for tuning HS400 target operating frequency depending on 
host driver
+        * If provided, this called:
+        * - In the case that retuning is in progress, after:
+        *   1. .prepare_hs400_tuning_downgrade(), if present
+        *   2. Switching from HS400 to HS200
+        * - And in any case before:
+        *   3. The HS400 tuning procedure
+        */
+
        int     (*prepare_hs400_tuning)(struct mmc_host *host, struct mmc_ios 
*ios);
+
+       /* Complete tuning HS400 target operating frequency depending host 
driver
+        * If provided, this is called after:
+        * 1. The HS400 tuning procedure
+        * 2. Switching from HS200 to HS400
+        */
+       void    (*complete_hs400_tuning)(struct mmc_host *host, struct mmc_ios 
*ios);
+
        /* Prepare enhanced strobe depending host driver */
        void    (*hs400_enhanced_strobe)(struct mmc_host *host,
                                         struct mmc_ios *ios);
-- 
2.11.0

Reply via email to