1ad71d45eSYann Gautier /* 2ad71d45eSYann Gautier * Copyright (c) 2018, 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 <arch_helpers.h> 10ad71d45eSYann Gautier #include <assert.h> 11ad71d45eSYann Gautier #include <debug.h> 1215e913d4SYann Gautier #include <delay_timer.h> 13ad71d45eSYann Gautier #include <errno.h> 14ad71d45eSYann Gautier #include <mmc.h> 15ad71d45eSYann Gautier #include <stdbool.h> 16ad71d45eSYann Gautier #include <string.h> 17ad71d45eSYann Gautier #include <utils.h> 18ad71d45eSYann Gautier 19ad71d45eSYann Gautier #define MMC_DEFAULT_MAX_RETRIES 5 20ad71d45eSYann Gautier #define SEND_OP_COND_MAX_RETRIES 100 21ad71d45eSYann Gautier 22ad71d45eSYann Gautier #define MULT_BY_512K_SHIFT 19 23ad71d45eSYann Gautier 24ad71d45eSYann Gautier static const struct mmc_ops *ops; 25ad71d45eSYann Gautier static unsigned int mmc_ocr_value; 26ad71d45eSYann Gautier static struct mmc_csd_emmc mmc_csd; 2707858dd8SHaojian Zhuang static unsigned char mmc_ext_csd[512] __aligned(16); 28ad71d45eSYann Gautier static unsigned int mmc_flags; 29ad71d45eSYann Gautier static struct mmc_device_info *mmc_dev_info; 30ad71d45eSYann Gautier static unsigned int rca; 31ad71d45eSYann Gautier 32ad71d45eSYann Gautier static const unsigned char tran_speed_base[16] = { 33ad71d45eSYann Gautier 0, 10, 12, 13, 15, 20, 26, 30, 35, 40, 45, 52, 55, 60, 70, 80 34ad71d45eSYann Gautier }; 35ad71d45eSYann Gautier 36ad71d45eSYann Gautier static const unsigned char sd_tran_speed_base[16] = { 37ad71d45eSYann Gautier 0, 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80 38ad71d45eSYann Gautier }; 39ad71d45eSYann Gautier 40ad71d45eSYann Gautier static bool is_cmd23_enabled(void) 41ad71d45eSYann Gautier { 42ad71d45eSYann Gautier return ((mmc_flags & MMC_FLAG_CMD23) != 0U); 43ad71d45eSYann Gautier } 44ad71d45eSYann Gautier 45ad71d45eSYann Gautier static int mmc_send_cmd(unsigned int idx, unsigned int arg, 46ad71d45eSYann Gautier unsigned int r_type, unsigned int *r_data) 47ad71d45eSYann Gautier { 48ad71d45eSYann Gautier struct mmc_cmd cmd; 49ad71d45eSYann Gautier int ret; 50ad71d45eSYann Gautier 51ad71d45eSYann Gautier zeromem(&cmd, sizeof(struct mmc_cmd)); 52ad71d45eSYann Gautier 53ad71d45eSYann Gautier cmd.cmd_idx = idx; 54ad71d45eSYann Gautier cmd.cmd_arg = arg; 55ad71d45eSYann Gautier cmd.resp_type = r_type; 56ad71d45eSYann Gautier 57ad71d45eSYann Gautier ret = ops->send_cmd(&cmd); 58ad71d45eSYann Gautier 59ad71d45eSYann Gautier if ((ret == 0) && (r_data != NULL)) { 60ad71d45eSYann Gautier int i; 61ad71d45eSYann Gautier 62ad71d45eSYann Gautier for (i = 0; i < 4; i++) { 63ad71d45eSYann Gautier *r_data = cmd.resp_data[i]; 64ad71d45eSYann Gautier r_data++; 65ad71d45eSYann Gautier } 66ad71d45eSYann Gautier } 67ad71d45eSYann Gautier 68ad71d45eSYann Gautier if (ret != 0) { 69ad71d45eSYann Gautier VERBOSE("Send command %u error: %d\n", idx, ret); 70ad71d45eSYann Gautier } 71ad71d45eSYann Gautier 72ad71d45eSYann Gautier return ret; 73ad71d45eSYann Gautier } 74ad71d45eSYann Gautier 75ad71d45eSYann Gautier static int mmc_device_state(void) 76ad71d45eSYann Gautier { 77ad71d45eSYann Gautier int retries = MMC_DEFAULT_MAX_RETRIES; 78ad71d45eSYann Gautier unsigned int resp_data[4]; 79ad71d45eSYann Gautier 80ad71d45eSYann Gautier do { 81ad71d45eSYann Gautier int ret; 82ad71d45eSYann Gautier 83ad71d45eSYann Gautier if (retries == 0) { 84ad71d45eSYann Gautier ERROR("CMD13 failed after %d retries\n", 85ad71d45eSYann Gautier MMC_DEFAULT_MAX_RETRIES); 86ad71d45eSYann Gautier return -EIO; 87ad71d45eSYann Gautier } 88ad71d45eSYann Gautier 89ad71d45eSYann Gautier ret = mmc_send_cmd(MMC_CMD(13), rca << RCA_SHIFT_OFFSET, 90ad71d45eSYann Gautier MMC_RESPONSE_R(1), &resp_data[0]); 91ad71d45eSYann Gautier if (ret != 0) { 92ad71d45eSYann Gautier return ret; 93ad71d45eSYann Gautier } 94ad71d45eSYann Gautier 95ad71d45eSYann Gautier if ((resp_data[0] & STATUS_SWITCH_ERROR) != 0U) { 96ad71d45eSYann Gautier return -EIO; 97ad71d45eSYann Gautier } 98ad71d45eSYann Gautier 99ad71d45eSYann Gautier retries--; 100ad71d45eSYann Gautier } while ((resp_data[0] & STATUS_READY_FOR_DATA) == 0U); 101ad71d45eSYann Gautier 102ad71d45eSYann Gautier return MMC_GET_STATE(resp_data[0]); 103ad71d45eSYann Gautier } 104ad71d45eSYann Gautier 105ad71d45eSYann Gautier static int mmc_set_ext_csd(unsigned int ext_cmd, unsigned int value) 106ad71d45eSYann Gautier { 107ad71d45eSYann Gautier int ret; 108ad71d45eSYann Gautier 109ad71d45eSYann Gautier ret = mmc_send_cmd(MMC_CMD(6), 110ad71d45eSYann Gautier EXTCSD_WRITE_BYTES | EXTCSD_CMD(ext_cmd) | 111ad71d45eSYann Gautier EXTCSD_VALUE(value) | EXTCSD_CMD_SET_NORMAL, 112ad71d45eSYann Gautier 0, NULL); 113ad71d45eSYann Gautier if (ret != 0) { 114ad71d45eSYann Gautier return ret; 115ad71d45eSYann Gautier } 116ad71d45eSYann Gautier 117ad71d45eSYann Gautier do { 118ad71d45eSYann Gautier ret = mmc_device_state(); 119ad71d45eSYann Gautier if (ret < 0) { 120ad71d45eSYann Gautier return ret; 121ad71d45eSYann Gautier } 122ad71d45eSYann Gautier } while (ret == MMC_STATE_PRG); 123ad71d45eSYann Gautier 124ad71d45eSYann Gautier return 0; 125ad71d45eSYann Gautier } 126ad71d45eSYann Gautier 127ad71d45eSYann Gautier static int mmc_sd_switch(unsigned int bus_width) 128ad71d45eSYann Gautier { 129ad71d45eSYann Gautier int ret; 130ad71d45eSYann Gautier int retries = MMC_DEFAULT_MAX_RETRIES; 131ad71d45eSYann Gautier unsigned int scr[2] = { 0 }; 132ad71d45eSYann Gautier unsigned int bus_width_arg = 0; 133ad71d45eSYann Gautier 134ad71d45eSYann Gautier ret = ops->prepare(0, (uintptr_t)&scr, sizeof(scr)); 135ad71d45eSYann Gautier if (ret != 0) { 136ad71d45eSYann Gautier return ret; 137ad71d45eSYann Gautier } 138ad71d45eSYann Gautier 139ad71d45eSYann Gautier /* CMD55: Application Specific Command */ 140ad71d45eSYann Gautier ret = mmc_send_cmd(MMC_CMD(55), rca << RCA_SHIFT_OFFSET, 141ad71d45eSYann Gautier MMC_RESPONSE_R(1), NULL); 142ad71d45eSYann Gautier if (ret != 0) { 143ad71d45eSYann Gautier return ret; 144ad71d45eSYann Gautier } 145ad71d45eSYann Gautier 146ad71d45eSYann Gautier /* ACMD51: SEND_SCR */ 147ad71d45eSYann Gautier do { 148ad71d45eSYann Gautier ret = mmc_send_cmd(MMC_ACMD(51), 0, MMC_RESPONSE_R(1), NULL); 149ad71d45eSYann Gautier if ((ret != 0) && (retries == 0)) { 150ad71d45eSYann Gautier ERROR("ACMD51 failed after %d retries (ret=%d)\n", 151ad71d45eSYann Gautier MMC_DEFAULT_MAX_RETRIES, ret); 152ad71d45eSYann Gautier return ret; 153ad71d45eSYann Gautier } 154ad71d45eSYann Gautier 155ad71d45eSYann Gautier retries--; 156ad71d45eSYann Gautier } while (ret != 0); 157ad71d45eSYann Gautier 158ad71d45eSYann Gautier ret = ops->read(0, (uintptr_t)&scr, sizeof(scr)); 159ad71d45eSYann Gautier if (ret != 0) { 160ad71d45eSYann Gautier return ret; 161ad71d45eSYann Gautier } 162ad71d45eSYann Gautier 163ad71d45eSYann Gautier if (((scr[0] & SD_SCR_BUS_WIDTH_4) != 0U) && 164ad71d45eSYann Gautier (bus_width == MMC_BUS_WIDTH_4)) { 165ad71d45eSYann Gautier bus_width_arg = 2; 166ad71d45eSYann Gautier } 167ad71d45eSYann Gautier 168ad71d45eSYann Gautier /* CMD55: Application Specific Command */ 169ad71d45eSYann Gautier ret = mmc_send_cmd(MMC_CMD(55), rca << RCA_SHIFT_OFFSET, 170ad71d45eSYann Gautier MMC_RESPONSE_R(1), NULL); 171ad71d45eSYann Gautier if (ret != 0) { 172ad71d45eSYann Gautier return ret; 173ad71d45eSYann Gautier } 174ad71d45eSYann Gautier 175ad71d45eSYann Gautier /* ACMD6: SET_BUS_WIDTH */ 176ad71d45eSYann Gautier ret = mmc_send_cmd(MMC_ACMD(6), bus_width_arg, MMC_RESPONSE_R(1), NULL); 177ad71d45eSYann Gautier if (ret != 0) { 178ad71d45eSYann Gautier return ret; 179ad71d45eSYann Gautier } 180ad71d45eSYann Gautier 181ad71d45eSYann Gautier do { 182ad71d45eSYann Gautier ret = mmc_device_state(); 183ad71d45eSYann Gautier if (ret < 0) { 184ad71d45eSYann Gautier return ret; 185ad71d45eSYann Gautier } 186ad71d45eSYann Gautier } while (ret == MMC_STATE_PRG); 187ad71d45eSYann Gautier 188ad71d45eSYann Gautier return 0; 189ad71d45eSYann Gautier } 190ad71d45eSYann Gautier 191ad71d45eSYann Gautier static int mmc_set_ios(unsigned int clk, unsigned int bus_width) 192ad71d45eSYann Gautier { 193ad71d45eSYann Gautier int ret; 194ad71d45eSYann Gautier unsigned int width = bus_width; 195ad71d45eSYann Gautier 196ad71d45eSYann Gautier if (mmc_dev_info->mmc_dev_type != MMC_IS_EMMC) { 197ad71d45eSYann Gautier if (width == MMC_BUS_WIDTH_8) { 198ad71d45eSYann Gautier WARN("Wrong bus config for SD-card, force to 4\n"); 199ad71d45eSYann Gautier width = MMC_BUS_WIDTH_4; 200ad71d45eSYann Gautier } 201ad71d45eSYann Gautier ret = mmc_sd_switch(width); 202ad71d45eSYann Gautier if (ret != 0) { 203ad71d45eSYann Gautier return ret; 204ad71d45eSYann Gautier } 205ad71d45eSYann Gautier } else if (mmc_csd.spec_vers == 4U) { 206ad71d45eSYann Gautier ret = mmc_set_ext_csd(CMD_EXTCSD_BUS_WIDTH, 207ad71d45eSYann Gautier (unsigned int)width); 208ad71d45eSYann Gautier if (ret != 0) { 209ad71d45eSYann Gautier return ret; 210ad71d45eSYann Gautier } 211ad71d45eSYann Gautier } else { 212ad71d45eSYann Gautier VERBOSE("Wrong MMC type or spec version\n"); 213ad71d45eSYann Gautier } 214ad71d45eSYann Gautier 215ad71d45eSYann Gautier return ops->set_ios(clk, width); 216ad71d45eSYann Gautier } 217ad71d45eSYann Gautier 218ad71d45eSYann Gautier static int mmc_fill_device_info(void) 219ad71d45eSYann Gautier { 220ad71d45eSYann Gautier unsigned long long c_size; 221ad71d45eSYann Gautier unsigned int speed_idx; 222ad71d45eSYann Gautier unsigned int nb_blocks; 223ad71d45eSYann Gautier unsigned int freq_unit; 224*cadb36cbSAntonio Nino Diaz int ret = 0; 225ad71d45eSYann Gautier struct mmc_csd_sd_v2 *csd_sd_v2; 226ad71d45eSYann Gautier 227ad71d45eSYann Gautier switch (mmc_dev_info->mmc_dev_type) { 228ad71d45eSYann Gautier case MMC_IS_EMMC: 229ad71d45eSYann Gautier mmc_dev_info->block_size = MMC_BLOCK_SIZE; 230ad71d45eSYann Gautier 231ad71d45eSYann Gautier ret = ops->prepare(0, (uintptr_t)&mmc_ext_csd, 232ad71d45eSYann Gautier sizeof(mmc_ext_csd)); 233ad71d45eSYann Gautier if (ret != 0) { 234ad71d45eSYann Gautier return ret; 235ad71d45eSYann Gautier } 236ad71d45eSYann Gautier 237ad71d45eSYann Gautier /* MMC CMD8: SEND_EXT_CSD */ 238ad71d45eSYann Gautier ret = mmc_send_cmd(MMC_CMD(8), 0, MMC_RESPONSE_R(1), NULL); 239ad71d45eSYann Gautier if (ret != 0) { 240ad71d45eSYann Gautier return ret; 241ad71d45eSYann Gautier } 242ad71d45eSYann Gautier 243ad71d45eSYann Gautier ret = ops->read(0, (uintptr_t)&mmc_ext_csd, 244ad71d45eSYann Gautier sizeof(mmc_ext_csd)); 245ad71d45eSYann Gautier if (ret != 0) { 246ad71d45eSYann Gautier return ret; 247ad71d45eSYann Gautier } 248ad71d45eSYann Gautier 249ad71d45eSYann Gautier nb_blocks = (mmc_ext_csd[CMD_EXTCSD_SEC_CNT] << 0) | 250ad71d45eSYann Gautier (mmc_ext_csd[CMD_EXTCSD_SEC_CNT + 1] << 8) | 251ad71d45eSYann Gautier (mmc_ext_csd[CMD_EXTCSD_SEC_CNT + 2] << 16) | 252ad71d45eSYann Gautier (mmc_ext_csd[CMD_EXTCSD_SEC_CNT + 3] << 24); 253ad71d45eSYann Gautier 254ad71d45eSYann Gautier mmc_dev_info->device_size = (unsigned long long)nb_blocks * 255ad71d45eSYann Gautier mmc_dev_info->block_size; 256ad71d45eSYann Gautier 257ad71d45eSYann Gautier break; 258ad71d45eSYann Gautier 259ad71d45eSYann Gautier case MMC_IS_SD: 260ad71d45eSYann Gautier /* 261ad71d45eSYann Gautier * Use the same mmc_csd struct, as required fields here 262ad71d45eSYann Gautier * (READ_BL_LEN, C_SIZE, CSIZE_MULT) are common with eMMC. 263ad71d45eSYann Gautier */ 264ad71d45eSYann Gautier mmc_dev_info->block_size = BIT_32(mmc_csd.read_bl_len); 265ad71d45eSYann Gautier 266ad71d45eSYann Gautier c_size = ((unsigned long long)mmc_csd.c_size_high << 2U) | 267ad71d45eSYann Gautier (unsigned long long)mmc_csd.c_size_low; 268ad71d45eSYann Gautier assert(c_size != 0xFFFU); 269ad71d45eSYann Gautier 270ad71d45eSYann Gautier mmc_dev_info->device_size = (c_size + 1U) * 271ad71d45eSYann Gautier BIT_64(mmc_csd.c_size_mult + 2U) * 272ad71d45eSYann Gautier mmc_dev_info->block_size; 273ad71d45eSYann Gautier 274ad71d45eSYann Gautier break; 275ad71d45eSYann Gautier 276ad71d45eSYann Gautier case MMC_IS_SD_HC: 277ad71d45eSYann Gautier assert(mmc_csd.csd_structure == 1U); 278ad71d45eSYann Gautier 279ad71d45eSYann Gautier mmc_dev_info->block_size = MMC_BLOCK_SIZE; 280ad71d45eSYann Gautier 281ad71d45eSYann Gautier /* Need to use mmc_csd_sd_v2 struct */ 282ad71d45eSYann Gautier csd_sd_v2 = (struct mmc_csd_sd_v2 *)&mmc_csd; 283ad71d45eSYann Gautier c_size = ((unsigned long long)csd_sd_v2->c_size_high << 16) | 284ad71d45eSYann Gautier (unsigned long long)csd_sd_v2->c_size_low; 285ad71d45eSYann Gautier 286ad71d45eSYann Gautier mmc_dev_info->device_size = (c_size + 1U) << MULT_BY_512K_SHIFT; 287ad71d45eSYann Gautier 288ad71d45eSYann Gautier break; 289ad71d45eSYann Gautier 290ad71d45eSYann Gautier default: 291ad71d45eSYann Gautier ret = -EINVAL; 292ad71d45eSYann Gautier break; 293ad71d45eSYann Gautier } 294ad71d45eSYann Gautier 295ad71d45eSYann Gautier if (ret != 0) { 296ad71d45eSYann Gautier return ret; 297ad71d45eSYann Gautier } 298ad71d45eSYann Gautier 299ad71d45eSYann Gautier speed_idx = (mmc_csd.tran_speed & CSD_TRAN_SPEED_MULT_MASK) >> 300ad71d45eSYann Gautier CSD_TRAN_SPEED_MULT_SHIFT; 301ad71d45eSYann Gautier 302ad71d45eSYann Gautier assert(speed_idx > 0U); 303ad71d45eSYann Gautier 304ad71d45eSYann Gautier if (mmc_dev_info->mmc_dev_type == MMC_IS_EMMC) { 305ad71d45eSYann Gautier mmc_dev_info->max_bus_freq = tran_speed_base[speed_idx]; 306ad71d45eSYann Gautier } else { 307ad71d45eSYann Gautier mmc_dev_info->max_bus_freq = sd_tran_speed_base[speed_idx]; 308ad71d45eSYann Gautier } 309ad71d45eSYann Gautier 310ad71d45eSYann Gautier freq_unit = mmc_csd.tran_speed & CSD_TRAN_SPEED_UNIT_MASK; 311ad71d45eSYann Gautier while (freq_unit != 0U) { 312ad71d45eSYann Gautier mmc_dev_info->max_bus_freq *= 10U; 313ad71d45eSYann Gautier --freq_unit; 314ad71d45eSYann Gautier } 315ad71d45eSYann Gautier 316ad71d45eSYann Gautier mmc_dev_info->max_bus_freq *= 10000U; 317ad71d45eSYann Gautier 318ad71d45eSYann Gautier return 0; 319ad71d45eSYann Gautier } 320ad71d45eSYann Gautier 321ad71d45eSYann Gautier static int sd_send_op_cond(void) 322ad71d45eSYann Gautier { 32315e913d4SYann Gautier int n; 324ad71d45eSYann Gautier unsigned int resp_data[4]; 325ad71d45eSYann Gautier 32615e913d4SYann Gautier for (n = 0; n < SEND_OP_COND_MAX_RETRIES; n++) { 327ad71d45eSYann Gautier int ret; 328ad71d45eSYann Gautier 329ad71d45eSYann Gautier /* CMD55: Application Specific Command */ 330ad71d45eSYann Gautier ret = mmc_send_cmd(MMC_CMD(55), 0, MMC_RESPONSE_R(1), NULL); 331ad71d45eSYann Gautier if (ret != 0) { 332ad71d45eSYann Gautier return ret; 333ad71d45eSYann Gautier } 334ad71d45eSYann Gautier 335ad71d45eSYann Gautier /* ACMD41: SD_SEND_OP_COND */ 336ad71d45eSYann Gautier ret = mmc_send_cmd(MMC_ACMD(41), OCR_HCS, MMC_RESPONSE_R(3), 337ad71d45eSYann Gautier &resp_data[0]); 338ad71d45eSYann Gautier if (ret != 0) { 339ad71d45eSYann Gautier return ret; 340ad71d45eSYann Gautier } 341ad71d45eSYann Gautier 34215e913d4SYann Gautier if ((resp_data[0] & OCR_POWERUP) != 0U) { 343ad71d45eSYann Gautier mmc_ocr_value = resp_data[0]; 344ad71d45eSYann Gautier 345ad71d45eSYann Gautier if ((mmc_ocr_value & OCR_HCS) != 0U) { 346ad71d45eSYann Gautier mmc_dev_info->mmc_dev_type = MMC_IS_SD_HC; 347ad71d45eSYann Gautier } else { 348ad71d45eSYann Gautier mmc_dev_info->mmc_dev_type = MMC_IS_SD; 349ad71d45eSYann Gautier } 350ad71d45eSYann Gautier 351ad71d45eSYann Gautier return 0; 352ad71d45eSYann Gautier } 353ad71d45eSYann Gautier 35415e913d4SYann Gautier mdelay(1); 35515e913d4SYann Gautier } 35615e913d4SYann Gautier 35715e913d4SYann Gautier ERROR("ACMD41 failed after %d retries\n", SEND_OP_COND_MAX_RETRIES); 35815e913d4SYann Gautier 35915e913d4SYann Gautier return -EIO; 36015e913d4SYann Gautier } 36115e913d4SYann Gautier 36215e913d4SYann Gautier static int mmc_reset_to_idle(void) 363ad71d45eSYann Gautier { 364ad71d45eSYann Gautier int ret; 36515e913d4SYann Gautier 366ad71d45eSYann Gautier /* CMD0: reset to IDLE */ 367ad71d45eSYann Gautier ret = mmc_send_cmd(MMC_CMD(0), 0, 0, NULL); 368ad71d45eSYann Gautier if (ret != 0) { 369ad71d45eSYann Gautier return ret; 370ad71d45eSYann Gautier } 371ad71d45eSYann Gautier 37215e913d4SYann Gautier mdelay(2); 37315e913d4SYann Gautier 37415e913d4SYann Gautier return 0; 375ad71d45eSYann Gautier } 376ad71d45eSYann Gautier 37715e913d4SYann Gautier static int mmc_send_op_cond(void) 37815e913d4SYann Gautier { 37915e913d4SYann Gautier int ret, n; 38015e913d4SYann Gautier unsigned int resp_data[4]; 38115e913d4SYann Gautier 38215e913d4SYann Gautier mmc_reset_to_idle(); 38315e913d4SYann Gautier 38415e913d4SYann Gautier for (n = 0; n < SEND_OP_COND_MAX_RETRIES; n++) { 385ad71d45eSYann Gautier ret = mmc_send_cmd(MMC_CMD(1), OCR_SECTOR_MODE | 386ad71d45eSYann Gautier OCR_VDD_MIN_2V7 | OCR_VDD_MIN_1V7, 387ad71d45eSYann Gautier MMC_RESPONSE_R(3), &resp_data[0]); 388ad71d45eSYann Gautier if (ret != 0) { 389ad71d45eSYann Gautier return ret; 390ad71d45eSYann Gautier } 391ad71d45eSYann Gautier 39215e913d4SYann Gautier if ((resp_data[0] & OCR_POWERUP) != 0U) { 393ad71d45eSYann Gautier mmc_ocr_value = resp_data[0]; 394ad71d45eSYann Gautier return 0; 395ad71d45eSYann Gautier } 396ad71d45eSYann Gautier 39715e913d4SYann Gautier mdelay(1); 39815e913d4SYann Gautier } 39915e913d4SYann Gautier 40015e913d4SYann Gautier ERROR("CMD1 failed after %d retries\n", SEND_OP_COND_MAX_RETRIES); 40115e913d4SYann Gautier 40215e913d4SYann Gautier return -EIO; 40315e913d4SYann Gautier } 40415e913d4SYann Gautier 405ad71d45eSYann Gautier static int mmc_enumerate(unsigned int clk, unsigned int bus_width) 406ad71d45eSYann Gautier { 407ad71d45eSYann Gautier int ret; 408ad71d45eSYann Gautier unsigned int resp_data[4]; 409ad71d45eSYann Gautier 410ad71d45eSYann Gautier ops->init(); 411ad71d45eSYann Gautier 41215e913d4SYann Gautier mmc_reset_to_idle(); 413ad71d45eSYann Gautier 414e74dc940SHaojian Zhuang if (mmc_dev_info->mmc_dev_type == MMC_IS_EMMC) { 415e74dc940SHaojian Zhuang ret = mmc_send_op_cond(); 416e74dc940SHaojian Zhuang } else { 417ad71d45eSYann Gautier /* CMD8: Send Interface Condition Command */ 418ad71d45eSYann Gautier ret = mmc_send_cmd(MMC_CMD(8), VHS_2_7_3_6_V | CMD8_CHECK_PATTERN, 419ad71d45eSYann Gautier MMC_RESPONSE_R(7), &resp_data[0]); 420ad71d45eSYann Gautier 421ad71d45eSYann Gautier if ((ret == 0) && ((resp_data[0] & 0xffU) == CMD8_CHECK_PATTERN)) { 422ad71d45eSYann Gautier ret = sd_send_op_cond(); 423e74dc940SHaojian Zhuang } 424ad71d45eSYann Gautier } 425ad71d45eSYann Gautier if (ret != 0) { 426ad71d45eSYann Gautier return ret; 427ad71d45eSYann Gautier } 428ad71d45eSYann Gautier 429ad71d45eSYann Gautier /* CMD2: Card Identification */ 430ad71d45eSYann Gautier ret = mmc_send_cmd(MMC_CMD(2), 0, MMC_RESPONSE_R(2), NULL); 431ad71d45eSYann Gautier if (ret != 0) { 432ad71d45eSYann Gautier return ret; 433ad71d45eSYann Gautier } 434ad71d45eSYann Gautier 435ad71d45eSYann Gautier /* CMD3: Set Relative Address */ 436ad71d45eSYann Gautier if (mmc_dev_info->mmc_dev_type == MMC_IS_EMMC) { 437ad71d45eSYann Gautier rca = MMC_FIX_RCA; 438ad71d45eSYann Gautier ret = mmc_send_cmd(MMC_CMD(3), rca << RCA_SHIFT_OFFSET, 439ad71d45eSYann Gautier MMC_RESPONSE_R(1), NULL); 440ad71d45eSYann Gautier if (ret != 0) { 441ad71d45eSYann Gautier return ret; 442ad71d45eSYann Gautier } 443ad71d45eSYann Gautier } else { 444ad71d45eSYann Gautier ret = mmc_send_cmd(MMC_CMD(3), 0, 445ad71d45eSYann Gautier MMC_RESPONSE_R(6), &resp_data[0]); 446ad71d45eSYann Gautier if (ret != 0) { 447ad71d45eSYann Gautier return ret; 448ad71d45eSYann Gautier } 449ad71d45eSYann Gautier 450ad71d45eSYann Gautier rca = (resp_data[0] & 0xFFFF0000U) >> 16; 451ad71d45eSYann Gautier } 452ad71d45eSYann Gautier 453ad71d45eSYann Gautier /* CMD9: CSD Register */ 454ad71d45eSYann Gautier ret = mmc_send_cmd(MMC_CMD(9), rca << RCA_SHIFT_OFFSET, 455ad71d45eSYann Gautier MMC_RESPONSE_R(2), &resp_data[0]); 456ad71d45eSYann Gautier if (ret != 0) { 457ad71d45eSYann Gautier return ret; 458ad71d45eSYann Gautier } 459ad71d45eSYann Gautier 460ad71d45eSYann Gautier memcpy(&mmc_csd, &resp_data, sizeof(resp_data)); 461ad71d45eSYann Gautier 462ad71d45eSYann Gautier /* CMD7: Select Card */ 463ad71d45eSYann Gautier ret = mmc_send_cmd(MMC_CMD(7), rca << RCA_SHIFT_OFFSET, 464ad71d45eSYann Gautier MMC_RESPONSE_R(1), NULL); 465ad71d45eSYann Gautier if (ret != 0) { 466ad71d45eSYann Gautier return ret; 467ad71d45eSYann Gautier } 468ad71d45eSYann Gautier 469ad71d45eSYann Gautier do { 470ad71d45eSYann Gautier ret = mmc_device_state(); 471ad71d45eSYann Gautier if (ret < 0) { 472ad71d45eSYann Gautier return ret; 473ad71d45eSYann Gautier } 474ad71d45eSYann Gautier } while (ret != MMC_STATE_TRAN); 475ad71d45eSYann Gautier 476bd4e3deeSHaojian Zhuang ret = mmc_set_ios(clk, bus_width); 477ad71d45eSYann Gautier if (ret != 0) { 478ad71d45eSYann Gautier return ret; 479ad71d45eSYann Gautier } 480ad71d45eSYann Gautier 481bd4e3deeSHaojian Zhuang return mmc_fill_device_info(); 482ad71d45eSYann Gautier } 483ad71d45eSYann Gautier 484ea315a69SHaojian Zhuang size_t mmc_read_blocks(int lba, uintptr_t buf, size_t size) 485ad71d45eSYann Gautier { 486ad71d45eSYann Gautier int ret; 487ad71d45eSYann Gautier unsigned int cmd_idx, cmd_arg; 488ad71d45eSYann Gautier 489ad71d45eSYann Gautier assert((ops != NULL) && 490ad71d45eSYann Gautier (ops->read != NULL) && 491ad71d45eSYann Gautier (size != 0U) && 492ad71d45eSYann Gautier ((size & MMC_BLOCK_MASK) == 0U)); 493ad71d45eSYann Gautier 494ad71d45eSYann Gautier ret = ops->prepare(lba, buf, size); 495ad71d45eSYann Gautier if (ret != 0) { 496ad71d45eSYann Gautier return 0; 497ad71d45eSYann Gautier } 498ad71d45eSYann Gautier 499ad71d45eSYann Gautier if (is_cmd23_enabled()) { 500ad71d45eSYann Gautier /* Set block count */ 501ad71d45eSYann Gautier ret = mmc_send_cmd(MMC_CMD(23), size / MMC_BLOCK_SIZE, 502ad71d45eSYann Gautier MMC_RESPONSE_R(1), NULL); 503ad71d45eSYann Gautier if (ret != 0) { 504ad71d45eSYann Gautier return 0; 505ad71d45eSYann Gautier } 506ad71d45eSYann Gautier 507ad71d45eSYann Gautier cmd_idx = MMC_CMD(18); 508ad71d45eSYann Gautier } else { 509ad71d45eSYann Gautier if (size > MMC_BLOCK_SIZE) { 510ad71d45eSYann Gautier cmd_idx = MMC_CMD(18); 511ad71d45eSYann Gautier } else { 512ad71d45eSYann Gautier cmd_idx = MMC_CMD(17); 513ad71d45eSYann Gautier } 514ad71d45eSYann Gautier } 515ad71d45eSYann Gautier 516ad71d45eSYann Gautier if (((mmc_ocr_value & OCR_ACCESS_MODE_MASK) == OCR_BYTE_MODE) && 517ad71d45eSYann Gautier (mmc_dev_info->mmc_dev_type != MMC_IS_SD_HC)) { 518ad71d45eSYann Gautier cmd_arg = lba * MMC_BLOCK_SIZE; 519ad71d45eSYann Gautier } else { 520ad71d45eSYann Gautier cmd_arg = lba; 521ad71d45eSYann Gautier } 522ad71d45eSYann Gautier 523ad71d45eSYann Gautier ret = mmc_send_cmd(cmd_idx, cmd_arg, MMC_RESPONSE_R(1), NULL); 524ad71d45eSYann Gautier if (ret != 0) { 525ad71d45eSYann Gautier return 0; 526ad71d45eSYann Gautier } 527ad71d45eSYann Gautier 528ad71d45eSYann Gautier ret = ops->read(lba, buf, size); 529ad71d45eSYann Gautier if (ret != 0) { 530ad71d45eSYann Gautier return 0; 531ad71d45eSYann Gautier } 532ad71d45eSYann Gautier 533ad71d45eSYann Gautier /* Wait buffer empty */ 534ad71d45eSYann Gautier do { 535ad71d45eSYann Gautier ret = mmc_device_state(); 536ad71d45eSYann Gautier if (ret < 0) { 537ad71d45eSYann Gautier return 0; 538ad71d45eSYann Gautier } 539ad71d45eSYann Gautier } while ((ret != MMC_STATE_TRAN) && (ret != MMC_STATE_DATA)); 540ad71d45eSYann Gautier 541ad71d45eSYann Gautier if (!is_cmd23_enabled() && (size > MMC_BLOCK_SIZE)) { 542ad71d45eSYann Gautier ret = mmc_send_cmd(MMC_CMD(12), 0, 0, NULL); 543ad71d45eSYann Gautier if (ret != 0) { 544ad71d45eSYann Gautier return 0; 545ad71d45eSYann Gautier } 546ad71d45eSYann Gautier } 547ad71d45eSYann Gautier 548ad71d45eSYann Gautier return size; 549ad71d45eSYann Gautier } 550ad71d45eSYann Gautier 551ea315a69SHaojian Zhuang size_t mmc_write_blocks(int lba, const uintptr_t buf, size_t size) 552ad71d45eSYann Gautier { 553ad71d45eSYann Gautier int ret; 554ad71d45eSYann Gautier unsigned int cmd_idx, cmd_arg; 555ad71d45eSYann Gautier 556ad71d45eSYann Gautier assert((ops != NULL) && 557ad71d45eSYann Gautier (ops->write != NULL) && 558ad71d45eSYann Gautier (size != 0U) && 559ad71d45eSYann Gautier ((buf & MMC_BLOCK_MASK) == 0U) && 560ad71d45eSYann Gautier ((size & MMC_BLOCK_MASK) == 0U)); 561ad71d45eSYann Gautier 562ad71d45eSYann Gautier ret = ops->prepare(lba, buf, size); 563ad71d45eSYann Gautier if (ret != 0) { 564ad71d45eSYann Gautier return 0; 565ad71d45eSYann Gautier } 566ad71d45eSYann Gautier 567ad71d45eSYann Gautier if (is_cmd23_enabled()) { 568ad71d45eSYann Gautier /* Set block count */ 569ad71d45eSYann Gautier ret = mmc_send_cmd(MMC_CMD(23), size / MMC_BLOCK_SIZE, 570ad71d45eSYann Gautier MMC_RESPONSE_R(1), NULL); 571ad71d45eSYann Gautier if (ret != 0) { 572ad71d45eSYann Gautier return 0; 573ad71d45eSYann Gautier } 574ad71d45eSYann Gautier 575ad71d45eSYann Gautier cmd_idx = MMC_CMD(25); 576ad71d45eSYann Gautier } else { 577ad71d45eSYann Gautier if (size > MMC_BLOCK_SIZE) { 578ad71d45eSYann Gautier cmd_idx = MMC_CMD(25); 579ad71d45eSYann Gautier } else { 580ad71d45eSYann Gautier cmd_idx = MMC_CMD(24); 581ad71d45eSYann Gautier } 582ad71d45eSYann Gautier } 583ad71d45eSYann Gautier 584ad71d45eSYann Gautier if ((mmc_ocr_value & OCR_ACCESS_MODE_MASK) == OCR_BYTE_MODE) { 585ad71d45eSYann Gautier cmd_arg = lba * MMC_BLOCK_SIZE; 586ad71d45eSYann Gautier } else { 587ad71d45eSYann Gautier cmd_arg = lba; 588ad71d45eSYann Gautier } 589ad71d45eSYann Gautier 590ad71d45eSYann Gautier ret = mmc_send_cmd(cmd_idx, cmd_arg, MMC_RESPONSE_R(1), NULL); 591ad71d45eSYann Gautier if (ret != 0) { 592ad71d45eSYann Gautier return 0; 593ad71d45eSYann Gautier } 594ad71d45eSYann Gautier 595ad71d45eSYann Gautier ret = ops->write(lba, buf, size); 596ad71d45eSYann Gautier if (ret != 0) { 597ad71d45eSYann Gautier return 0; 598ad71d45eSYann Gautier } 599ad71d45eSYann Gautier 600ad71d45eSYann Gautier /* Wait buffer empty */ 601ad71d45eSYann Gautier do { 602ad71d45eSYann Gautier ret = mmc_device_state(); 603ad71d45eSYann Gautier if (ret < 0) { 604ad71d45eSYann Gautier return 0; 605ad71d45eSYann Gautier } 606ad71d45eSYann Gautier } while ((ret != MMC_STATE_TRAN) && (ret != MMC_STATE_RCV)); 607ad71d45eSYann Gautier 608ad71d45eSYann Gautier if (!is_cmd23_enabled() && (size > MMC_BLOCK_SIZE)) { 609ad71d45eSYann Gautier ret = mmc_send_cmd(MMC_CMD(12), 0, 0, NULL); 610ad71d45eSYann Gautier if (ret != 0) { 611ad71d45eSYann Gautier return 0; 612ad71d45eSYann Gautier } 613ad71d45eSYann Gautier } 614ad71d45eSYann Gautier 615ad71d45eSYann Gautier return size; 616ad71d45eSYann Gautier } 617ad71d45eSYann Gautier 618ea315a69SHaojian Zhuang size_t mmc_erase_blocks(int lba, size_t size) 619ad71d45eSYann Gautier { 620ad71d45eSYann Gautier int ret; 621ad71d45eSYann Gautier 622ad71d45eSYann Gautier assert(ops != NULL); 623ad71d45eSYann Gautier assert((size != 0U) && ((size & MMC_BLOCK_MASK) == 0U)); 624ad71d45eSYann Gautier 625ad71d45eSYann Gautier ret = mmc_send_cmd(MMC_CMD(35), lba, MMC_RESPONSE_R(1), NULL); 626ad71d45eSYann Gautier if (ret != 0) { 627ad71d45eSYann Gautier return 0; 628ad71d45eSYann Gautier } 629ad71d45eSYann Gautier 630ad71d45eSYann Gautier ret = mmc_send_cmd(MMC_CMD(36), lba + (size / MMC_BLOCK_SIZE) - 1U, 631ad71d45eSYann Gautier MMC_RESPONSE_R(1), NULL); 632ad71d45eSYann Gautier if (ret != 0) { 633ad71d45eSYann Gautier return 0; 634ad71d45eSYann Gautier } 635ad71d45eSYann Gautier 636ad71d45eSYann Gautier ret = mmc_send_cmd(MMC_CMD(38), lba, MMC_RESPONSE_R(0x1B), NULL); 637ad71d45eSYann Gautier if (ret != 0) { 638ad71d45eSYann Gautier return 0; 639ad71d45eSYann Gautier } 640ad71d45eSYann Gautier 641ad71d45eSYann Gautier do { 642ad71d45eSYann Gautier ret = mmc_device_state(); 643ad71d45eSYann Gautier if (ret < 0) { 644ad71d45eSYann Gautier return 0; 645ad71d45eSYann Gautier } 646ad71d45eSYann Gautier } while (ret != MMC_STATE_TRAN); 647ad71d45eSYann Gautier 648ad71d45eSYann Gautier return size; 649ad71d45eSYann Gautier } 650ad71d45eSYann Gautier 651ad71d45eSYann Gautier static inline void mmc_rpmb_enable(void) 652ad71d45eSYann Gautier { 653ad71d45eSYann Gautier mmc_set_ext_csd(CMD_EXTCSD_PARTITION_CONFIG, 654ad71d45eSYann Gautier PART_CFG_BOOT_PARTITION1_ENABLE | 655ad71d45eSYann Gautier PART_CFG_PARTITION1_ACCESS); 656ad71d45eSYann Gautier } 657ad71d45eSYann Gautier 658ad71d45eSYann Gautier static inline void mmc_rpmb_disable(void) 659ad71d45eSYann Gautier { 660ad71d45eSYann Gautier mmc_set_ext_csd(CMD_EXTCSD_PARTITION_CONFIG, 661ad71d45eSYann Gautier PART_CFG_BOOT_PARTITION1_ENABLE); 662ad71d45eSYann Gautier } 663ad71d45eSYann Gautier 664ea315a69SHaojian Zhuang size_t mmc_rpmb_read_blocks(int lba, uintptr_t buf, size_t size) 665ad71d45eSYann Gautier { 666ad71d45eSYann Gautier size_t size_read; 667ad71d45eSYann Gautier 668ad71d45eSYann Gautier mmc_rpmb_enable(); 669ad71d45eSYann Gautier size_read = mmc_read_blocks(lba, buf, size); 670ad71d45eSYann Gautier mmc_rpmb_disable(); 671ad71d45eSYann Gautier 672ad71d45eSYann Gautier return size_read; 673ad71d45eSYann Gautier } 674ad71d45eSYann Gautier 675ea315a69SHaojian Zhuang size_t mmc_rpmb_write_blocks(int lba, const uintptr_t buf, size_t size) 676ad71d45eSYann Gautier { 677ad71d45eSYann Gautier size_t size_written; 678ad71d45eSYann Gautier 679ad71d45eSYann Gautier mmc_rpmb_enable(); 680ad71d45eSYann Gautier size_written = mmc_write_blocks(lba, buf, size); 681ad71d45eSYann Gautier mmc_rpmb_disable(); 682ad71d45eSYann Gautier 683ad71d45eSYann Gautier return size_written; 684ad71d45eSYann Gautier } 685ad71d45eSYann Gautier 686ea315a69SHaojian Zhuang size_t mmc_rpmb_erase_blocks(int lba, size_t size) 687ad71d45eSYann Gautier { 688ad71d45eSYann Gautier size_t size_erased; 689ad71d45eSYann Gautier 690ad71d45eSYann Gautier mmc_rpmb_enable(); 691ad71d45eSYann Gautier size_erased = mmc_erase_blocks(lba, size); 692ad71d45eSYann Gautier mmc_rpmb_disable(); 693ad71d45eSYann Gautier 694ad71d45eSYann Gautier return size_erased; 695ad71d45eSYann Gautier } 696ad71d45eSYann Gautier 697ad71d45eSYann Gautier int mmc_init(const struct mmc_ops *ops_ptr, unsigned int clk, 698ad71d45eSYann Gautier unsigned int width, unsigned int flags, 699ad71d45eSYann Gautier struct mmc_device_info *device_info) 700ad71d45eSYann Gautier { 701ad71d45eSYann Gautier assert((ops_ptr != NULL) && 702ad71d45eSYann Gautier (ops_ptr->init != NULL) && 703ad71d45eSYann Gautier (ops_ptr->send_cmd != NULL) && 704ad71d45eSYann Gautier (ops_ptr->set_ios != NULL) && 705ad71d45eSYann Gautier (ops_ptr->prepare != NULL) && 706ad71d45eSYann Gautier (ops_ptr->read != NULL) && 707ad71d45eSYann Gautier (ops_ptr->write != NULL) && 708ad71d45eSYann Gautier (device_info != NULL) && 709ad71d45eSYann Gautier (clk != 0) && 710ad71d45eSYann Gautier ((width == MMC_BUS_WIDTH_1) || 711ad71d45eSYann Gautier (width == MMC_BUS_WIDTH_4) || 712ad71d45eSYann Gautier (width == MMC_BUS_WIDTH_8) || 713ad71d45eSYann Gautier (width == MMC_BUS_WIDTH_DDR_4) || 714ad71d45eSYann Gautier (width == MMC_BUS_WIDTH_DDR_8))); 715ad71d45eSYann Gautier 716ad71d45eSYann Gautier ops = ops_ptr; 717ad71d45eSYann Gautier mmc_flags = flags; 718ad71d45eSYann Gautier mmc_dev_info = device_info; 719ad71d45eSYann Gautier 720ad71d45eSYann Gautier return mmc_enumerate(clk, width); 721ad71d45eSYann Gautier } 722