Merge changes from topic "st-mmc-updates" into integration

* changes:
  feat(st-sdmmc2): define FIFO size
  feat(st-sdmmc2): make reset property optional
  feat(st): enable MMC_FLAG_SD_CMD6 for SD-cards
  feat(st-sdmmc2): manage CMD6
  feat(mmc): manage SD Switch Function for high speed mode
This commit is contained in:
Madhukar Pappireddy 2022-08-17 16:33:10 +02:00 committed by TrustedFirmware Code Review
commit afbb10abdc
4 changed files with 133 additions and 16 deletions
drivers
include/drivers
plat/st/common

View file

@ -25,6 +25,7 @@
static const struct mmc_ops *ops;
static unsigned int mmc_ocr_value;
static struct mmc_csd_emmc mmc_csd;
static struct sd_switch_status sd_switch_func_status;
static unsigned char mmc_ext_csd[512] __aligned(16);
static unsigned int mmc_flags;
static struct mmc_device_info *mmc_dev_info;
@ -44,6 +45,11 @@ static bool is_cmd23_enabled(void)
return ((mmc_flags & MMC_FLAG_CMD23) != 0U);
}
static bool is_sd_cmd6_enabled(void)
{
return ((mmc_flags & MMC_FLAG_SD_CMD6) != 0U);
}
static int mmc_send_cmd(unsigned int idx, unsigned int arg,
unsigned int r_type, unsigned int *r_data)
{
@ -357,6 +363,33 @@ static int mmc_fill_device_info(void)
return 0;
}
static int sd_switch(unsigned int mode, unsigned char group,
unsigned char func)
{
unsigned int group_shift = (group - 1U) * 4U;
unsigned int group_mask = GENMASK(group_shift + 3U, group_shift);
unsigned int arg;
int ret;
ret = ops->prepare(0, (uintptr_t)&sd_switch_func_status,
sizeof(sd_switch_func_status));
if (ret != 0) {
return ret;
}
/* MMC CMD6: SWITCH_FUNC */
arg = mode | SD_SWITCH_ALL_GROUPS_MASK;
arg &= ~group_mask;
arg |= func << group_shift;
ret = mmc_send_cmd(MMC_CMD(6), arg, MMC_RESPONSE_R1, NULL);
if (ret != 0) {
return ret;
}
return ops->read(0, (uintptr_t)&sd_switch_func_status,
sizeof(sd_switch_func_status));
}
static int sd_send_op_cond(void)
{
int n;
@ -524,7 +557,39 @@ static int mmc_enumerate(unsigned int clk, unsigned int bus_width)
return ret;
}
return mmc_fill_device_info();
ret = mmc_fill_device_info();
if (ret != 0) {
return ret;
}
if (is_sd_cmd6_enabled() &&
(mmc_dev_info->mmc_dev_type == MMC_IS_SD_HC)) {
/* Try to switch to High Speed Mode */
ret = sd_switch(SD_SWITCH_FUNC_CHECK, 1U, 1U);
if (ret != 0) {
return ret;
}
if ((sd_switch_func_status.support_g1 & BIT(9)) == 0U) {
/* High speed not supported, keep default speed */
return 0;
}
ret = sd_switch(SD_SWITCH_FUNC_SWITCH, 1U, 1U);
if (ret != 0) {
return ret;
}
if ((sd_switch_func_status.sel_g2_g1 & 0x1U) == 0U) {
/* Cannot switch to high speed, keep default speed */
return 0;
}
mmc_dev_info->max_bus_freq = 50000000U;
ret = ops->set_ios(clk, bus_width);
}
return ret;
}
size_t mmc_read_blocks(int lba, uintptr_t buf, size_t size)

View file

@ -129,6 +129,8 @@
#define DT_SDMMC2_COMPAT "st,stm32-sdmmc2"
#endif
#define SDMMC_FIFO_SIZE 64U
static void stm32_sdmmc2_init(void);
static int stm32_sdmmc2_send_cmd_req(struct mmc_cmd *cmd);
static int stm32_sdmmc2_send_cmd(struct mmc_cmd *cmd);
@ -148,6 +150,8 @@ static const struct mmc_ops stm32_sdmmc2_ops = {
static struct stm32_sdmmc2_params sdmmc2_params;
static bool next_cmd_is_acmd;
#pragma weak plat_sdmmc2_use_dma
bool plat_sdmmc2_use_dma(unsigned int instance, unsigned int memory)
{
@ -257,6 +261,20 @@ static int stm32_sdmmc2_send_cmd_req(struct mmc_cmd *cmd)
case MMC_CMD(1):
arg_reg |= OCR_POWERUP;
break;
case MMC_CMD(6):
if ((sdmmc2_params.device_info->mmc_dev_type == MMC_IS_SD_HC) &&
(!next_cmd_is_acmd)) {
cmd_reg |= SDMMC_CMDR_CMDTRANS;
if (sdmmc2_params.use_dma) {
flags_data |= SDMMC_STAR_DCRCFAIL |
SDMMC_STAR_DTIMEOUT |
SDMMC_STAR_DATAEND |
SDMMC_STAR_RXOVERR |
SDMMC_STAR_IDMATE |
SDMMC_STAR_DBCKEND;
}
}
break;
case MMC_CMD(8):
if (sdmmc2_params.device_info->mmc_dev_type == MMC_IS_EMMC) {
cmd_reg |= SDMMC_CMDR_CMDTRANS;
@ -294,6 +312,8 @@ static int stm32_sdmmc2_send_cmd_req(struct mmc_cmd *cmd)
break;
}
next_cmd_is_acmd = (cmd->cmd_idx == MMC_CMD(55));
mmio_write_32(base + SDMMC_ICR, SDMMC_STATIC_FLAGS);
/*
@ -301,8 +321,7 @@ static int stm32_sdmmc2_send_cmd_req(struct mmc_cmd *cmd)
* Skip CMD55 as the next command could be data related, and
* the register could have been set in prepare function.
*/
if (((cmd_reg & SDMMC_CMDR_CMDTRANS) == 0U) &&
(cmd->cmd_idx != MMC_CMD(55))) {
if (((cmd_reg & SDMMC_CMDR_CMDTRANS) == 0U) && !next_cmd_is_acmd) {
mmio_write_32(base + SDMMC_DCTRLR, 0U);
}
@ -627,7 +646,7 @@ static int stm32_sdmmc2_read(int lba, uintptr_t buf, size_t size)
return -ETIMEDOUT;
}
if (size < (8U * sizeof(uint32_t))) {
if (size < (SDMMC_FIFO_SIZE / 2U)) {
if ((mmio_read_32(base + SDMMC_DCNTR) > 0U) &&
((status & SDMMC_STAR_RXFIFOE) == 0U)) {
*buffer = mmio_read_32(fifo_reg);
@ -637,7 +656,8 @@ static int stm32_sdmmc2_read(int lba, uintptr_t buf, size_t size)
uint32_t count;
/* Read data from SDMMC Rx FIFO */
for (count = 0; count < 8U; count++) {
for (count = 0; count < (SDMMC_FIFO_SIZE / 2U);
count += sizeof(uint32_t)) {
*buffer = mmio_read_32(fifo_reg);
buffer++;
}
@ -737,8 +757,6 @@ unsigned long long stm32_sdmmc2_mmc_get_device_size(void)
int stm32_sdmmc2_mmc_init(struct stm32_sdmmc2_params *params)
{
int rc;
assert((params != NULL) &&
((params->reg_base & MMC_BLOCK_MASK) == 0U) &&
((params->bus_width == MMC_BUS_WIDTH_1) ||
@ -756,16 +774,20 @@ int stm32_sdmmc2_mmc_init(struct stm32_sdmmc2_params *params)
clk_enable(sdmmc2_params.clock_id);
rc = stm32mp_reset_assert(sdmmc2_params.reset_id, TIMEOUT_US_1_MS);
if (rc != 0) {
panic();
if ((int)sdmmc2_params.reset_id >= 0) {
int rc;
rc = stm32mp_reset_assert(sdmmc2_params.reset_id, TIMEOUT_US_1_MS);
if (rc != 0) {
panic();
}
udelay(2);
rc = stm32mp_reset_deassert(sdmmc2_params.reset_id, TIMEOUT_US_1_MS);
if (rc != 0) {
panic();
}
mdelay(1);
}
udelay(2);
rc = stm32mp_reset_deassert(sdmmc2_params.reset_id, TIMEOUT_US_1_MS);
if (rc != 0) {
panic();
}
mdelay(1);
sdmmc2_params.clk_rate = clk_get_rate(sdmmc2_params.clock_id);
sdmmc2_params.device_info->ocr_voltage = OCR_3_2_3_3 | OCR_3_3_3_4;

View file

@ -111,6 +111,7 @@
#define MMC_STATE_SLP 10
#define MMC_FLAG_CMD23 (U(1) << 0)
#define MMC_FLAG_SD_CMD6 (U(1) << 1)
#define CMD8_CHECK_PATTERN U(0xAA)
#define VHS_2_7_3_6_V BIT(8)
@ -118,6 +119,10 @@
#define SD_SCR_BUS_WIDTH_1 BIT(8)
#define SD_SCR_BUS_WIDTH_4 BIT(10)
#define SD_SWITCH_FUNC_CHECK 0U
#define SD_SWITCH_FUNC_SWITCH BIT(31)
#define SD_SWITCH_ALL_GROUPS_MASK GENMASK(23, 0)
struct mmc_cmd {
unsigned int cmd_idx;
unsigned int cmd_arg;
@ -217,6 +222,27 @@ struct mmc_csd_sd_v2 {
unsigned int csd_structure: 2;
};
struct sd_switch_status {
unsigned short max_current;
unsigned short support_g6;
unsigned short support_g5;
unsigned short support_g4;
unsigned short support_g3;
unsigned short support_g2;
unsigned short support_g1;
unsigned char sel_g6_g5;
unsigned char sel_g4_g3;
unsigned char sel_g2_g1;
unsigned char data_struct_ver;
unsigned short busy_g6;
unsigned short busy_g5;
unsigned short busy_g4;
unsigned short busy_g3;
unsigned short busy_g2;
unsigned short busy_g1;
unsigned short reserved[17];
};
enum mmc_device_type {
MMC_IS_EMMC,
MMC_IS_SD,

View file

@ -221,6 +221,10 @@ static void boot_mmc(enum mmc_device_type mmc_dev_type,
break;
}
if (mmc_dev_type != MMC_IS_EMMC) {
params.flags = MMC_FLAG_SD_CMD6;
}
params.device_info = &mmc_info;
if (stm32_sdmmc2_mmc_init(&params) != 0) {
ERROR("SDMMC%u init failed\n", boot_interface_instance);