[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 <fan.yang@hpmicro.com>
This commit is contained in:
parent
09a0e4c5f8
commit
2cc2743fc7
|
@ -7,6 +7,7 @@
|
|||
* Date Author Notes
|
||||
* 2011-07-25 weety first version
|
||||
* 2024-05-24 HPMicro add HS400 support
|
||||
* 2024-05-26 HPMicro add UHS-I support for SD card
|
||||
*/
|
||||
|
||||
#ifndef __MMCSD_CARD_H__
|
||||
|
@ -84,6 +85,51 @@ struct rt_sdio_cccr {
|
|||
|
||||
};
|
||||
|
||||
/*
|
||||
* SD Status
|
||||
*/
|
||||
union rt_sd_status {
|
||||
rt_uint32_t status_words[16];
|
||||
struct {
|
||||
rt_uint32_t reserved[12];
|
||||
rt_uint64_t : 8;
|
||||
rt_uint64_t uhs_au_size: 4;
|
||||
rt_uint64_t uhs_speed_grade: 4;
|
||||
rt_uint64_t erase_offset: 2;
|
||||
rt_uint64_t erase_timeout: 6;
|
||||
rt_uint64_t erase_size: 16;
|
||||
rt_uint64_t : 4;
|
||||
rt_uint64_t au_size: 4;
|
||||
rt_uint64_t performance_move: 8;
|
||||
rt_uint64_t speed_class: 8;
|
||||
|
||||
rt_uint32_t size_of_protected_area;
|
||||
|
||||
rt_uint32_t sd_card_type: 16;
|
||||
rt_uint32_t : 6;
|
||||
rt_uint32_t : 7;
|
||||
rt_uint32_t secured_mode: 1;
|
||||
rt_uint32_t data_bus_width: 2;
|
||||
};
|
||||
};
|
||||
|
||||
/*
|
||||
* SD Speed Class
|
||||
*/
|
||||
#define SD_SPEED_CLASS_0 0
|
||||
#define SD_SPEED_CLASS_2 1
|
||||
#define SD_SPEED_CLASS_4 2
|
||||
#define SD_SPEED_CLASS_6 3
|
||||
#define SD_SPEED_CLASS_10 4
|
||||
|
||||
/*
|
||||
* UHS Speed Grade
|
||||
*/
|
||||
#define UHS_SPEED_GRADE_0 0
|
||||
#define UHS_SPEED_GRADE_1 1
|
||||
#define UHS_SPEED_GRADE_3 3
|
||||
|
||||
|
||||
struct rt_sdio_cis {
|
||||
rt_uint16_t manufacturer;
|
||||
rt_uint16_t product;
|
||||
|
@ -161,6 +207,9 @@ struct rt_mmcsd_card {
|
|||
#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 */
|
||||
#define CARD_FLAG_SDR50 (1 << 6) /* BUS SPEED 100MHz */
|
||||
#define CARD_FLAG_SDR104 (1 << 7) /* BUS SPEED 200MHz */
|
||||
#define CARD_FLAG_DDR50 (1 << 8) /* DDR50, works on 1.8V only */
|
||||
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 */
|
||||
|
|
|
@ -5,7 +5,8 @@
|
|||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2011-07-25 weety first version
|
||||
* 2011-07-25 weety first version
|
||||
* 2024-05-26 HPMicro add VOLTAGE_SWITCH definition
|
||||
*/
|
||||
|
||||
#ifndef __CMD_H__
|
||||
|
@ -26,7 +27,7 @@ extern "C" {
|
|||
#define SEND_EXT_CSD 8 /* adtc R1 */
|
||||
#define SEND_CSD 9 /* ac [31:16] RCA R2 */
|
||||
#define SEND_CID 10 /* ac [31:16] RCA R2 */
|
||||
#define READ_DAT_UNTIL_STOP 11 /* adtc [31:0] dadr R1 */
|
||||
#define VOLTAGE_SWITCH 11 /* ac [31:0] R1 */
|
||||
#define STOP_TRANSMISSION 12 /* ac R1b */
|
||||
#define SEND_STATUS 13 /* ac [31:16] RCA R1 */
|
||||
#define GO_INACTIVE_STATE 15 /* ac [31:16] RCA */
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
* Date Author Notes
|
||||
* 2011-07-25 weety first version
|
||||
* 2024-05-25 HPMicro add HS400 support
|
||||
* 2024-05-26 HPMicro add UHS-I support
|
||||
*/
|
||||
|
||||
#ifndef __HOST_H__
|
||||
|
@ -87,6 +88,7 @@ struct rt_mmcsd_host_ops
|
|||
rt_int32_t (*get_card_status)(struct rt_mmcsd_host *host);
|
||||
void (*enable_sdio_irq)(struct rt_mmcsd_host *host, rt_int32_t en);
|
||||
rt_int32_t (*execute_tuning)(struct rt_mmcsd_host *host, rt_int32_t opcode);
|
||||
rt_int32_t (*switch_uhs_voltage)(struct rt_mmcsd_host *host);
|
||||
};
|
||||
|
||||
struct rt_mmcsd_host
|
||||
|
@ -115,6 +117,7 @@ struct rt_mmcsd_host
|
|||
#define VDD_33_34 (1 << 21) /* VDD voltage 3.3 ~ 3.4 */
|
||||
#define VDD_34_35 (1 << 22) /* VDD voltage 3.4 ~ 3.5 */
|
||||
#define VDD_35_36 (1 << 23) /* VDD voltage 3.5 ~ 3.6 */
|
||||
#define OCR_S18R (1 << 24) /* Switch to 1V8 Request */
|
||||
rt_uint32_t flags; /* define device capabilities */
|
||||
#define MMCSD_BUSWIDTH_4 (1 << 0)
|
||||
#define MMCSD_BUSWIDTH_8 (1 << 1)
|
||||
|
@ -135,6 +138,9 @@ struct rt_mmcsd_host
|
|||
#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)
|
||||
#define MMCSD_SUP_SDR50 (1 << 15)
|
||||
#define MMCSD_SUP_SDR104 (1 << 16)
|
||||
#define MMCSD_SUP_DDR50 (1 << 17)
|
||||
|
||||
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 */
|
||||
|
|
|
@ -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
|
||||
* 2024-05-26 HPMicro Add UHS-I support
|
||||
*/
|
||||
|
||||
#ifndef __SD_H__
|
||||
|
@ -18,6 +19,17 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* SWITCH_FUNC timing
|
||||
*/
|
||||
#define SD_SWITCH_FUNC_TIMING_DEFAULT 0
|
||||
#define SD_SWITCH_FUNC_TIMING_HS 1
|
||||
#define SD_SWITCH_FUNC_TIMING_SDR50 2
|
||||
#define SD_SWITCH_FUNC_TIMING_SDR104 3
|
||||
#define SD_SWITCH_FUNC_TIMING_DDR50 4
|
||||
|
||||
|
||||
rt_err_t mmcsd_send_if_cond(struct rt_mmcsd_host *host, rt_uint32_t ocr);
|
||||
rt_err_t mmcsd_send_app_op_cond(struct rt_mmcsd_host *host, rt_uint32_t ocr, rt_uint32_t *rocr);
|
||||
|
||||
|
|
|
@ -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,31 +755,8 @@ static rt_int32_t mmcsd_sd_init_card(struct rt_mmcsd_host *host,
|
|||
goto err1;
|
||||
}
|
||||
|
||||
/*
|
||||
* change SD card to high-speed, only SD2.0 spec
|
||||
*/
|
||||
err = mmcsd_switch(card);
|
||||
if (err)
|
||||
goto err1;
|
||||
|
||||
/* set bus speed */
|
||||
max_data_rate = (unsigned int)-1;
|
||||
|
||||
if (card->flags & CARD_FLAG_HIGHSPEED)
|
||||
{
|
||||
if (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)
|
||||
{
|
||||
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))
|
||||
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)
|
||||
|
@ -628,6 +764,41 @@ static rt_int32_t mmcsd_sd_init_card(struct rt_mmcsd_host *host,
|
|||
|
||||
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 the highest supported speed
|
||||
*/
|
||||
err = mmcsd_switch(card);
|
||||
if (err)
|
||||
goto err1;
|
||||
|
||||
/* set bus speed */
|
||||
max_data_rate = (unsigned int)-1;
|
||||
if (max_data_rate < card->hs_max_data_rate)
|
||||
{
|
||||
max_data_rate = card->hs_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);
|
||||
|
||||
host->card = card;
|
||||
|
||||
|
@ -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);
|
||||
|
||||
/*
|
||||
|
|
Loading…
Reference in New Issue