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