From 1a1514640a7bb1af107e400b4e27d07f7a7c444f Mon Sep 17 00:00:00 2001 From: Fan YANG Date: Sun, 26 May 2024 10:24:38 +0800 Subject: [PATCH] [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 --- components/drivers/include/drivers/mmc.h | 9 +- .../drivers/include/drivers/mmcsd_card.h | 13 ++- .../drivers/include/drivers/mmcsd_host.h | 14 ++- components/drivers/sdio/mmc.c | 109 +++++++++++++++++- 4 files changed, 127 insertions(+), 18 deletions(-) diff --git a/components/drivers/include/drivers/mmc.h b/components/drivers/include/drivers/mmc.h index c531baa90f..88ee740050 100644 --- a/components/drivers/include/drivers/mmc.h +++ b/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 */ diff --git a/components/drivers/include/drivers/mmcsd_card.h b/components/drivers/include/drivers/mmcsd_card.h index d348c9affa..1da7ac921a 100644 --- a/components/drivers/include/drivers/mmcsd_card.h +++ b/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) */ diff --git a/components/drivers/include/drivers/mmcsd_host.h b/components/drivers/include/drivers/mmcsd_host.h index c6935c1056..405adacb53 100644 --- a/components/drivers/include/drivers/mmcsd_host.h +++ b/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 */ diff --git a/components/drivers/sdio/mmc.c b/components/drivers/sdio/mmc.c index b4b6fbbad2..3723d9db76 100644 --- a/components/drivers/sdio/mmc.c +++ b/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 @@ -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); }