summaryrefslogtreecommitdiff
path: root/components/drivers/sdio
diff options
context:
space:
mode:
authorFan YANG <[email protected]>2024-05-26 14:13:32 +0800
committerRbb666 <[email protected]>2024-05-27 11:27:03 +0800
commit2cc2743fc73ec1645c9c84fa2d28988b5b6cbc6a (patch)
tree2adfe27a78e168ae78a9612dee10b208be887e42 /components/drivers/sdio
parent09a0e4c5f83fab24348e95d52fba7180a82abe12 (diff)
[components][drivers][sd] add uhs-i mode support to sd driver
- added SDR50, SDR104 and DDR50 support to SD driver Signed-off-by: Fan YANG <[email protected]>
Diffstat (limited to 'components/drivers/sdio')
-rw-r--r--components/drivers/sdio/sd.c227
1 files changed, 195 insertions, 32 deletions
diff --git a/components/drivers/sdio/sd.c b/components/drivers/sdio/sd.c
index cebb86ee43..222c1fd95f 100644
--- a/components/drivers/sdio/sd.c
+++ b/components/drivers/sdio/sd.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
- * 2011-07-25 weety first version
+ * 2011-07-25 weety first version
+ * 2024-05-26 HPMicro add UHS-I support
*/
#include <drivers/mmcsd_core.h>
@@ -203,7 +204,25 @@ static rt_int32_t mmcsd_switch(struct rt_mmcsd_card *card)
rt_memset(&cmd, 0, sizeof(struct rt_mmcsd_cmd));
cmd.cmd_code = SD_SWITCH;
- cmd.arg = 0x80FFFFF1;
+
+ rt_uint32_t switch_func_timing;
+ if ((card->flags & CARD_FLAG_SDR104) && (card->host->flags & MMCSD_SUP_SDR104))
+ {
+ switch_func_timing = SD_SWITCH_FUNC_TIMING_SDR104;
+ }
+ else if ((card->flags & CARD_FLAG_SDR50) && (card->host->flags & MMCSD_SUP_SDR50))
+ {
+ switch_func_timing = SD_SWITCH_FUNC_TIMING_SDR50;
+ }
+ else if ((card->flags & CARD_FLAG_DDR50) && (card->host->flags & MMCSD_SUP_DDR50))
+ {
+ switch_func_timing = SD_SWITCH_FUNC_TIMING_DDR50;
+ }
+ else
+ {
+ switch_func_timing = SD_SWITCH_FUNC_TIMING_HS;
+ }
+ cmd.arg = 0x80FFFFF0 | switch_func_timing;
cmd.flags = RESP_R1 | CMD_ADTC;
rt_memset(&data, 0, sizeof(struct rt_mmcsd_data));
@@ -227,13 +246,60 @@ static rt_int32_t mmcsd_switch(struct rt_mmcsd_card *card)
goto err1;
}
- if ((buf[16] & 0xF) != 1)
+ if ((buf[16] & 0xF) != switch_func_timing)
{
- LOG_I("switching card to high speed failed!");
+ LOG_E("switching card to timing mode %d failed!", switch_func_timing);
goto err;
}
- card->flags |= CARD_FLAG_HIGHSPEED;
+ switch(switch_func_timing)
+ {
+ case SD_SWITCH_FUNC_TIMING_SDR104:
+ card->flags |= CARD_FLAG_SDR104;
+ break;
+ case SD_SWITCH_FUNC_TIMING_SDR50:
+ card->flags |= CARD_FLAG_SDR50;
+ break;
+ case SD_SWITCH_FUNC_TIMING_DDR50:
+ card->flags |= CARD_FLAG_DDR50;
+ break;
+ case SD_SWITCH_FUNC_TIMING_HS:
+ card->flags |= CARD_FLAG_HIGHSPEED;
+ break;
+ default:
+ /* Default speed */
+ break;
+ }
+
+ card->max_data_rate = 50000000;
+ if (switch_func_timing == SD_SWITCH_FUNC_TIMING_SDR104)
+ {
+ LOG_I("sd: switch to SDR104 mode\n");
+ mmcsd_set_timing(card->host, MMCSD_TIMING_UHS_SDR104);
+ mmcsd_set_clock(card->host, 208000000);
+ err = mmcsd_excute_tuning(card);
+ card->max_data_rate = 208000000;
+ }
+ else if (switch_func_timing == SD_SWITCH_FUNC_TIMING_SDR50)
+ {
+ LOG_I("sd: switch to SDR50 mode\n");
+ mmcsd_set_timing(card->host, MMCSD_TIMING_UHS_SDR50);
+ mmcsd_set_clock(card->host, 100000000);
+ err = mmcsd_excute_tuning(card);
+ card->max_data_rate = 10000000;
+ }
+ else if (switch_func_timing == SD_SWITCH_FUNC_TIMING_DDR50)
+ {
+ LOG_I("sd: switch to DDR50 mode\n");
+ mmcsd_set_timing(card->host, MMCSD_TIMING_UHS_DDR50);
+ mmcsd_set_clock(card->host, 50000000);
+ }
+ else
+ {
+ LOG_I("sd: switch to High Speed / SDR25 mode \n");
+ mmcsd_set_timing(card->host, MMCSD_TIMING_SD_HS);
+ mmcsd_set_clock(card->host, 50000000);
+ }
err:
rt_free(buf);
@@ -511,6 +577,82 @@ rt_int32_t mmcsd_get_scr(struct rt_mmcsd_card *card, rt_uint32_t *scr)
return 0;
}
+static rt_err_t mmcsd_read_sd_status(struct rt_mmcsd_card *card, rt_uint32_t *sd_status)
+{
+ rt_int32_t err;
+ struct rt_mmcsd_req req;
+ struct rt_mmcsd_cmd cmd;
+ struct rt_mmcsd_data data;
+
+ err = mmcsd_app_cmd(card->host, card);
+ if (err)
+ return err;
+
+ rt_memset(&req, 0, sizeof(struct rt_mmcsd_req));
+ rt_memset(&cmd, 0, sizeof(struct rt_mmcsd_cmd));
+ rt_memset(&data, 0, sizeof(struct rt_mmcsd_data));
+
+ req.cmd = &cmd;
+ req.data = &data;
+
+ cmd.cmd_code = SEND_STATUS;
+ cmd.arg = 0;
+ cmd.flags = RESP_SPI_R1 | RESP_R1 | CMD_ADTC;
+
+ data.blksize = 64;
+ data.blks = 1;
+ data.flags = DATA_DIR_READ;
+ data.buf = sd_status;
+
+ mmcsd_set_data_timeout(&data, card);
+
+ mmcsd_send_request(card->host, &req);
+
+ if (cmd.err)
+ return cmd.err;
+ if (data.err)
+ return data.err;
+
+ /* Convert endian */
+ for (uint32_t i=0; i < 8; i++)
+ {
+ uint32_t tmp = sd_status[i];
+ sd_status[i] = sd_status[15 - i];
+ sd_status[15 - i] = tmp;
+ }
+ for (uint32_t i=0; i < 16; i++)
+ {
+ sd_status[i] = be32_to_cpu(sd_status[i]);
+ }
+
+
+ return 0;
+}
+
+static rt_err_t sd_switch_voltage(struct rt_mmcsd_host *host)
+{
+ rt_err_t err;
+ struct rt_mmcsd_cmd cmd = { 0 };
+
+ cmd.cmd_code = VOLTAGE_SWITCH;
+ cmd.arg = 0;
+ cmd.flags = RESP_R1 | CMD_AC;
+
+ err = mmcsd_send_cmd(host, &cmd, 0);
+ if (err)
+ return err;
+
+ return RT_EOK;
+}
+
+static rt_err_t sd_switch_uhs_voltage(struct rt_mmcsd_host *host)
+{
+ if (host->ops->switch_uhs_voltage != RT_NULL)
+ {
+ return host->ops->switch_uhs_voltage(host);
+ }
+ return -ENOSYS;
+}
static rt_int32_t mmcsd_sd_init_card(struct rt_mmcsd_host *host,
rt_uint32_t ocr)
@@ -532,10 +674,27 @@ static rt_int32_t mmcsd_sd_init_card(struct rt_mmcsd_host *host,
if (!err)
ocr |= 1 << 30;
- err = mmcsd_send_app_op_cond(host, ocr, RT_NULL);
+ /* Switch to UHS voltage if both Host and the Card support this feature */
+ if (((host->valid_ocr & VDD_165_195) != 0) && (host->ops->switch_uhs_voltage != RT_NULL))
+ {
+ ocr |= OCR_S18R;
+ }
+ err = mmcsd_send_app_op_cond(host, ocr, &ocr);
if (err)
goto err2;
+ /* Select voltage */
+ if (ocr & OCR_S18R)
+ {
+ ocr = VDD_165_195;
+ err = sd_switch_voltage(host);
+ if (err)
+ goto err2;
+ err = sd_switch_uhs_voltage(host);
+ if (err)
+ goto err2;
+ }
+
if (controller_is_spi(host))
err = mmcsd_get_cid(host, resp);
else
@@ -596,8 +755,33 @@ static rt_int32_t mmcsd_sd_init_card(struct rt_mmcsd_host *host,
goto err1;
}
+ /*switch bus width*/
+ if ((host->flags & MMCSD_BUSWIDTH_4) && (card->scr.sd_bus_widths & SD_SCR_BUS_WIDTH_4))
+ {
+ err = mmcsd_app_set_bus_width(card, MMCSD_BUS_WIDTH_4);
+ if (err)
+ goto err1;
+
+ mmcsd_set_bus_width(host, MMCSD_BUS_WIDTH_4);
+ }
+ mmcsd_set_timing(host, MMCSD_TIMING_LEGACY);
+ mmcsd_set_clock(host, 25000000);
+
+ /* Read and decode SD Status and check whether UHS mode is supported */
+ union rt_sd_status sd_status;
+ err = mmcsd_read_sd_status(card, sd_status.status_words);
+ if (err)
+ goto err1;
+ if ((sd_status.uhs_speed_grade > 0) && (ocr & VDD_165_195))
+ {
+ /* Assume the card supports all UHS-I modes because we cannot find any mainstreaming card
+ * that can support only part of the following modes.
+ */
+ card->flags |= CARD_FLAG_SDR50 | CARD_FLAG_SDR104 | CARD_FLAG_DDR50;
+ }
+
/*
- * change SD card to high-speed, only SD2.0 spec
+ * change SD card to the highest supported speed
*/
err = mmcsd_switch(card);
if (err)
@@ -605,30 +789,17 @@ static rt_int32_t mmcsd_sd_init_card(struct rt_mmcsd_host *host,
/* set bus speed */
max_data_rate = (unsigned int)-1;
-
- if (card->flags & CARD_FLAG_HIGHSPEED)
+ if (max_data_rate < card->hs_max_data_rate)
{
- if (max_data_rate > card->hs_max_data_rate)
- max_data_rate = card->hs_max_data_rate;
+ max_data_rate = card->hs_max_data_rate;
}
- else if (max_data_rate > card->max_data_rate)
+ if (max_data_rate < card->max_data_rate)
{
max_data_rate = card->max_data_rate;
}
mmcsd_set_clock(host, max_data_rate);
- /*switch bus width*/
- if ((host->flags & MMCSD_BUSWIDTH_4) &&
- (card->scr.sd_bus_widths & SD_SCR_BUS_WIDTH_4))
- {
- err = mmcsd_app_set_bus_width(card, MMCSD_BUS_WIDTH_4);
- if (err)
- goto err1;
-
- mmcsd_set_bus_width(host, MMCSD_BUS_WIDTH_4);
- }
-
host->card = card;
return 0;
@@ -659,14 +830,6 @@ rt_int32_t init_sd(struct rt_mmcsd_host *host, rt_uint32_t ocr)
goto _err;
}
- if (ocr & VDD_165_195)
- {
- LOG_I(" SD card claims to support the "
- "incompletely defined 'low voltage range'. This "
- "will be ignored.");
- ocr &= ~VDD_165_195;
- }
-
current_ocr = mmcsd_select_voltage(host, ocr);
/*