Forráskód Böngészése

[components][drivers][mmc] add HS400 support to mmc driver

- added HS400 supprt (both eMMC5.0 and eMMC5.1 flavor are supported)

Signed-off-by: Fan YANG <fan.yang@hpmicro.com>
Fan YANG 11 hónapja
szülő
commit
1a1514640a

+ 6 - 3
components/drivers/include/drivers/mmc.h

@@ -1,11 +1,12 @@
 /*
- * Copyright (c) 2006-2023, RT-Thread Development Team
+ * Copyright (c) 2006-2024, RT-Thread Development Team
  *
  * SPDX-License-Identifier: Apache-2.0
  *
  * Change Logs:
  * Date           Author        Notes
- * 2015-06-15     hichard         first version
+ * 2015-06-15     hichard       first version
+ * 2024-05-25     HPMicro       add strobe support
  */
 
 #ifndef __MMC_H__
@@ -45,6 +46,7 @@ extern "C" {
 #define EXT_CSD_PART_CONFIG             179 /* R/W */
 #define EXT_CSD_ERASED_MEM_CONT         181 /* RO */
 #define EXT_CSD_BUS_WIDTH               183 /* R/W */
+#define EXT_CSD_STROBE_SUPPORT          184 /* RO */
 #define EXT_CSD_HS_TIMING               185 /* R/W */
 #define EXT_CSD_POWER_CLASS             187 /* R/W */
 #define EXT_CSD_REV                     192 /* RO */
@@ -130,8 +132,9 @@ extern "C" {
 #define EXT_CSD_BUS_WIDTH_8             2   /* Card is in 8 bit mode */
 #define EXT_CSD_DDR_BUS_WIDTH_4         5   /* Card is in 4 bit DDR mode */
 #define EXT_CSD_DDR_BUS_WIDTH_8         6   /* Card is in 8 bit DDR mode */
+#define EXT_CSD_DDR_BUS_WIDTH_8_EH_DS   0x86/* Card is in 8 bit DDR mode with Enhanced Data Strobe */
 
-#define EXT_CSD_TIMING_BC               0   /* Backwards compatility */
+#define EXT_CSD_TIMING_BC               0   /* Backwards compatibility */
 #define EXT_CSD_TIMING_HS               1   /* High speed */
 #define EXT_CSD_TIMING_HS200            2   /* HS200 */
 #define EXT_CSD_TIMING_HS400            3   /* HS400 */

+ 8 - 5
components/drivers/include/drivers/mmcsd_card.h

@@ -1,11 +1,12 @@
 /*
- * Copyright (c) 2006-2023, RT-Thread Development Team
+ * Copyright (c) 2006-2024, RT-Thread Development Team
  *
  * SPDX-License-Identifier: Apache-2.0
  *
  * Change Logs:
  * Date           Author        Notes
- * 2011-07-25     weety     first version
+ * 2011-07-25     weety         first version
+ * 2024-05-24     HPMicro       add HS400 support
  */
 
 #ifndef __MMCSD_CARD_H__
@@ -130,6 +131,7 @@ struct rt_sdio_function {
 struct rt_mmc_ext_csd
 {
     rt_uint32_t cache_size;
+    rt_uint32_t enhanced_data_strobe;
 };
 
 struct rt_mmcsd_card {
@@ -156,13 +158,14 @@ struct rt_mmcsd_card {
 #define CARD_FLAG_HIGHSPEED  (1 << 0)   /* SDIO bus speed 50MHz */
 #define CARD_FLAG_SDHC       (1 << 1)   /* SDHC card */
 #define CARD_FLAG_SDXC       (1 << 2)   /* SDXC card */
-#define CARD_FLAG_HIGHSPEED_DDR  (1 << 3)   /*HIGH SPEED DDR*/
-#define CARD_FLAG_HS200      (1 << 4)   /* BUS SPEED 200mHz*/
+#define CARD_FLAG_HIGHSPEED_DDR  (1 << 3)   /* HIGH SPEED DDR */
+#define CARD_FLAG_HS200      (1 << 4)   /* BUS SPEED 200MHz */
+#define CARD_FLAG_HS400      (1 << 5)   /* BUS SPEED 400MHz */
     struct rt_sd_scr    scr;
     struct rt_mmcsd_csd csd;
     rt_uint32_t     hs_max_data_rate;  /* max data transfer rate in high speed mode */
 
-    rt_uint8_t      sdio_function_num;  /* totol number of SDIO functions */
+    rt_uint8_t      sdio_function_num;  /* total number of SDIO functions */
     struct rt_sdio_cccr    cccr;  /* common card info */
     struct rt_sdio_cis     cis;  /* common tuple info */
     struct rt_sdio_function *sdio_function[SDIO_MAX_FUNCTIONS + 1]; /* SDIO functions (devices) */

+ 10 - 4
components/drivers/include/drivers/mmcsd_host.h

@@ -1,11 +1,12 @@
 /*
- * Copyright (c) 2006-2023, RT-Thread Development Team
+ * Copyright (c) 2006-2024, RT-Thread Development Team
  *
  * SPDX-License-Identifier: Apache-2.0
  *
  * Change Logs:
  * Date           Author        Notes
- * 2011-07-25     weety     first version
+ * 2011-07-25     weety         first version
+ * 2024-05-25     HPMicro       add HS400 support
  */
 
 #ifndef __HOST_H__
@@ -60,6 +61,7 @@ struct rt_mmcsd_io_cfg
 #define MMCSD_TIMING_MMC_DDR52  8
 #define MMCSD_TIMING_MMC_HS200  9
 #define MMCSD_TIMING_MMC_HS400  10
+#define MMCSD_TIMING_MMC_HS400_ENH_DS  11
 
     unsigned char   drv_type;       /* driver type (A, B, C, D) */
 
@@ -120,15 +122,19 @@ struct rt_mmcsd_host
 #define MMCSD_HOST_IS_SPI   (1 << 3)
 #define controller_is_spi(host) (host->flags & MMCSD_HOST_IS_SPI)
 #define MMCSD_SUP_SDIO_IRQ  (1 << 4)    /* support signal pending SDIO IRQs */
-#define MMCSD_SUP_HIGHSPEED (1 << 5)    /* support high speed SDR*/
+#define MMCSD_SUP_HIGHSPEED (1 << 5)    /* support high speed SDR */
 #define MMCSD_SUP_DDR_3V3    (1 << 6)
 #define MMCSD_SUP_DDR_1V8    (1 << 7)
 #define MMCSD_SUP_DDR_1V2    (1 << 8)
-#define MMCSD_SUP_HIGHSPEED_DDR (MMCSD_SUP_DDR_3V3 | MMCSD_SUP_DDR_1V8 | MMCSD_SUP_DDR_1V2)/* HIGH SPEED DDR*/
+#define MMCSD_SUP_HIGHSPEED_DDR (MMCSD_SUP_DDR_3V3 | MMCSD_SUP_DDR_1V8 | MMCSD_SUP_DDR_1V2)/* HIGH SPEED DDR */
 #define MMCSD_SUP_HS200_1V8  (1 << 9)
 #define MMCSD_SUP_HS200_1V2  (1 << 10)
 #define MMCSD_SUP_HS200     (MMCSD_SUP_HS200_1V2 | MMCSD_SUP_HS200_1V8) /* hs200 sdr */
 #define MMCSD_SUP_NONREMOVABLE  (1 << 11)
+#define MMCSD_SUP_HS400_1V8  (1 << 12)
+#define MMCSD_SUP_HS400_1V2  (1 << 13)
+#define MMCSD_SUP_HS400      (MMCSD_SUP_HS400_1V2 | MMCSD_SUP_HS400_1V8) /* hs400 ddr */
+#define MMCSD_SUP_ENH_DS     (1 << 14)
 
     rt_uint32_t max_seg_size;   /* maximum size of one dma segment */
     rt_uint32_t max_dma_segs;   /* maximum number of dma segments in one request */

+ 103 - 6
components/drivers/sdio/mmc.c

@@ -1,11 +1,12 @@
 /*
- * Copyright (c) 2006-2023, RT-Thread Development Team
+ * Copyright (c) 2006-2024, RT-Thread Development Team
  *
  * SPDX-License-Identifier: Apache-2.0
  *
  * Change Logs:
  * Date           Author       Notes
  * 2015-06-15     hichard      first version
+ * 2024-05-25     HPMicro      add HS400 support
  */
 
 #include <drivers/mmcsd_core.h>
@@ -193,12 +194,19 @@ static int mmc_parse_ext_csd(struct rt_mmcsd_card *card, rt_uint8_t *ext_csd)
     }
 
     host = card->host;
-    if (host->flags & MMCSD_SUP_HS200)
+
+    uint8_t device_type = ext_csd[EXT_CSD_CARD_TYPE];
+    if ((host->flags & MMCSD_SUP_HS400) && (device_type & EXT_CSD_CARD_TYPE_HS400))
+    {
+        card->flags |=  CARD_FLAG_HS400;
+        card->max_data_rate = 200000000;
+    }
+    else if ((host->flags & MMCSD_SUP_HS200) && (device_type & EXT_CSD_CARD_TYPE_HS200))
     {
         card->flags |=  CARD_FLAG_HS200;
-        card->hs_max_data_rate = 200000000;
+        card->max_data_rate = 200000000;
     }
-    else if (host->flags & MMCSD_SUP_HIGHSPEED_DDR)
+    else if ((host->flags & MMCSD_SUP_HIGHSPEED_DDR) && (device_type & EXT_CSD_CARD_TYPE_DDR_52))
     {
         card->flags |=  CARD_FLAG_HIGHSPEED_DDR;
         card->hs_max_data_rate = 52000000;
@@ -209,6 +217,11 @@ static int mmc_parse_ext_csd(struct rt_mmcsd_card *card, rt_uint8_t *ext_csd)
         card->hs_max_data_rate = 52000000;
     }
 
+    if (ext_csd[EXT_CSD_STROBE_SUPPORT] != 0)
+    {
+        card->ext_csd.enhanced_data_strobe = 1;
+    }
+
     card->ext_csd.cache_size =
         ext_csd[EXT_CSD_CACHE_SIZE + 0] << 0 |
         ext_csd[EXT_CSD_CACHE_SIZE + 1] << 8 |
@@ -410,6 +423,7 @@ static int mmc_select_bus_width(struct rt_mmcsd_card *card, rt_uint8_t *ext_csd)
 
     return err;
 }
+
 rt_err_t mmc_send_op_cond(struct rt_mmcsd_host *host,
                           rt_uint32_t ocr, rt_uint32_t *rocr)
 {
@@ -484,28 +498,111 @@ static int mmc_select_hs200(struct rt_mmcsd_card *card)
         return ret;
 
     mmcsd_set_timing(card->host, MMCSD_TIMING_MMC_HS200);
-    mmcsd_set_clock(card->host, 200000000);
+    mmcsd_set_clock(card->host, card->max_data_rate);
 
     ret = mmcsd_excute_tuning(card);
 
     return ret;
 }
 
+static int mmc_switch_to_hs400(struct rt_mmcsd_card *card)
+{
+    struct rt_mmcsd_host *host = card->host;
+    int err;
+    rt_uint8_t ext_csd_bus_width;
+    rt_uint32_t hs_timing;
+
+    /* Switch to HS_TIMING to 0x01 (High Speed) */
+    err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+                           EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS);
+    if (err != RT_EOK)
+    {
+        return err;
+    }
+    mmcsd_set_timing(card->host, MMCSD_TIMING_MMC_HS);
+    /* Host changes frequency to <= 52MHz  */
+    mmcsd_set_clock(card->host, 52000000);
+
+    rt_bool_t support_enhanced_ds = ((card->ext_csd.enhanced_data_strobe != 0) &&
+                                     ((host->flags & MMCSD_SUP_ENH_DS) != 0));
+
+    /* Set the bus width to:
+     *  0x86 if enhanced data strobe is supported, or
+     *  0x06 if enhanced data strobe is not supported
+     */
+    ext_csd_bus_width = support_enhanced_ds ?
+                        EXT_CSD_DDR_BUS_WIDTH_8_EH_DS :
+                        EXT_CSD_DDR_BUS_WIDTH_8;
+
+    err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+                     EXT_CSD_BUS_WIDTH,
+                     ext_csd_bus_width);
+    if (err != RT_EOK)
+    {
+        return err;
+    }
+
+    /* Set HS_TIMING to 0x03 (HS400) */
+    err = mmc_switch(card,
+                     EXT_CSD_CMD_SET_NORMAL,
+                     EXT_CSD_HS_TIMING,
+                     EXT_CSD_TIMING_HS400);
+    if (err != RT_EOK)
+    {
+        return err;
+    }
+
+    /* Change the Host timing accordingly */
+    hs_timing = support_enhanced_ds ?
+                MMCSD_TIMING_MMC_HS400_ENH_DS :
+                MMCSD_TIMING_MMC_HS400;
+    mmcsd_set_timing(host, hs_timing);
+
+    /* Host may changes frequency to <= 200MHz */
+    mmcsd_set_clock(card->host, card->max_data_rate);
+
+    return RT_EOK;
+}
+
+static int mmc_select_hs400(struct rt_mmcsd_card *card)
+{
+    int ret;
+    struct rt_mmcsd_host *host = card->host;
+    /* if the card or host doesn't support enhanced data strobe, switch to HS200 and perform tuning process first */
+    if ((card->ext_csd.enhanced_data_strobe == 0) || ((host->flags & MMCSD_SUP_ENH_DS) == 0))
+    {
+        ret = mmc_select_hs200(card);
+        if (ret != RT_EOK)
+        {
+            return ret;
+        }
+    }
+    return mmc_switch_to_hs400(card);
+}
+
 static int mmc_select_timing(struct rt_mmcsd_card *card)
 {
     int ret = 0;
 
-    if (card->flags & CARD_FLAG_HS200)
+    if (card->flags & CARD_FLAG_HS400)
+    {
+        LOG_I("emmc: switch to HS400 mode\n");
+        ret = mmc_select_hs400(card);
+    }
+    else if (card->flags & CARD_FLAG_HS200)
     {
+        LOG_I("emmc: switch to HS200 mode\n");
         ret = mmc_select_hs200(card);
     }
     else if (card->flags & CARD_FLAG_HIGHSPEED_DDR)
     {
+        LOG_I("emmc: switch to HIGH Speed DDR mode\n");
         mmcsd_set_timing(card->host, MMCSD_TIMING_MMC_DDR52);
         mmcsd_set_clock(card->host, card->hs_max_data_rate);
     }
     else
     {
+        LOG_I("emmc: switch to HIGH Speed mode\n");
         mmcsd_set_timing(card->host, MMCSD_TIMING_MMC_HS);
         mmcsd_set_clock(card->host, card->hs_max_data_rate);
     }