1ad71d45eSYann Gautier /* 2*5f9984efSYann Gautier * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. 3ad71d45eSYann Gautier * 4ad71d45eSYann Gautier * SPDX-License-Identifier: BSD-3-Clause 5ad71d45eSYann Gautier */ 6ad71d45eSYann Gautier 7ad71d45eSYann Gautier /* Define a simple and generic interface to access eMMC and SD-card devices. */ 8ad71d45eSYann Gautier 9ad71d45eSYann Gautier #include <assert.h> 10ad71d45eSYann Gautier #include <errno.h> 11ad71d45eSYann Gautier #include <stdbool.h> 12ad71d45eSYann Gautier #include <string.h> 1309d40e0eSAntonio Nino Diaz 1409d40e0eSAntonio Nino Diaz #include <arch_helpers.h> 1509d40e0eSAntonio Nino Diaz #include <common/debug.h> 1609d40e0eSAntonio Nino Diaz #include <drivers/delay_timer.h> 1709d40e0eSAntonio Nino Diaz #include <drivers/mmc.h> 1809d40e0eSAntonio Nino Diaz #include <lib/utils.h> 19ad71d45eSYann Gautier 20ad71d45eSYann Gautier #define MMC_DEFAULT_MAX_RETRIES 5 21ad71d45eSYann Gautier #define SEND_OP_COND_MAX_RETRIES 100 22ad71d45eSYann Gautier 23ad71d45eSYann Gautier #define MULT_BY_512K_SHIFT 19 24ad71d45eSYann Gautier 25ad71d45eSYann Gautier static const struct mmc_ops *ops; 26ad71d45eSYann Gautier static unsigned int mmc_ocr_value; 27ad71d45eSYann Gautier static struct mmc_csd_emmc mmc_csd; 2807858dd8SHaojian Zhuang static unsigned char mmc_ext_csd[512] __aligned(16); 29ad71d45eSYann Gautier static unsigned int mmc_flags; 30ad71d45eSYann Gautier static struct mmc_device_info *mmc_dev_info; 31ad71d45eSYann Gautier static unsigned int rca; 32ad71d45eSYann Gautier 33ad71d45eSYann Gautier static const unsigned char tran_speed_base[16] = { 34ad71d45eSYann Gautier 0, 10, 12, 13, 15, 20, 26, 30, 35, 40, 45, 52, 55, 60, 70, 80 35ad71d45eSYann Gautier }; 36ad71d45eSYann Gautier 37ad71d45eSYann Gautier static const unsigned char sd_tran_speed_base[16] = { 38ad71d45eSYann Gautier 0, 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80 39ad71d45eSYann Gautier }; 40ad71d45eSYann Gautier 41ad71d45eSYann Gautier static bool is_cmd23_enabled(void) 42ad71d45eSYann Gautier { 43ad71d45eSYann Gautier return ((mmc_flags & MMC_FLAG_CMD23) != 0U); 44ad71d45eSYann Gautier } 45ad71d45eSYann Gautier 46ad71d45eSYann Gautier static int mmc_send_cmd(unsigned int idx, unsigned int arg, 47ad71d45eSYann Gautier unsigned int r_type, unsigned int *r_data) 48ad71d45eSYann Gautier { 49ad71d45eSYann Gautier struct mmc_cmd cmd; 50ad71d45eSYann Gautier int ret; 51ad71d45eSYann Gautier 52ad71d45eSYann Gautier zeromem(&cmd, sizeof(struct mmc_cmd)); 53ad71d45eSYann Gautier 54ad71d45eSYann Gautier cmd.cmd_idx = idx; 55ad71d45eSYann Gautier cmd.cmd_arg = arg; 56ad71d45eSYann Gautier cmd.resp_type = r_type; 57ad71d45eSYann Gautier 58ad71d45eSYann Gautier ret = ops->send_cmd(&cmd); 59ad71d45eSYann Gautier 60ad71d45eSYann Gautier if ((ret == 0) && (r_data != NULL)) { 61ad71d45eSYann Gautier int i; 62ad71d45eSYann Gautier 63ad71d45eSYann Gautier for (i = 0; i < 4; i++) { 64ad71d45eSYann Gautier *r_data = cmd.resp_data[i]; 65ad71d45eSYann Gautier r_data++; 66ad71d45eSYann Gautier } 67ad71d45eSYann Gautier } 68ad71d45eSYann Gautier 69ad71d45eSYann Gautier if (ret != 0) { 70ad71d45eSYann Gautier VERBOSE("Send command %u error: %d\n", idx, ret); 71ad71d45eSYann Gautier } 72ad71d45eSYann Gautier 73ad71d45eSYann Gautier return ret; 74ad71d45eSYann Gautier } 75ad71d45eSYann Gautier 76ad71d45eSYann Gautier static int mmc_device_state(void) 77ad71d45eSYann Gautier { 78ad71d45eSYann Gautier int retries = MMC_DEFAULT_MAX_RETRIES; 79ad71d45eSYann Gautier unsigned int resp_data[4]; 80ad71d45eSYann Gautier 81ad71d45eSYann Gautier do { 82ad71d45eSYann Gautier int ret; 83ad71d45eSYann Gautier 84ad71d45eSYann Gautier if (retries == 0) { 85ad71d45eSYann Gautier ERROR("CMD13 failed after %d retries\n", 86ad71d45eSYann Gautier MMC_DEFAULT_MAX_RETRIES); 87ad71d45eSYann Gautier return -EIO; 88ad71d45eSYann Gautier } 89ad71d45eSYann Gautier 90ad71d45eSYann Gautier ret = mmc_send_cmd(MMC_CMD(13), rca << RCA_SHIFT_OFFSET, 9197d5db8cSYann Gautier MMC_RESPONSE_R1, &resp_data[0]); 92ad71d45eSYann Gautier if (ret != 0) { 93ad71d45eSYann Gautier return ret; 94ad71d45eSYann Gautier } 95ad71d45eSYann Gautier 96ad71d45eSYann Gautier if ((resp_data[0] & STATUS_SWITCH_ERROR) != 0U) { 97ad71d45eSYann Gautier return -EIO; 98ad71d45eSYann Gautier } 99ad71d45eSYann Gautier 100ad71d45eSYann Gautier retries--; 101ad71d45eSYann Gautier } while ((resp_data[0] & STATUS_READY_FOR_DATA) == 0U); 102ad71d45eSYann Gautier 103ad71d45eSYann Gautier return MMC_GET_STATE(resp_data[0]); 104ad71d45eSYann Gautier } 105ad71d45eSYann Gautier 106ad71d45eSYann Gautier static int mmc_set_ext_csd(unsigned int ext_cmd, unsigned int value) 107ad71d45eSYann Gautier { 108ad71d45eSYann Gautier int ret; 109ad71d45eSYann Gautier 110ad71d45eSYann Gautier ret = mmc_send_cmd(MMC_CMD(6), 111ad71d45eSYann Gautier EXTCSD_WRITE_BYTES | EXTCSD_CMD(ext_cmd) | 112ad71d45eSYann Gautier EXTCSD_VALUE(value) | EXTCSD_CMD_SET_NORMAL, 11361752898SBryan O'Donoghue MMC_RESPONSE_R1B, NULL); 114ad71d45eSYann Gautier if (ret != 0) { 115ad71d45eSYann Gautier return ret; 116ad71d45eSYann Gautier } 117ad71d45eSYann Gautier 118ad71d45eSYann Gautier do { 119ad71d45eSYann Gautier ret = mmc_device_state(); 120ad71d45eSYann Gautier if (ret < 0) { 121ad71d45eSYann Gautier return ret; 122ad71d45eSYann Gautier } 123ad71d45eSYann Gautier } while (ret == MMC_STATE_PRG); 124ad71d45eSYann Gautier 125ad71d45eSYann Gautier return 0; 126ad71d45eSYann Gautier } 127ad71d45eSYann Gautier 128ad71d45eSYann Gautier static int mmc_sd_switch(unsigned int bus_width) 129ad71d45eSYann Gautier { 130ad71d45eSYann Gautier int ret; 131ad71d45eSYann Gautier int retries = MMC_DEFAULT_MAX_RETRIES; 132ad71d45eSYann Gautier unsigned int scr[2] = { 0 }; 133ad71d45eSYann Gautier unsigned int bus_width_arg = 0; 134ad71d45eSYann Gautier 135ad71d45eSYann Gautier ret = ops->prepare(0, (uintptr_t)&scr, sizeof(scr)); 136ad71d45eSYann Gautier if (ret != 0) { 137ad71d45eSYann Gautier return ret; 138ad71d45eSYann Gautier } 139ad71d45eSYann Gautier 140ad71d45eSYann Gautier /* CMD55: Application Specific Command */ 141ad71d45eSYann Gautier ret = mmc_send_cmd(MMC_CMD(55), rca << RCA_SHIFT_OFFSET, 14297d5db8cSYann Gautier MMC_RESPONSE_R5, NULL); 143ad71d45eSYann Gautier if (ret != 0) { 144ad71d45eSYann Gautier return ret; 145ad71d45eSYann Gautier } 146ad71d45eSYann Gautier 147ad71d45eSYann Gautier /* ACMD51: SEND_SCR */ 148ad71d45eSYann Gautier do { 14997d5db8cSYann Gautier ret = mmc_send_cmd(MMC_ACMD(51), 0, MMC_RESPONSE_R1, NULL); 150ad71d45eSYann Gautier if ((ret != 0) && (retries == 0)) { 151ad71d45eSYann Gautier ERROR("ACMD51 failed after %d retries (ret=%d)\n", 152ad71d45eSYann Gautier MMC_DEFAULT_MAX_RETRIES, ret); 153ad71d45eSYann Gautier return ret; 154ad71d45eSYann Gautier } 155ad71d45eSYann Gautier 156ad71d45eSYann Gautier retries--; 157ad71d45eSYann Gautier } while (ret != 0); 158ad71d45eSYann Gautier 159ad71d45eSYann Gautier ret = ops->read(0, (uintptr_t)&scr, sizeof(scr)); 160ad71d45eSYann Gautier if (ret != 0) { 161ad71d45eSYann Gautier return ret; 162ad71d45eSYann Gautier } 163ad71d45eSYann Gautier 164ad71d45eSYann Gautier if (((scr[0] & SD_SCR_BUS_WIDTH_4) != 0U) && 165ad71d45eSYann Gautier (bus_width == MMC_BUS_WIDTH_4)) { 166ad71d45eSYann Gautier bus_width_arg = 2; 167ad71d45eSYann Gautier } 168ad71d45eSYann Gautier 169ad71d45eSYann Gautier /* CMD55: Application Specific Command */ 170ad71d45eSYann Gautier ret = mmc_send_cmd(MMC_CMD(55), rca << RCA_SHIFT_OFFSET, 17197d5db8cSYann Gautier MMC_RESPONSE_R5, NULL); 172ad71d45eSYann Gautier if (ret != 0) { 173ad71d45eSYann Gautier return ret; 174ad71d45eSYann Gautier } 175ad71d45eSYann Gautier 176ad71d45eSYann Gautier /* ACMD6: SET_BUS_WIDTH */ 17797d5db8cSYann Gautier ret = mmc_send_cmd(MMC_ACMD(6), bus_width_arg, MMC_RESPONSE_R1, NULL); 178ad71d45eSYann Gautier if (ret != 0) { 179ad71d45eSYann Gautier return ret; 180ad71d45eSYann Gautier } 181ad71d45eSYann Gautier 182ad71d45eSYann Gautier do { 183ad71d45eSYann Gautier ret = mmc_device_state(); 184ad71d45eSYann Gautier if (ret < 0) { 185ad71d45eSYann Gautier return ret; 186ad71d45eSYann Gautier } 187ad71d45eSYann Gautier } while (ret == MMC_STATE_PRG); 188ad71d45eSYann Gautier 189ad71d45eSYann Gautier return 0; 190ad71d45eSYann Gautier } 191ad71d45eSYann Gautier 192ad71d45eSYann Gautier static int mmc_set_ios(unsigned int clk, unsigned int bus_width) 193ad71d45eSYann Gautier { 194ad71d45eSYann Gautier int ret; 195ad71d45eSYann Gautier unsigned int width = bus_width; 196ad71d45eSYann Gautier 197ad71d45eSYann Gautier if (mmc_dev_info->mmc_dev_type != MMC_IS_EMMC) { 198ad71d45eSYann Gautier if (width == MMC_BUS_WIDTH_8) { 199ad71d45eSYann Gautier WARN("Wrong bus config for SD-card, force to 4\n"); 200ad71d45eSYann Gautier width = MMC_BUS_WIDTH_4; 201ad71d45eSYann Gautier } 202ad71d45eSYann Gautier ret = mmc_sd_switch(width); 203ad71d45eSYann Gautier if (ret != 0) { 204ad71d45eSYann Gautier return ret; 205ad71d45eSYann Gautier } 206ad71d45eSYann Gautier } else if (mmc_csd.spec_vers == 4U) { 207ad71d45eSYann Gautier ret = mmc_set_ext_csd(CMD_EXTCSD_BUS_WIDTH, 208ad71d45eSYann Gautier (unsigned int)width); 209ad71d45eSYann Gautier if (ret != 0) { 210ad71d45eSYann Gautier return ret; 211ad71d45eSYann Gautier } 212ad71d45eSYann Gautier } else { 213ad71d45eSYann Gautier VERBOSE("Wrong MMC type or spec version\n"); 214ad71d45eSYann Gautier } 215ad71d45eSYann Gautier 216ad71d45eSYann Gautier return ops->set_ios(clk, width); 217ad71d45eSYann Gautier } 218ad71d45eSYann Gautier 219ad71d45eSYann Gautier static int mmc_fill_device_info(void) 220ad71d45eSYann Gautier { 221ad71d45eSYann Gautier unsigned long long c_size; 222ad71d45eSYann Gautier unsigned int speed_idx; 223ad71d45eSYann Gautier unsigned int nb_blocks; 224ad71d45eSYann Gautier unsigned int freq_unit; 225cadb36cbSAntonio Nino Diaz int ret = 0; 226ad71d45eSYann Gautier struct mmc_csd_sd_v2 *csd_sd_v2; 227ad71d45eSYann Gautier 228ad71d45eSYann Gautier switch (mmc_dev_info->mmc_dev_type) { 229ad71d45eSYann Gautier case MMC_IS_EMMC: 230ad71d45eSYann Gautier mmc_dev_info->block_size = MMC_BLOCK_SIZE; 231ad71d45eSYann Gautier 232ad71d45eSYann Gautier ret = ops->prepare(0, (uintptr_t)&mmc_ext_csd, 233ad71d45eSYann Gautier sizeof(mmc_ext_csd)); 234ad71d45eSYann Gautier if (ret != 0) { 235ad71d45eSYann Gautier return ret; 236ad71d45eSYann Gautier } 237ad71d45eSYann Gautier 238ad71d45eSYann Gautier /* MMC CMD8: SEND_EXT_CSD */ 23997d5db8cSYann Gautier ret = mmc_send_cmd(MMC_CMD(8), 0, MMC_RESPONSE_R1, NULL); 240ad71d45eSYann Gautier if (ret != 0) { 241ad71d45eSYann Gautier return ret; 242ad71d45eSYann Gautier } 243ad71d45eSYann Gautier 244ad71d45eSYann Gautier ret = ops->read(0, (uintptr_t)&mmc_ext_csd, 245ad71d45eSYann Gautier sizeof(mmc_ext_csd)); 246ad71d45eSYann Gautier if (ret != 0) { 247ad71d45eSYann Gautier return ret; 248ad71d45eSYann Gautier } 249ad71d45eSYann Gautier 25093768644SHaojian Zhuang do { 25193768644SHaojian Zhuang ret = mmc_device_state(); 25293768644SHaojian Zhuang if (ret < 0) { 25393768644SHaojian Zhuang return ret; 25493768644SHaojian Zhuang } 25593768644SHaojian Zhuang } while (ret != MMC_STATE_TRAN); 25693768644SHaojian Zhuang 257ad71d45eSYann Gautier nb_blocks = (mmc_ext_csd[CMD_EXTCSD_SEC_CNT] << 0) | 258ad71d45eSYann Gautier (mmc_ext_csd[CMD_EXTCSD_SEC_CNT + 1] << 8) | 259ad71d45eSYann Gautier (mmc_ext_csd[CMD_EXTCSD_SEC_CNT + 2] << 16) | 260ad71d45eSYann Gautier (mmc_ext_csd[CMD_EXTCSD_SEC_CNT + 3] << 24); 261ad71d45eSYann Gautier 262ad71d45eSYann Gautier mmc_dev_info->device_size = (unsigned long long)nb_blocks * 263ad71d45eSYann Gautier mmc_dev_info->block_size; 264ad71d45eSYann Gautier 265ad71d45eSYann Gautier break; 266ad71d45eSYann Gautier 267ad71d45eSYann Gautier case MMC_IS_SD: 268ad71d45eSYann Gautier /* 269ad71d45eSYann Gautier * Use the same mmc_csd struct, as required fields here 270ad71d45eSYann Gautier * (READ_BL_LEN, C_SIZE, CSIZE_MULT) are common with eMMC. 271ad71d45eSYann Gautier */ 272ad71d45eSYann Gautier mmc_dev_info->block_size = BIT_32(mmc_csd.read_bl_len); 273ad71d45eSYann Gautier 274ad71d45eSYann Gautier c_size = ((unsigned long long)mmc_csd.c_size_high << 2U) | 275ad71d45eSYann Gautier (unsigned long long)mmc_csd.c_size_low; 276ad71d45eSYann Gautier assert(c_size != 0xFFFU); 277ad71d45eSYann Gautier 278ad71d45eSYann Gautier mmc_dev_info->device_size = (c_size + 1U) * 279ad71d45eSYann Gautier BIT_64(mmc_csd.c_size_mult + 2U) * 280ad71d45eSYann Gautier mmc_dev_info->block_size; 281ad71d45eSYann Gautier 282ad71d45eSYann Gautier break; 283ad71d45eSYann Gautier 284ad71d45eSYann Gautier case MMC_IS_SD_HC: 285ad71d45eSYann Gautier assert(mmc_csd.csd_structure == 1U); 286ad71d45eSYann Gautier 287ad71d45eSYann Gautier mmc_dev_info->block_size = MMC_BLOCK_SIZE; 288ad71d45eSYann Gautier 289ad71d45eSYann Gautier /* Need to use mmc_csd_sd_v2 struct */ 290ad71d45eSYann Gautier csd_sd_v2 = (struct mmc_csd_sd_v2 *)&mmc_csd; 291ad71d45eSYann Gautier c_size = ((unsigned long long)csd_sd_v2->c_size_high << 16) | 292ad71d45eSYann Gautier (unsigned long long)csd_sd_v2->c_size_low; 293ad71d45eSYann Gautier 294ad71d45eSYann Gautier mmc_dev_info->device_size = (c_size + 1U) << MULT_BY_512K_SHIFT; 295ad71d45eSYann Gautier 296ad71d45eSYann Gautier break; 297ad71d45eSYann Gautier 298ad71d45eSYann Gautier default: 299ad71d45eSYann Gautier ret = -EINVAL; 300ad71d45eSYann Gautier break; 301ad71d45eSYann Gautier } 302ad71d45eSYann Gautier 303*5f9984efSYann Gautier if (ret < 0) { 304ad71d45eSYann Gautier return ret; 305ad71d45eSYann Gautier } 306ad71d45eSYann Gautier 307ad71d45eSYann Gautier speed_idx = (mmc_csd.tran_speed & CSD_TRAN_SPEED_MULT_MASK) >> 308ad71d45eSYann Gautier CSD_TRAN_SPEED_MULT_SHIFT; 309ad71d45eSYann Gautier 310ad71d45eSYann Gautier assert(speed_idx > 0U); 311ad71d45eSYann Gautier 312ad71d45eSYann Gautier if (mmc_dev_info->mmc_dev_type == MMC_IS_EMMC) { 313ad71d45eSYann Gautier mmc_dev_info->max_bus_freq = tran_speed_base[speed_idx]; 314ad71d45eSYann Gautier } else { 315ad71d45eSYann Gautier mmc_dev_info->max_bus_freq = sd_tran_speed_base[speed_idx]; 316ad71d45eSYann Gautier } 317ad71d45eSYann Gautier 318ad71d45eSYann Gautier freq_unit = mmc_csd.tran_speed & CSD_TRAN_SPEED_UNIT_MASK; 319ad71d45eSYann Gautier while (freq_unit != 0U) { 320ad71d45eSYann Gautier mmc_dev_info->max_bus_freq *= 10U; 321ad71d45eSYann Gautier --freq_unit; 322ad71d45eSYann Gautier } 323ad71d45eSYann Gautier 324ad71d45eSYann Gautier mmc_dev_info->max_bus_freq *= 10000U; 325ad71d45eSYann Gautier 326ad71d45eSYann Gautier return 0; 327ad71d45eSYann Gautier } 328ad71d45eSYann Gautier 329ad71d45eSYann Gautier static int sd_send_op_cond(void) 330ad71d45eSYann Gautier { 33115e913d4SYann Gautier int n; 332ad71d45eSYann Gautier unsigned int resp_data[4]; 333ad71d45eSYann Gautier 33415e913d4SYann Gautier for (n = 0; n < SEND_OP_COND_MAX_RETRIES; n++) { 335ad71d45eSYann Gautier int ret; 336ad71d45eSYann Gautier 337ad71d45eSYann Gautier /* CMD55: Application Specific Command */ 33897d5db8cSYann Gautier ret = mmc_send_cmd(MMC_CMD(55), 0, MMC_RESPONSE_R1, NULL); 339ad71d45eSYann Gautier if (ret != 0) { 340ad71d45eSYann Gautier return ret; 341ad71d45eSYann Gautier } 342ad71d45eSYann Gautier 343ad71d45eSYann Gautier /* ACMD41: SD_SEND_OP_COND */ 34494522ff7SBryan O'Donoghue ret = mmc_send_cmd(MMC_ACMD(41), OCR_HCS, MMC_RESPONSE_R3, 345ad71d45eSYann Gautier &resp_data[0]); 346ad71d45eSYann Gautier if (ret != 0) { 347ad71d45eSYann Gautier return ret; 348ad71d45eSYann Gautier } 349ad71d45eSYann Gautier 35015e913d4SYann Gautier if ((resp_data[0] & OCR_POWERUP) != 0U) { 351ad71d45eSYann Gautier mmc_ocr_value = resp_data[0]; 352ad71d45eSYann Gautier 353ad71d45eSYann Gautier if ((mmc_ocr_value & OCR_HCS) != 0U) { 354ad71d45eSYann Gautier mmc_dev_info->mmc_dev_type = MMC_IS_SD_HC; 355ad71d45eSYann Gautier } else { 356ad71d45eSYann Gautier mmc_dev_info->mmc_dev_type = MMC_IS_SD; 357ad71d45eSYann Gautier } 358ad71d45eSYann Gautier 359ad71d45eSYann Gautier return 0; 360ad71d45eSYann Gautier } 361ad71d45eSYann Gautier 36215e913d4SYann Gautier mdelay(1); 36315e913d4SYann Gautier } 36415e913d4SYann Gautier 36515e913d4SYann Gautier ERROR("ACMD41 failed after %d retries\n", SEND_OP_COND_MAX_RETRIES); 36615e913d4SYann Gautier 36715e913d4SYann Gautier return -EIO; 36815e913d4SYann Gautier } 36915e913d4SYann Gautier 37015e913d4SYann Gautier static int mmc_reset_to_idle(void) 371ad71d45eSYann Gautier { 372ad71d45eSYann Gautier int ret; 37315e913d4SYann Gautier 374ad71d45eSYann Gautier /* CMD0: reset to IDLE */ 375ad71d45eSYann Gautier ret = mmc_send_cmd(MMC_CMD(0), 0, 0, NULL); 376ad71d45eSYann Gautier if (ret != 0) { 377ad71d45eSYann Gautier return ret; 378ad71d45eSYann Gautier } 379ad71d45eSYann Gautier 38015e913d4SYann Gautier mdelay(2); 38115e913d4SYann Gautier 38215e913d4SYann Gautier return 0; 383ad71d45eSYann Gautier } 384ad71d45eSYann Gautier 38515e913d4SYann Gautier static int mmc_send_op_cond(void) 38615e913d4SYann Gautier { 38715e913d4SYann Gautier int ret, n; 38815e913d4SYann Gautier unsigned int resp_data[4]; 38915e913d4SYann Gautier 39077614a99SYann Gautier ret = mmc_reset_to_idle(); 39177614a99SYann Gautier if (ret != 0) { 39277614a99SYann Gautier return ret; 39377614a99SYann Gautier }; 39415e913d4SYann Gautier 39515e913d4SYann Gautier for (n = 0; n < SEND_OP_COND_MAX_RETRIES; n++) { 396ad71d45eSYann Gautier ret = mmc_send_cmd(MMC_CMD(1), OCR_SECTOR_MODE | 397ad71d45eSYann Gautier OCR_VDD_MIN_2V7 | OCR_VDD_MIN_1V7, 39894522ff7SBryan O'Donoghue MMC_RESPONSE_R3, &resp_data[0]); 399ad71d45eSYann Gautier if (ret != 0) { 400ad71d45eSYann Gautier return ret; 401ad71d45eSYann Gautier } 402ad71d45eSYann Gautier 40315e913d4SYann Gautier if ((resp_data[0] & OCR_POWERUP) != 0U) { 404ad71d45eSYann Gautier mmc_ocr_value = resp_data[0]; 405ad71d45eSYann Gautier return 0; 406ad71d45eSYann Gautier } 407ad71d45eSYann Gautier 4087d639429SJoakim Bech mdelay(10); 40915e913d4SYann Gautier } 41015e913d4SYann Gautier 41115e913d4SYann Gautier ERROR("CMD1 failed after %d retries\n", SEND_OP_COND_MAX_RETRIES); 41215e913d4SYann Gautier 41315e913d4SYann Gautier return -EIO; 41415e913d4SYann Gautier } 41515e913d4SYann Gautier 416ad71d45eSYann Gautier static int mmc_enumerate(unsigned int clk, unsigned int bus_width) 417ad71d45eSYann Gautier { 418ad71d45eSYann Gautier int ret; 419ad71d45eSYann Gautier unsigned int resp_data[4]; 420ad71d45eSYann Gautier 421ad71d45eSYann Gautier ops->init(); 422ad71d45eSYann Gautier 42377614a99SYann Gautier ret = mmc_reset_to_idle(); 42477614a99SYann Gautier if (ret != 0) { 42577614a99SYann Gautier return ret; 42677614a99SYann Gautier }; 427ad71d45eSYann Gautier 428e74dc940SHaojian Zhuang if (mmc_dev_info->mmc_dev_type == MMC_IS_EMMC) { 429e74dc940SHaojian Zhuang ret = mmc_send_op_cond(); 430e74dc940SHaojian Zhuang } else { 431ad71d45eSYann Gautier /* CMD8: Send Interface Condition Command */ 432ad71d45eSYann Gautier ret = mmc_send_cmd(MMC_CMD(8), VHS_2_7_3_6_V | CMD8_CHECK_PATTERN, 43397d5db8cSYann Gautier MMC_RESPONSE_R5, &resp_data[0]); 434ad71d45eSYann Gautier 435ad71d45eSYann Gautier if ((ret == 0) && ((resp_data[0] & 0xffU) == CMD8_CHECK_PATTERN)) { 436ad71d45eSYann Gautier ret = sd_send_op_cond(); 437e74dc940SHaojian Zhuang } 438ad71d45eSYann Gautier } 439ad71d45eSYann Gautier if (ret != 0) { 440ad71d45eSYann Gautier return ret; 441ad71d45eSYann Gautier } 442ad71d45eSYann Gautier 443ad71d45eSYann Gautier /* CMD2: Card Identification */ 444a2a69bc8SShawn Guo ret = mmc_send_cmd(MMC_CMD(2), 0, MMC_RESPONSE_R2, NULL); 445ad71d45eSYann Gautier if (ret != 0) { 446ad71d45eSYann Gautier return ret; 447ad71d45eSYann Gautier } 448ad71d45eSYann Gautier 449ad71d45eSYann Gautier /* CMD3: Set Relative Address */ 450ad71d45eSYann Gautier if (mmc_dev_info->mmc_dev_type == MMC_IS_EMMC) { 451ad71d45eSYann Gautier rca = MMC_FIX_RCA; 452ad71d45eSYann Gautier ret = mmc_send_cmd(MMC_CMD(3), rca << RCA_SHIFT_OFFSET, 45397d5db8cSYann Gautier MMC_RESPONSE_R1, NULL); 454ad71d45eSYann Gautier if (ret != 0) { 455ad71d45eSYann Gautier return ret; 456ad71d45eSYann Gautier } 457ad71d45eSYann Gautier } else { 458ad71d45eSYann Gautier ret = mmc_send_cmd(MMC_CMD(3), 0, 45997d5db8cSYann Gautier MMC_RESPONSE_R6, &resp_data[0]); 460ad71d45eSYann Gautier if (ret != 0) { 461ad71d45eSYann Gautier return ret; 462ad71d45eSYann Gautier } 463ad71d45eSYann Gautier 464ad71d45eSYann Gautier rca = (resp_data[0] & 0xFFFF0000U) >> 16; 465ad71d45eSYann Gautier } 466ad71d45eSYann Gautier 467ad71d45eSYann Gautier /* CMD9: CSD Register */ 468ad71d45eSYann Gautier ret = mmc_send_cmd(MMC_CMD(9), rca << RCA_SHIFT_OFFSET, 469a2a69bc8SShawn Guo MMC_RESPONSE_R2, &resp_data[0]); 470ad71d45eSYann Gautier if (ret != 0) { 471ad71d45eSYann Gautier return ret; 472ad71d45eSYann Gautier } 473ad71d45eSYann Gautier 474ad71d45eSYann Gautier memcpy(&mmc_csd, &resp_data, sizeof(resp_data)); 475ad71d45eSYann Gautier 476ad71d45eSYann Gautier /* CMD7: Select Card */ 477ad71d45eSYann Gautier ret = mmc_send_cmd(MMC_CMD(7), rca << RCA_SHIFT_OFFSET, 47897d5db8cSYann Gautier MMC_RESPONSE_R1, NULL); 479ad71d45eSYann Gautier if (ret != 0) { 480ad71d45eSYann Gautier return ret; 481ad71d45eSYann Gautier } 482ad71d45eSYann Gautier 483ad71d45eSYann Gautier do { 484ad71d45eSYann Gautier ret = mmc_device_state(); 485ad71d45eSYann Gautier if (ret < 0) { 486ad71d45eSYann Gautier return ret; 487ad71d45eSYann Gautier } 488ad71d45eSYann Gautier } while (ret != MMC_STATE_TRAN); 489ad71d45eSYann Gautier 490bd4e3deeSHaojian Zhuang ret = mmc_set_ios(clk, bus_width); 491ad71d45eSYann Gautier if (ret != 0) { 492ad71d45eSYann Gautier return ret; 493ad71d45eSYann Gautier } 494ad71d45eSYann Gautier 495bd4e3deeSHaojian Zhuang return mmc_fill_device_info(); 496ad71d45eSYann Gautier } 497ad71d45eSYann Gautier 498ea315a69SHaojian Zhuang size_t mmc_read_blocks(int lba, uintptr_t buf, size_t size) 499ad71d45eSYann Gautier { 500ad71d45eSYann Gautier int ret; 501ad71d45eSYann Gautier unsigned int cmd_idx, cmd_arg; 502ad71d45eSYann Gautier 503ad71d45eSYann Gautier assert((ops != NULL) && 504ad71d45eSYann Gautier (ops->read != NULL) && 505ad71d45eSYann Gautier (size != 0U) && 506ad71d45eSYann Gautier ((size & MMC_BLOCK_MASK) == 0U)); 507ad71d45eSYann Gautier 508ad71d45eSYann Gautier ret = ops->prepare(lba, buf, size); 509ad71d45eSYann Gautier if (ret != 0) { 510ad71d45eSYann Gautier return 0; 511ad71d45eSYann Gautier } 512ad71d45eSYann Gautier 513ad71d45eSYann Gautier if (is_cmd23_enabled()) { 514ad71d45eSYann Gautier /* Set block count */ 515ad71d45eSYann Gautier ret = mmc_send_cmd(MMC_CMD(23), size / MMC_BLOCK_SIZE, 51697d5db8cSYann Gautier MMC_RESPONSE_R1, NULL); 517ad71d45eSYann Gautier if (ret != 0) { 518ad71d45eSYann Gautier return 0; 519ad71d45eSYann Gautier } 520ad71d45eSYann Gautier 521ad71d45eSYann Gautier cmd_idx = MMC_CMD(18); 522ad71d45eSYann Gautier } else { 523ad71d45eSYann Gautier if (size > MMC_BLOCK_SIZE) { 524ad71d45eSYann Gautier cmd_idx = MMC_CMD(18); 525ad71d45eSYann Gautier } else { 526ad71d45eSYann Gautier cmd_idx = MMC_CMD(17); 527ad71d45eSYann Gautier } 528ad71d45eSYann Gautier } 529ad71d45eSYann Gautier 530ad71d45eSYann Gautier if (((mmc_ocr_value & OCR_ACCESS_MODE_MASK) == OCR_BYTE_MODE) && 531ad71d45eSYann Gautier (mmc_dev_info->mmc_dev_type != MMC_IS_SD_HC)) { 532ad71d45eSYann Gautier cmd_arg = lba * MMC_BLOCK_SIZE; 533ad71d45eSYann Gautier } else { 534ad71d45eSYann Gautier cmd_arg = lba; 535ad71d45eSYann Gautier } 536ad71d45eSYann Gautier 53797d5db8cSYann Gautier ret = mmc_send_cmd(cmd_idx, cmd_arg, MMC_RESPONSE_R1, NULL); 538ad71d45eSYann Gautier if (ret != 0) { 539ad71d45eSYann Gautier return 0; 540ad71d45eSYann Gautier } 541ad71d45eSYann Gautier 542ad71d45eSYann Gautier ret = ops->read(lba, buf, size); 543ad71d45eSYann Gautier if (ret != 0) { 544ad71d45eSYann Gautier return 0; 545ad71d45eSYann Gautier } 546ad71d45eSYann Gautier 547ad71d45eSYann Gautier /* Wait buffer empty */ 548ad71d45eSYann Gautier do { 549ad71d45eSYann Gautier ret = mmc_device_state(); 550ad71d45eSYann Gautier if (ret < 0) { 551ad71d45eSYann Gautier return 0; 552ad71d45eSYann Gautier } 553ad71d45eSYann Gautier } while ((ret != MMC_STATE_TRAN) && (ret != MMC_STATE_DATA)); 554ad71d45eSYann Gautier 555ad71d45eSYann Gautier if (!is_cmd23_enabled() && (size > MMC_BLOCK_SIZE)) { 55661752898SBryan O'Donoghue ret = mmc_send_cmd(MMC_CMD(12), 0, MMC_RESPONSE_R1B, NULL); 557ad71d45eSYann Gautier if (ret != 0) { 558ad71d45eSYann Gautier return 0; 559ad71d45eSYann Gautier } 560ad71d45eSYann Gautier } 561ad71d45eSYann Gautier 562ad71d45eSYann Gautier return size; 563ad71d45eSYann Gautier } 564ad71d45eSYann Gautier 565ea315a69SHaojian Zhuang size_t mmc_write_blocks(int lba, const uintptr_t buf, size_t size) 566ad71d45eSYann Gautier { 567ad71d45eSYann Gautier int ret; 568ad71d45eSYann Gautier unsigned int cmd_idx, cmd_arg; 569ad71d45eSYann Gautier 570ad71d45eSYann Gautier assert((ops != NULL) && 571ad71d45eSYann Gautier (ops->write != NULL) && 572ad71d45eSYann Gautier (size != 0U) && 573ad71d45eSYann Gautier ((buf & MMC_BLOCK_MASK) == 0U) && 574ad71d45eSYann Gautier ((size & MMC_BLOCK_MASK) == 0U)); 575ad71d45eSYann Gautier 576ad71d45eSYann Gautier ret = ops->prepare(lba, buf, size); 577ad71d45eSYann Gautier if (ret != 0) { 578ad71d45eSYann Gautier return 0; 579ad71d45eSYann Gautier } 580ad71d45eSYann Gautier 581ad71d45eSYann Gautier if (is_cmd23_enabled()) { 582ad71d45eSYann Gautier /* Set block count */ 583ad71d45eSYann Gautier ret = mmc_send_cmd(MMC_CMD(23), size / MMC_BLOCK_SIZE, 58497d5db8cSYann Gautier MMC_RESPONSE_R1, NULL); 585ad71d45eSYann Gautier if (ret != 0) { 586ad71d45eSYann Gautier return 0; 587ad71d45eSYann Gautier } 588ad71d45eSYann Gautier 589ad71d45eSYann Gautier cmd_idx = MMC_CMD(25); 590ad71d45eSYann Gautier } else { 591ad71d45eSYann Gautier if (size > MMC_BLOCK_SIZE) { 592ad71d45eSYann Gautier cmd_idx = MMC_CMD(25); 593ad71d45eSYann Gautier } else { 594ad71d45eSYann Gautier cmd_idx = MMC_CMD(24); 595ad71d45eSYann Gautier } 596ad71d45eSYann Gautier } 597ad71d45eSYann Gautier 598ad71d45eSYann Gautier if ((mmc_ocr_value & OCR_ACCESS_MODE_MASK) == OCR_BYTE_MODE) { 599ad71d45eSYann Gautier cmd_arg = lba * MMC_BLOCK_SIZE; 600ad71d45eSYann Gautier } else { 601ad71d45eSYann Gautier cmd_arg = lba; 602ad71d45eSYann Gautier } 603ad71d45eSYann Gautier 60497d5db8cSYann Gautier ret = mmc_send_cmd(cmd_idx, cmd_arg, MMC_RESPONSE_R1, NULL); 605ad71d45eSYann Gautier if (ret != 0) { 606ad71d45eSYann Gautier return 0; 607ad71d45eSYann Gautier } 608ad71d45eSYann Gautier 609ad71d45eSYann Gautier ret = ops->write(lba, buf, size); 610ad71d45eSYann Gautier if (ret != 0) { 611ad71d45eSYann Gautier return 0; 612ad71d45eSYann Gautier } 613ad71d45eSYann Gautier 614ad71d45eSYann Gautier /* Wait buffer empty */ 615ad71d45eSYann Gautier do { 616ad71d45eSYann Gautier ret = mmc_device_state(); 617ad71d45eSYann Gautier if (ret < 0) { 618ad71d45eSYann Gautier return 0; 619ad71d45eSYann Gautier } 620ad71d45eSYann Gautier } while ((ret != MMC_STATE_TRAN) && (ret != MMC_STATE_RCV)); 621ad71d45eSYann Gautier 622ad71d45eSYann Gautier if (!is_cmd23_enabled() && (size > MMC_BLOCK_SIZE)) { 62361752898SBryan O'Donoghue ret = mmc_send_cmd(MMC_CMD(12), 0, MMC_RESPONSE_R1B, NULL); 624ad71d45eSYann Gautier if (ret != 0) { 625ad71d45eSYann Gautier return 0; 626ad71d45eSYann Gautier } 627ad71d45eSYann Gautier } 628ad71d45eSYann Gautier 629ad71d45eSYann Gautier return size; 630ad71d45eSYann Gautier } 631ad71d45eSYann Gautier 632ea315a69SHaojian Zhuang size_t mmc_erase_blocks(int lba, size_t size) 633ad71d45eSYann Gautier { 634ad71d45eSYann Gautier int ret; 635ad71d45eSYann Gautier 636ad71d45eSYann Gautier assert(ops != NULL); 637ad71d45eSYann Gautier assert((size != 0U) && ((size & MMC_BLOCK_MASK) == 0U)); 638ad71d45eSYann Gautier 63997d5db8cSYann Gautier ret = mmc_send_cmd(MMC_CMD(35), lba, MMC_RESPONSE_R1, NULL); 640ad71d45eSYann Gautier if (ret != 0) { 641ad71d45eSYann Gautier return 0; 642ad71d45eSYann Gautier } 643ad71d45eSYann Gautier 644ad71d45eSYann Gautier ret = mmc_send_cmd(MMC_CMD(36), lba + (size / MMC_BLOCK_SIZE) - 1U, 64597d5db8cSYann Gautier MMC_RESPONSE_R1, NULL); 646ad71d45eSYann Gautier if (ret != 0) { 647ad71d45eSYann Gautier return 0; 648ad71d45eSYann Gautier } 649ad71d45eSYann Gautier 65097d5db8cSYann Gautier ret = mmc_send_cmd(MMC_CMD(38), lba, MMC_RESPONSE_R1B, NULL); 651ad71d45eSYann Gautier if (ret != 0) { 652ad71d45eSYann Gautier return 0; 653ad71d45eSYann Gautier } 654ad71d45eSYann Gautier 655ad71d45eSYann Gautier do { 656ad71d45eSYann Gautier ret = mmc_device_state(); 657ad71d45eSYann Gautier if (ret < 0) { 658ad71d45eSYann Gautier return 0; 659ad71d45eSYann Gautier } 660ad71d45eSYann Gautier } while (ret != MMC_STATE_TRAN); 661ad71d45eSYann Gautier 662ad71d45eSYann Gautier return size; 663ad71d45eSYann Gautier } 664ad71d45eSYann Gautier 665ad71d45eSYann Gautier static inline void mmc_rpmb_enable(void) 666ad71d45eSYann Gautier { 667ad71d45eSYann Gautier mmc_set_ext_csd(CMD_EXTCSD_PARTITION_CONFIG, 668ad71d45eSYann Gautier PART_CFG_BOOT_PARTITION1_ENABLE | 669ad71d45eSYann Gautier PART_CFG_PARTITION1_ACCESS); 670ad71d45eSYann Gautier } 671ad71d45eSYann Gautier 672ad71d45eSYann Gautier static inline void mmc_rpmb_disable(void) 673ad71d45eSYann Gautier { 674ad71d45eSYann Gautier mmc_set_ext_csd(CMD_EXTCSD_PARTITION_CONFIG, 675ad71d45eSYann Gautier PART_CFG_BOOT_PARTITION1_ENABLE); 676ad71d45eSYann Gautier } 677ad71d45eSYann Gautier 678ea315a69SHaojian Zhuang size_t mmc_rpmb_read_blocks(int lba, uintptr_t buf, size_t size) 679ad71d45eSYann Gautier { 680ad71d45eSYann Gautier size_t size_read; 681ad71d45eSYann Gautier 682ad71d45eSYann Gautier mmc_rpmb_enable(); 683ad71d45eSYann Gautier size_read = mmc_read_blocks(lba, buf, size); 684ad71d45eSYann Gautier mmc_rpmb_disable(); 685ad71d45eSYann Gautier 686ad71d45eSYann Gautier return size_read; 687ad71d45eSYann Gautier } 688ad71d45eSYann Gautier 689ea315a69SHaojian Zhuang size_t mmc_rpmb_write_blocks(int lba, const uintptr_t buf, size_t size) 690ad71d45eSYann Gautier { 691ad71d45eSYann Gautier size_t size_written; 692ad71d45eSYann Gautier 693ad71d45eSYann Gautier mmc_rpmb_enable(); 694ad71d45eSYann Gautier size_written = mmc_write_blocks(lba, buf, size); 695ad71d45eSYann Gautier mmc_rpmb_disable(); 696ad71d45eSYann Gautier 697ad71d45eSYann Gautier return size_written; 698ad71d45eSYann Gautier } 699ad71d45eSYann Gautier 700ea315a69SHaojian Zhuang size_t mmc_rpmb_erase_blocks(int lba, size_t size) 701ad71d45eSYann Gautier { 702ad71d45eSYann Gautier size_t size_erased; 703ad71d45eSYann Gautier 704ad71d45eSYann Gautier mmc_rpmb_enable(); 705ad71d45eSYann Gautier size_erased = mmc_erase_blocks(lba, size); 706ad71d45eSYann Gautier mmc_rpmb_disable(); 707ad71d45eSYann Gautier 708ad71d45eSYann Gautier return size_erased; 709ad71d45eSYann Gautier } 710ad71d45eSYann Gautier 711ad71d45eSYann Gautier int mmc_init(const struct mmc_ops *ops_ptr, unsigned int clk, 712ad71d45eSYann Gautier unsigned int width, unsigned int flags, 713ad71d45eSYann Gautier struct mmc_device_info *device_info) 714ad71d45eSYann Gautier { 715ad71d45eSYann Gautier assert((ops_ptr != NULL) && 716ad71d45eSYann Gautier (ops_ptr->init != NULL) && 717ad71d45eSYann Gautier (ops_ptr->send_cmd != NULL) && 718ad71d45eSYann Gautier (ops_ptr->set_ios != NULL) && 719ad71d45eSYann Gautier (ops_ptr->prepare != NULL) && 720ad71d45eSYann Gautier (ops_ptr->read != NULL) && 721ad71d45eSYann Gautier (ops_ptr->write != NULL) && 722ad71d45eSYann Gautier (device_info != NULL) && 723ad71d45eSYann Gautier (clk != 0) && 724ad71d45eSYann Gautier ((width == MMC_BUS_WIDTH_1) || 725ad71d45eSYann Gautier (width == MMC_BUS_WIDTH_4) || 726ad71d45eSYann Gautier (width == MMC_BUS_WIDTH_8) || 727ad71d45eSYann Gautier (width == MMC_BUS_WIDTH_DDR_4) || 728ad71d45eSYann Gautier (width == MMC_BUS_WIDTH_DDR_8))); 729ad71d45eSYann Gautier 730ad71d45eSYann Gautier ops = ops_ptr; 731ad71d45eSYann Gautier mmc_flags = flags; 732ad71d45eSYann Gautier mmc_dev_info = device_info; 733ad71d45eSYann Gautier 734ad71d45eSYann Gautier return mmc_enumerate(clk, width); 735ad71d45eSYann Gautier } 736