diff options
| author | Fan YANG <[email protected]> | 2024-05-26 14:13:32 +0800 |
|---|---|---|
| committer | Rbb666 <[email protected]> | 2024-05-27 11:27:03 +0800 |
| commit | 2cc2743fc73ec1645c9c84fa2d28988b5b6cbc6a (patch) | |
| tree | 2adfe27a78e168ae78a9612dee10b208be887e42 /components/drivers/sdio | |
| parent | 09a0e4c5f83fab24348e95d52fba7180a82abe12 (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.c | 227 |
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); /* |
