mirror of
https://github.com/ARM-software/arm-trusted-firmware.git
synced 2025-04-27 07:15:20 +00:00
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:
commit
afbb10abdc
4 changed files with 133 additions and 16 deletions
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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(¶ms) != 0) {
|
||||
ERROR("SDMMC%u init failed\n", boot_interface_instance);
|
||||
|
|
Loading…
Add table
Reference in a new issue