1*91f16700Schasinglulu /* 2*91f16700Schasinglulu * Copyright (c) 2018-2022, ARM Limited and Contributors. All rights reserved. 3*91f16700Schasinglulu * 4*91f16700Schasinglulu * SPDX-License-Identifier: BSD-3-Clause 5*91f16700Schasinglulu */ 6*91f16700Schasinglulu 7*91f16700Schasinglulu /* Define a simple and generic interface to access eMMC and SD-card devices. */ 8*91f16700Schasinglulu 9*91f16700Schasinglulu #include <assert.h> 10*91f16700Schasinglulu #include <errno.h> 11*91f16700Schasinglulu #include <stdbool.h> 12*91f16700Schasinglulu #include <string.h> 13*91f16700Schasinglulu 14*91f16700Schasinglulu #include <arch_helpers.h> 15*91f16700Schasinglulu #include <common/debug.h> 16*91f16700Schasinglulu #include <drivers/delay_timer.h> 17*91f16700Schasinglulu #include <drivers/mmc.h> 18*91f16700Schasinglulu #include <lib/utils.h> 19*91f16700Schasinglulu #include <plat/common/common_def.h> 20*91f16700Schasinglulu 21*91f16700Schasinglulu #define MMC_DEFAULT_MAX_RETRIES 5 22*91f16700Schasinglulu #define SEND_OP_COND_MAX_RETRIES 100 23*91f16700Schasinglulu 24*91f16700Schasinglulu #define MULT_BY_512K_SHIFT 19 25*91f16700Schasinglulu 26*91f16700Schasinglulu static const struct mmc_ops *ops; 27*91f16700Schasinglulu static unsigned int mmc_ocr_value; 28*91f16700Schasinglulu static struct mmc_csd_emmc mmc_csd; 29*91f16700Schasinglulu static struct sd_switch_status sd_switch_func_status; 30*91f16700Schasinglulu static unsigned char mmc_ext_csd[512] __aligned(16); 31*91f16700Schasinglulu static unsigned int mmc_flags; 32*91f16700Schasinglulu static struct mmc_device_info *mmc_dev_info; 33*91f16700Schasinglulu static unsigned int rca; 34*91f16700Schasinglulu static unsigned int scr[2]__aligned(16) = { 0 }; 35*91f16700Schasinglulu 36*91f16700Schasinglulu static const unsigned char tran_speed_base[16] = { 37*91f16700Schasinglulu 0, 10, 12, 13, 15, 20, 26, 30, 35, 40, 45, 52, 55, 60, 70, 80 38*91f16700Schasinglulu }; 39*91f16700Schasinglulu 40*91f16700Schasinglulu static const unsigned char sd_tran_speed_base[16] = { 41*91f16700Schasinglulu 0, 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80 42*91f16700Schasinglulu }; 43*91f16700Schasinglulu 44*91f16700Schasinglulu static bool is_cmd23_enabled(void) 45*91f16700Schasinglulu { 46*91f16700Schasinglulu return ((mmc_flags & MMC_FLAG_CMD23) != 0U); 47*91f16700Schasinglulu } 48*91f16700Schasinglulu 49*91f16700Schasinglulu static bool is_sd_cmd6_enabled(void) 50*91f16700Schasinglulu { 51*91f16700Schasinglulu return ((mmc_flags & MMC_FLAG_SD_CMD6) != 0U); 52*91f16700Schasinglulu } 53*91f16700Schasinglulu 54*91f16700Schasinglulu static int mmc_send_cmd(unsigned int idx, unsigned int arg, 55*91f16700Schasinglulu unsigned int r_type, unsigned int *r_data) 56*91f16700Schasinglulu { 57*91f16700Schasinglulu struct mmc_cmd cmd; 58*91f16700Schasinglulu int ret; 59*91f16700Schasinglulu 60*91f16700Schasinglulu zeromem(&cmd, sizeof(struct mmc_cmd)); 61*91f16700Schasinglulu 62*91f16700Schasinglulu cmd.cmd_idx = idx; 63*91f16700Schasinglulu cmd.cmd_arg = arg; 64*91f16700Schasinglulu cmd.resp_type = r_type; 65*91f16700Schasinglulu 66*91f16700Schasinglulu ret = ops->send_cmd(&cmd); 67*91f16700Schasinglulu 68*91f16700Schasinglulu if ((ret == 0) && (r_data != NULL)) { 69*91f16700Schasinglulu int i; 70*91f16700Schasinglulu 71*91f16700Schasinglulu for (i = 0; i < 4; i++) { 72*91f16700Schasinglulu r_data[i] = cmd.resp_data[i]; 73*91f16700Schasinglulu } 74*91f16700Schasinglulu } 75*91f16700Schasinglulu 76*91f16700Schasinglulu if (ret != 0) { 77*91f16700Schasinglulu VERBOSE("Send command %u error: %d\n", idx, ret); 78*91f16700Schasinglulu } 79*91f16700Schasinglulu 80*91f16700Schasinglulu return ret; 81*91f16700Schasinglulu } 82*91f16700Schasinglulu 83*91f16700Schasinglulu static int mmc_device_state(void) 84*91f16700Schasinglulu { 85*91f16700Schasinglulu int retries = MMC_DEFAULT_MAX_RETRIES; 86*91f16700Schasinglulu unsigned int resp_data[4] = {0}; 87*91f16700Schasinglulu 88*91f16700Schasinglulu do { 89*91f16700Schasinglulu int ret; 90*91f16700Schasinglulu 91*91f16700Schasinglulu if (retries == 0) { 92*91f16700Schasinglulu ERROR("CMD13 failed after %d retries\n", 93*91f16700Schasinglulu MMC_DEFAULT_MAX_RETRIES); 94*91f16700Schasinglulu return -EIO; 95*91f16700Schasinglulu } 96*91f16700Schasinglulu 97*91f16700Schasinglulu ret = mmc_send_cmd(MMC_CMD(13), rca << RCA_SHIFT_OFFSET, 98*91f16700Schasinglulu MMC_RESPONSE_R1, &resp_data[0]); 99*91f16700Schasinglulu if (ret != 0) { 100*91f16700Schasinglulu retries--; 101*91f16700Schasinglulu continue; 102*91f16700Schasinglulu } 103*91f16700Schasinglulu 104*91f16700Schasinglulu if ((resp_data[0] & STATUS_SWITCH_ERROR) != 0U) { 105*91f16700Schasinglulu return -EIO; 106*91f16700Schasinglulu } 107*91f16700Schasinglulu 108*91f16700Schasinglulu retries--; 109*91f16700Schasinglulu } while ((resp_data[0] & STATUS_READY_FOR_DATA) == 0U); 110*91f16700Schasinglulu 111*91f16700Schasinglulu return MMC_GET_STATE(resp_data[0]); 112*91f16700Schasinglulu } 113*91f16700Schasinglulu 114*91f16700Schasinglulu static int mmc_send_part_switch_cmd(unsigned char part_config) 115*91f16700Schasinglulu { 116*91f16700Schasinglulu int ret; 117*91f16700Schasinglulu unsigned int part_time = 0; 118*91f16700Schasinglulu 119*91f16700Schasinglulu ret = mmc_send_cmd(MMC_CMD(6), 120*91f16700Schasinglulu EXTCSD_WRITE_BYTES | 121*91f16700Schasinglulu EXTCSD_CMD(CMD_EXTCSD_PARTITION_CONFIG) | 122*91f16700Schasinglulu EXTCSD_VALUE(part_config) | 123*91f16700Schasinglulu EXTCSD_CMD_SET_NORMAL, 124*91f16700Schasinglulu MMC_RESPONSE_R1B, NULL); 125*91f16700Schasinglulu if (ret != 0) { 126*91f16700Schasinglulu return ret; 127*91f16700Schasinglulu } 128*91f16700Schasinglulu 129*91f16700Schasinglulu /* Partition switch timing is in 10ms units */ 130*91f16700Schasinglulu part_time = mmc_ext_csd[CMD_EXTCSD_PART_SWITCH_TIME] * 10; 131*91f16700Schasinglulu 132*91f16700Schasinglulu mdelay(part_time); 133*91f16700Schasinglulu 134*91f16700Schasinglulu do { 135*91f16700Schasinglulu ret = mmc_device_state(); 136*91f16700Schasinglulu if (ret < 0) { 137*91f16700Schasinglulu return ret; 138*91f16700Schasinglulu } 139*91f16700Schasinglulu } while (ret == MMC_STATE_PRG); 140*91f16700Schasinglulu 141*91f16700Schasinglulu return 0; 142*91f16700Schasinglulu } 143*91f16700Schasinglulu 144*91f16700Schasinglulu static int mmc_set_ext_csd(unsigned int ext_cmd, unsigned int value) 145*91f16700Schasinglulu { 146*91f16700Schasinglulu int ret; 147*91f16700Schasinglulu 148*91f16700Schasinglulu ret = mmc_send_cmd(MMC_CMD(6), 149*91f16700Schasinglulu EXTCSD_WRITE_BYTES | EXTCSD_CMD(ext_cmd) | 150*91f16700Schasinglulu EXTCSD_VALUE(value) | EXTCSD_CMD_SET_NORMAL, 151*91f16700Schasinglulu MMC_RESPONSE_R1B, NULL); 152*91f16700Schasinglulu if (ret != 0) { 153*91f16700Schasinglulu return ret; 154*91f16700Schasinglulu } 155*91f16700Schasinglulu 156*91f16700Schasinglulu do { 157*91f16700Schasinglulu ret = mmc_device_state(); 158*91f16700Schasinglulu if (ret < 0) { 159*91f16700Schasinglulu return ret; 160*91f16700Schasinglulu } 161*91f16700Schasinglulu } while (ret == MMC_STATE_PRG); 162*91f16700Schasinglulu 163*91f16700Schasinglulu return 0; 164*91f16700Schasinglulu } 165*91f16700Schasinglulu 166*91f16700Schasinglulu static int mmc_sd_switch(unsigned int bus_width) 167*91f16700Schasinglulu { 168*91f16700Schasinglulu int ret; 169*91f16700Schasinglulu int retries = MMC_DEFAULT_MAX_RETRIES; 170*91f16700Schasinglulu unsigned int bus_width_arg = 0; 171*91f16700Schasinglulu 172*91f16700Schasinglulu ret = ops->prepare(0, (uintptr_t)&scr, sizeof(scr)); 173*91f16700Schasinglulu if (ret != 0) { 174*91f16700Schasinglulu return ret; 175*91f16700Schasinglulu } 176*91f16700Schasinglulu 177*91f16700Schasinglulu /* CMD55: Application Specific Command */ 178*91f16700Schasinglulu ret = mmc_send_cmd(MMC_CMD(55), rca << RCA_SHIFT_OFFSET, 179*91f16700Schasinglulu MMC_RESPONSE_R5, NULL); 180*91f16700Schasinglulu if (ret != 0) { 181*91f16700Schasinglulu return ret; 182*91f16700Schasinglulu } 183*91f16700Schasinglulu 184*91f16700Schasinglulu /* ACMD51: SEND_SCR */ 185*91f16700Schasinglulu do { 186*91f16700Schasinglulu ret = mmc_send_cmd(MMC_ACMD(51), 0, MMC_RESPONSE_R1, NULL); 187*91f16700Schasinglulu if ((ret != 0) && (retries == 0)) { 188*91f16700Schasinglulu ERROR("ACMD51 failed after %d retries (ret=%d)\n", 189*91f16700Schasinglulu MMC_DEFAULT_MAX_RETRIES, ret); 190*91f16700Schasinglulu return ret; 191*91f16700Schasinglulu } 192*91f16700Schasinglulu 193*91f16700Schasinglulu retries--; 194*91f16700Schasinglulu } while (ret != 0); 195*91f16700Schasinglulu 196*91f16700Schasinglulu ret = ops->read(0, (uintptr_t)&scr, sizeof(scr)); 197*91f16700Schasinglulu if (ret != 0) { 198*91f16700Schasinglulu return ret; 199*91f16700Schasinglulu } 200*91f16700Schasinglulu 201*91f16700Schasinglulu if (((scr[0] & SD_SCR_BUS_WIDTH_4) != 0U) && 202*91f16700Schasinglulu (bus_width == MMC_BUS_WIDTH_4)) { 203*91f16700Schasinglulu bus_width_arg = 2; 204*91f16700Schasinglulu } 205*91f16700Schasinglulu 206*91f16700Schasinglulu /* CMD55: Application Specific Command */ 207*91f16700Schasinglulu ret = mmc_send_cmd(MMC_CMD(55), rca << RCA_SHIFT_OFFSET, 208*91f16700Schasinglulu MMC_RESPONSE_R5, NULL); 209*91f16700Schasinglulu if (ret != 0) { 210*91f16700Schasinglulu return ret; 211*91f16700Schasinglulu } 212*91f16700Schasinglulu 213*91f16700Schasinglulu /* ACMD6: SET_BUS_WIDTH */ 214*91f16700Schasinglulu ret = mmc_send_cmd(MMC_ACMD(6), bus_width_arg, MMC_RESPONSE_R1, NULL); 215*91f16700Schasinglulu if (ret != 0) { 216*91f16700Schasinglulu return ret; 217*91f16700Schasinglulu } 218*91f16700Schasinglulu 219*91f16700Schasinglulu do { 220*91f16700Schasinglulu ret = mmc_device_state(); 221*91f16700Schasinglulu if (ret < 0) { 222*91f16700Schasinglulu return ret; 223*91f16700Schasinglulu } 224*91f16700Schasinglulu } while (ret == MMC_STATE_PRG); 225*91f16700Schasinglulu 226*91f16700Schasinglulu return 0; 227*91f16700Schasinglulu } 228*91f16700Schasinglulu 229*91f16700Schasinglulu static int mmc_set_ios(unsigned int clk, unsigned int bus_width) 230*91f16700Schasinglulu { 231*91f16700Schasinglulu int ret; 232*91f16700Schasinglulu unsigned int width = bus_width; 233*91f16700Schasinglulu 234*91f16700Schasinglulu if (mmc_dev_info->mmc_dev_type != MMC_IS_EMMC) { 235*91f16700Schasinglulu if (width == MMC_BUS_WIDTH_8) { 236*91f16700Schasinglulu WARN("Wrong bus config for SD-card, force to 4\n"); 237*91f16700Schasinglulu width = MMC_BUS_WIDTH_4; 238*91f16700Schasinglulu } 239*91f16700Schasinglulu ret = mmc_sd_switch(width); 240*91f16700Schasinglulu if (ret != 0) { 241*91f16700Schasinglulu return ret; 242*91f16700Schasinglulu } 243*91f16700Schasinglulu } else if (mmc_csd.spec_vers == 4U) { 244*91f16700Schasinglulu ret = mmc_set_ext_csd(CMD_EXTCSD_BUS_WIDTH, 245*91f16700Schasinglulu (unsigned int)width); 246*91f16700Schasinglulu if (ret != 0) { 247*91f16700Schasinglulu return ret; 248*91f16700Schasinglulu } 249*91f16700Schasinglulu } else { 250*91f16700Schasinglulu VERBOSE("Wrong MMC type or spec version\n"); 251*91f16700Schasinglulu } 252*91f16700Schasinglulu 253*91f16700Schasinglulu return ops->set_ios(clk, width); 254*91f16700Schasinglulu } 255*91f16700Schasinglulu 256*91f16700Schasinglulu static int mmc_fill_device_info(void) 257*91f16700Schasinglulu { 258*91f16700Schasinglulu unsigned long long c_size; 259*91f16700Schasinglulu unsigned int speed_idx; 260*91f16700Schasinglulu unsigned int nb_blocks; 261*91f16700Schasinglulu unsigned int freq_unit; 262*91f16700Schasinglulu int ret = 0; 263*91f16700Schasinglulu struct mmc_csd_sd_v2 *csd_sd_v2; 264*91f16700Schasinglulu 265*91f16700Schasinglulu switch (mmc_dev_info->mmc_dev_type) { 266*91f16700Schasinglulu case MMC_IS_EMMC: 267*91f16700Schasinglulu mmc_dev_info->block_size = MMC_BLOCK_SIZE; 268*91f16700Schasinglulu 269*91f16700Schasinglulu ret = ops->prepare(0, (uintptr_t)&mmc_ext_csd, 270*91f16700Schasinglulu sizeof(mmc_ext_csd)); 271*91f16700Schasinglulu if (ret != 0) { 272*91f16700Schasinglulu return ret; 273*91f16700Schasinglulu } 274*91f16700Schasinglulu 275*91f16700Schasinglulu /* MMC CMD8: SEND_EXT_CSD */ 276*91f16700Schasinglulu ret = mmc_send_cmd(MMC_CMD(8), 0, MMC_RESPONSE_R1, NULL); 277*91f16700Schasinglulu if (ret != 0) { 278*91f16700Schasinglulu return ret; 279*91f16700Schasinglulu } 280*91f16700Schasinglulu 281*91f16700Schasinglulu ret = ops->read(0, (uintptr_t)&mmc_ext_csd, 282*91f16700Schasinglulu sizeof(mmc_ext_csd)); 283*91f16700Schasinglulu if (ret != 0) { 284*91f16700Schasinglulu return ret; 285*91f16700Schasinglulu } 286*91f16700Schasinglulu 287*91f16700Schasinglulu do { 288*91f16700Schasinglulu ret = mmc_device_state(); 289*91f16700Schasinglulu if (ret < 0) { 290*91f16700Schasinglulu return ret; 291*91f16700Schasinglulu } 292*91f16700Schasinglulu } while (ret != MMC_STATE_TRAN); 293*91f16700Schasinglulu 294*91f16700Schasinglulu nb_blocks = (mmc_ext_csd[CMD_EXTCSD_SEC_CNT] << 0) | 295*91f16700Schasinglulu (mmc_ext_csd[CMD_EXTCSD_SEC_CNT + 1] << 8) | 296*91f16700Schasinglulu (mmc_ext_csd[CMD_EXTCSD_SEC_CNT + 2] << 16) | 297*91f16700Schasinglulu (mmc_ext_csd[CMD_EXTCSD_SEC_CNT + 3] << 24); 298*91f16700Schasinglulu 299*91f16700Schasinglulu mmc_dev_info->device_size = (unsigned long long)nb_blocks * 300*91f16700Schasinglulu mmc_dev_info->block_size; 301*91f16700Schasinglulu 302*91f16700Schasinglulu break; 303*91f16700Schasinglulu 304*91f16700Schasinglulu case MMC_IS_SD: 305*91f16700Schasinglulu /* 306*91f16700Schasinglulu * Use the same mmc_csd struct, as required fields here 307*91f16700Schasinglulu * (READ_BL_LEN, C_SIZE, CSIZE_MULT) are common with eMMC. 308*91f16700Schasinglulu */ 309*91f16700Schasinglulu mmc_dev_info->block_size = BIT_32(mmc_csd.read_bl_len); 310*91f16700Schasinglulu 311*91f16700Schasinglulu c_size = ((unsigned long long)mmc_csd.c_size_high << 2U) | 312*91f16700Schasinglulu (unsigned long long)mmc_csd.c_size_low; 313*91f16700Schasinglulu assert(c_size != 0xFFFU); 314*91f16700Schasinglulu 315*91f16700Schasinglulu mmc_dev_info->device_size = (c_size + 1U) * 316*91f16700Schasinglulu BIT_64(mmc_csd.c_size_mult + 2U) * 317*91f16700Schasinglulu mmc_dev_info->block_size; 318*91f16700Schasinglulu 319*91f16700Schasinglulu break; 320*91f16700Schasinglulu 321*91f16700Schasinglulu case MMC_IS_SD_HC: 322*91f16700Schasinglulu assert(mmc_csd.csd_structure == 1U); 323*91f16700Schasinglulu 324*91f16700Schasinglulu mmc_dev_info->block_size = MMC_BLOCK_SIZE; 325*91f16700Schasinglulu 326*91f16700Schasinglulu /* Need to use mmc_csd_sd_v2 struct */ 327*91f16700Schasinglulu csd_sd_v2 = (struct mmc_csd_sd_v2 *)&mmc_csd; 328*91f16700Schasinglulu c_size = ((unsigned long long)csd_sd_v2->c_size_high << 16) | 329*91f16700Schasinglulu (unsigned long long)csd_sd_v2->c_size_low; 330*91f16700Schasinglulu 331*91f16700Schasinglulu mmc_dev_info->device_size = (c_size + 1U) << MULT_BY_512K_SHIFT; 332*91f16700Schasinglulu 333*91f16700Schasinglulu break; 334*91f16700Schasinglulu 335*91f16700Schasinglulu default: 336*91f16700Schasinglulu ret = -EINVAL; 337*91f16700Schasinglulu break; 338*91f16700Schasinglulu } 339*91f16700Schasinglulu 340*91f16700Schasinglulu if (ret < 0) { 341*91f16700Schasinglulu return ret; 342*91f16700Schasinglulu } 343*91f16700Schasinglulu 344*91f16700Schasinglulu speed_idx = (mmc_csd.tran_speed & CSD_TRAN_SPEED_MULT_MASK) >> 345*91f16700Schasinglulu CSD_TRAN_SPEED_MULT_SHIFT; 346*91f16700Schasinglulu 347*91f16700Schasinglulu assert(speed_idx > 0U); 348*91f16700Schasinglulu 349*91f16700Schasinglulu if (mmc_dev_info->mmc_dev_type == MMC_IS_EMMC) { 350*91f16700Schasinglulu mmc_dev_info->max_bus_freq = tran_speed_base[speed_idx]; 351*91f16700Schasinglulu } else { 352*91f16700Schasinglulu mmc_dev_info->max_bus_freq = sd_tran_speed_base[speed_idx]; 353*91f16700Schasinglulu } 354*91f16700Schasinglulu 355*91f16700Schasinglulu freq_unit = mmc_csd.tran_speed & CSD_TRAN_SPEED_UNIT_MASK; 356*91f16700Schasinglulu while (freq_unit != 0U) { 357*91f16700Schasinglulu mmc_dev_info->max_bus_freq *= 10U; 358*91f16700Schasinglulu --freq_unit; 359*91f16700Schasinglulu } 360*91f16700Schasinglulu 361*91f16700Schasinglulu mmc_dev_info->max_bus_freq *= 10000U; 362*91f16700Schasinglulu 363*91f16700Schasinglulu return 0; 364*91f16700Schasinglulu } 365*91f16700Schasinglulu 366*91f16700Schasinglulu static int sd_switch(unsigned int mode, unsigned char group, 367*91f16700Schasinglulu unsigned char func) 368*91f16700Schasinglulu { 369*91f16700Schasinglulu unsigned int group_shift = (group - 1U) * 4U; 370*91f16700Schasinglulu unsigned int group_mask = GENMASK(group_shift + 3U, group_shift); 371*91f16700Schasinglulu unsigned int arg; 372*91f16700Schasinglulu int ret; 373*91f16700Schasinglulu 374*91f16700Schasinglulu ret = ops->prepare(0, (uintptr_t)&sd_switch_func_status, 375*91f16700Schasinglulu sizeof(sd_switch_func_status)); 376*91f16700Schasinglulu if (ret != 0) { 377*91f16700Schasinglulu return ret; 378*91f16700Schasinglulu } 379*91f16700Schasinglulu 380*91f16700Schasinglulu /* MMC CMD6: SWITCH_FUNC */ 381*91f16700Schasinglulu arg = mode | SD_SWITCH_ALL_GROUPS_MASK; 382*91f16700Schasinglulu arg &= ~group_mask; 383*91f16700Schasinglulu arg |= func << group_shift; 384*91f16700Schasinglulu ret = mmc_send_cmd(MMC_CMD(6), arg, MMC_RESPONSE_R1, NULL); 385*91f16700Schasinglulu if (ret != 0) { 386*91f16700Schasinglulu return ret; 387*91f16700Schasinglulu } 388*91f16700Schasinglulu 389*91f16700Schasinglulu return ops->read(0, (uintptr_t)&sd_switch_func_status, 390*91f16700Schasinglulu sizeof(sd_switch_func_status)); 391*91f16700Schasinglulu } 392*91f16700Schasinglulu 393*91f16700Schasinglulu static int sd_send_op_cond(void) 394*91f16700Schasinglulu { 395*91f16700Schasinglulu int n; 396*91f16700Schasinglulu unsigned int resp_data[4]; 397*91f16700Schasinglulu 398*91f16700Schasinglulu for (n = 0; n < SEND_OP_COND_MAX_RETRIES; n++) { 399*91f16700Schasinglulu int ret; 400*91f16700Schasinglulu 401*91f16700Schasinglulu /* CMD55: Application Specific Command */ 402*91f16700Schasinglulu ret = mmc_send_cmd(MMC_CMD(55), 0, MMC_RESPONSE_R1, NULL); 403*91f16700Schasinglulu if (ret != 0) { 404*91f16700Schasinglulu return ret; 405*91f16700Schasinglulu } 406*91f16700Schasinglulu 407*91f16700Schasinglulu /* ACMD41: SD_SEND_OP_COND */ 408*91f16700Schasinglulu ret = mmc_send_cmd(MMC_ACMD(41), OCR_HCS | 409*91f16700Schasinglulu mmc_dev_info->ocr_voltage, MMC_RESPONSE_R3, 410*91f16700Schasinglulu &resp_data[0]); 411*91f16700Schasinglulu if (ret != 0) { 412*91f16700Schasinglulu return ret; 413*91f16700Schasinglulu } 414*91f16700Schasinglulu 415*91f16700Schasinglulu if ((resp_data[0] & OCR_POWERUP) != 0U) { 416*91f16700Schasinglulu mmc_ocr_value = resp_data[0]; 417*91f16700Schasinglulu 418*91f16700Schasinglulu if ((mmc_ocr_value & OCR_HCS) != 0U) { 419*91f16700Schasinglulu mmc_dev_info->mmc_dev_type = MMC_IS_SD_HC; 420*91f16700Schasinglulu } else { 421*91f16700Schasinglulu mmc_dev_info->mmc_dev_type = MMC_IS_SD; 422*91f16700Schasinglulu } 423*91f16700Schasinglulu 424*91f16700Schasinglulu return 0; 425*91f16700Schasinglulu } 426*91f16700Schasinglulu 427*91f16700Schasinglulu mdelay(10); 428*91f16700Schasinglulu } 429*91f16700Schasinglulu 430*91f16700Schasinglulu ERROR("ACMD41 failed after %d retries\n", SEND_OP_COND_MAX_RETRIES); 431*91f16700Schasinglulu 432*91f16700Schasinglulu return -EIO; 433*91f16700Schasinglulu } 434*91f16700Schasinglulu 435*91f16700Schasinglulu static int mmc_reset_to_idle(void) 436*91f16700Schasinglulu { 437*91f16700Schasinglulu int ret; 438*91f16700Schasinglulu 439*91f16700Schasinglulu /* CMD0: reset to IDLE */ 440*91f16700Schasinglulu ret = mmc_send_cmd(MMC_CMD(0), 0, 0, NULL); 441*91f16700Schasinglulu if (ret != 0) { 442*91f16700Schasinglulu return ret; 443*91f16700Schasinglulu } 444*91f16700Schasinglulu 445*91f16700Schasinglulu mdelay(2); 446*91f16700Schasinglulu 447*91f16700Schasinglulu return 0; 448*91f16700Schasinglulu } 449*91f16700Schasinglulu 450*91f16700Schasinglulu static int mmc_send_op_cond(void) 451*91f16700Schasinglulu { 452*91f16700Schasinglulu int ret, n; 453*91f16700Schasinglulu unsigned int resp_data[4]; 454*91f16700Schasinglulu 455*91f16700Schasinglulu for (n = 0; n < SEND_OP_COND_MAX_RETRIES; n++) { 456*91f16700Schasinglulu ret = mmc_send_cmd(MMC_CMD(1), OCR_SECTOR_MODE | 457*91f16700Schasinglulu OCR_VDD_MIN_2V7 | OCR_VDD_MIN_1V7, 458*91f16700Schasinglulu MMC_RESPONSE_R3, &resp_data[0]); 459*91f16700Schasinglulu if (ret != 0) { 460*91f16700Schasinglulu return ret; 461*91f16700Schasinglulu } 462*91f16700Schasinglulu 463*91f16700Schasinglulu if ((resp_data[0] & OCR_POWERUP) != 0U) { 464*91f16700Schasinglulu mmc_ocr_value = resp_data[0]; 465*91f16700Schasinglulu return 0; 466*91f16700Schasinglulu } 467*91f16700Schasinglulu 468*91f16700Schasinglulu mdelay(10); 469*91f16700Schasinglulu } 470*91f16700Schasinglulu 471*91f16700Schasinglulu ERROR("CMD1 failed after %d retries\n", SEND_OP_COND_MAX_RETRIES); 472*91f16700Schasinglulu 473*91f16700Schasinglulu return -EIO; 474*91f16700Schasinglulu } 475*91f16700Schasinglulu 476*91f16700Schasinglulu static int mmc_enumerate(unsigned int clk, unsigned int bus_width) 477*91f16700Schasinglulu { 478*91f16700Schasinglulu int ret; 479*91f16700Schasinglulu unsigned int resp_data[4]; 480*91f16700Schasinglulu 481*91f16700Schasinglulu ops->init(); 482*91f16700Schasinglulu 483*91f16700Schasinglulu ret = mmc_reset_to_idle(); 484*91f16700Schasinglulu if (ret != 0) { 485*91f16700Schasinglulu return ret; 486*91f16700Schasinglulu } 487*91f16700Schasinglulu 488*91f16700Schasinglulu if (mmc_dev_info->mmc_dev_type == MMC_IS_EMMC) { 489*91f16700Schasinglulu ret = mmc_send_op_cond(); 490*91f16700Schasinglulu } else { 491*91f16700Schasinglulu /* CMD8: Send Interface Condition Command */ 492*91f16700Schasinglulu ret = mmc_send_cmd(MMC_CMD(8), VHS_2_7_3_6_V | CMD8_CHECK_PATTERN, 493*91f16700Schasinglulu MMC_RESPONSE_R5, &resp_data[0]); 494*91f16700Schasinglulu 495*91f16700Schasinglulu if ((ret == 0) && ((resp_data[0] & 0xffU) == CMD8_CHECK_PATTERN)) { 496*91f16700Schasinglulu ret = sd_send_op_cond(); 497*91f16700Schasinglulu } 498*91f16700Schasinglulu } 499*91f16700Schasinglulu if (ret != 0) { 500*91f16700Schasinglulu return ret; 501*91f16700Schasinglulu } 502*91f16700Schasinglulu 503*91f16700Schasinglulu /* CMD2: Card Identification */ 504*91f16700Schasinglulu ret = mmc_send_cmd(MMC_CMD(2), 0, MMC_RESPONSE_R2, NULL); 505*91f16700Schasinglulu if (ret != 0) { 506*91f16700Schasinglulu return ret; 507*91f16700Schasinglulu } 508*91f16700Schasinglulu 509*91f16700Schasinglulu /* CMD3: Set Relative Address */ 510*91f16700Schasinglulu if (mmc_dev_info->mmc_dev_type == MMC_IS_EMMC) { 511*91f16700Schasinglulu rca = MMC_FIX_RCA; 512*91f16700Schasinglulu ret = mmc_send_cmd(MMC_CMD(3), rca << RCA_SHIFT_OFFSET, 513*91f16700Schasinglulu MMC_RESPONSE_R1, NULL); 514*91f16700Schasinglulu if (ret != 0) { 515*91f16700Schasinglulu return ret; 516*91f16700Schasinglulu } 517*91f16700Schasinglulu } else { 518*91f16700Schasinglulu ret = mmc_send_cmd(MMC_CMD(3), 0, 519*91f16700Schasinglulu MMC_RESPONSE_R6, &resp_data[0]); 520*91f16700Schasinglulu if (ret != 0) { 521*91f16700Schasinglulu return ret; 522*91f16700Schasinglulu } 523*91f16700Schasinglulu 524*91f16700Schasinglulu rca = (resp_data[0] & 0xFFFF0000U) >> 16; 525*91f16700Schasinglulu } 526*91f16700Schasinglulu 527*91f16700Schasinglulu /* CMD9: CSD Register */ 528*91f16700Schasinglulu ret = mmc_send_cmd(MMC_CMD(9), rca << RCA_SHIFT_OFFSET, 529*91f16700Schasinglulu MMC_RESPONSE_R2, &resp_data[0]); 530*91f16700Schasinglulu if (ret != 0) { 531*91f16700Schasinglulu return ret; 532*91f16700Schasinglulu } 533*91f16700Schasinglulu 534*91f16700Schasinglulu memcpy(&mmc_csd, &resp_data, sizeof(resp_data)); 535*91f16700Schasinglulu 536*91f16700Schasinglulu /* CMD7: Select Card */ 537*91f16700Schasinglulu ret = mmc_send_cmd(MMC_CMD(7), rca << RCA_SHIFT_OFFSET, 538*91f16700Schasinglulu MMC_RESPONSE_R1, NULL); 539*91f16700Schasinglulu if (ret != 0) { 540*91f16700Schasinglulu return ret; 541*91f16700Schasinglulu } 542*91f16700Schasinglulu 543*91f16700Schasinglulu do { 544*91f16700Schasinglulu ret = mmc_device_state(); 545*91f16700Schasinglulu if (ret < 0) { 546*91f16700Schasinglulu return ret; 547*91f16700Schasinglulu } 548*91f16700Schasinglulu } while (ret != MMC_STATE_TRAN); 549*91f16700Schasinglulu 550*91f16700Schasinglulu ret = mmc_set_ios(clk, bus_width); 551*91f16700Schasinglulu if (ret != 0) { 552*91f16700Schasinglulu return ret; 553*91f16700Schasinglulu } 554*91f16700Schasinglulu 555*91f16700Schasinglulu ret = mmc_fill_device_info(); 556*91f16700Schasinglulu if (ret != 0) { 557*91f16700Schasinglulu return ret; 558*91f16700Schasinglulu } 559*91f16700Schasinglulu 560*91f16700Schasinglulu if (is_sd_cmd6_enabled() && 561*91f16700Schasinglulu (mmc_dev_info->mmc_dev_type == MMC_IS_SD_HC)) { 562*91f16700Schasinglulu /* Try to switch to High Speed Mode */ 563*91f16700Schasinglulu ret = sd_switch(SD_SWITCH_FUNC_CHECK, 1U, 1U); 564*91f16700Schasinglulu if (ret != 0) { 565*91f16700Schasinglulu return ret; 566*91f16700Schasinglulu } 567*91f16700Schasinglulu 568*91f16700Schasinglulu if ((sd_switch_func_status.support_g1 & BIT(9)) == 0U) { 569*91f16700Schasinglulu /* High speed not supported, keep default speed */ 570*91f16700Schasinglulu return 0; 571*91f16700Schasinglulu } 572*91f16700Schasinglulu 573*91f16700Schasinglulu ret = sd_switch(SD_SWITCH_FUNC_SWITCH, 1U, 1U); 574*91f16700Schasinglulu if (ret != 0) { 575*91f16700Schasinglulu return ret; 576*91f16700Schasinglulu } 577*91f16700Schasinglulu 578*91f16700Schasinglulu if ((sd_switch_func_status.sel_g2_g1 & 0x1U) == 0U) { 579*91f16700Schasinglulu /* Cannot switch to high speed, keep default speed */ 580*91f16700Schasinglulu return 0; 581*91f16700Schasinglulu } 582*91f16700Schasinglulu 583*91f16700Schasinglulu mmc_dev_info->max_bus_freq = 50000000U; 584*91f16700Schasinglulu ret = ops->set_ios(clk, bus_width); 585*91f16700Schasinglulu } 586*91f16700Schasinglulu 587*91f16700Schasinglulu return ret; 588*91f16700Schasinglulu } 589*91f16700Schasinglulu 590*91f16700Schasinglulu size_t mmc_read_blocks(int lba, uintptr_t buf, size_t size) 591*91f16700Schasinglulu { 592*91f16700Schasinglulu int ret; 593*91f16700Schasinglulu unsigned int cmd_idx, cmd_arg; 594*91f16700Schasinglulu 595*91f16700Schasinglulu assert((ops != NULL) && 596*91f16700Schasinglulu (ops->read != NULL) && 597*91f16700Schasinglulu (size != 0U) && 598*91f16700Schasinglulu ((size & MMC_BLOCK_MASK) == 0U)); 599*91f16700Schasinglulu 600*91f16700Schasinglulu ret = ops->prepare(lba, buf, size); 601*91f16700Schasinglulu if (ret != 0) { 602*91f16700Schasinglulu return 0; 603*91f16700Schasinglulu } 604*91f16700Schasinglulu 605*91f16700Schasinglulu if (is_cmd23_enabled()) { 606*91f16700Schasinglulu /* Set block count */ 607*91f16700Schasinglulu ret = mmc_send_cmd(MMC_CMD(23), size / MMC_BLOCK_SIZE, 608*91f16700Schasinglulu MMC_RESPONSE_R1, NULL); 609*91f16700Schasinglulu if (ret != 0) { 610*91f16700Schasinglulu return 0; 611*91f16700Schasinglulu } 612*91f16700Schasinglulu 613*91f16700Schasinglulu cmd_idx = MMC_CMD(18); 614*91f16700Schasinglulu } else { 615*91f16700Schasinglulu if (size > MMC_BLOCK_SIZE) { 616*91f16700Schasinglulu cmd_idx = MMC_CMD(18); 617*91f16700Schasinglulu } else { 618*91f16700Schasinglulu cmd_idx = MMC_CMD(17); 619*91f16700Schasinglulu } 620*91f16700Schasinglulu } 621*91f16700Schasinglulu 622*91f16700Schasinglulu if (((mmc_ocr_value & OCR_ACCESS_MODE_MASK) == OCR_BYTE_MODE) && 623*91f16700Schasinglulu (mmc_dev_info->mmc_dev_type != MMC_IS_SD_HC)) { 624*91f16700Schasinglulu cmd_arg = lba * MMC_BLOCK_SIZE; 625*91f16700Schasinglulu } else { 626*91f16700Schasinglulu cmd_arg = lba; 627*91f16700Schasinglulu } 628*91f16700Schasinglulu 629*91f16700Schasinglulu ret = mmc_send_cmd(cmd_idx, cmd_arg, MMC_RESPONSE_R1, NULL); 630*91f16700Schasinglulu if (ret != 0) { 631*91f16700Schasinglulu return 0; 632*91f16700Schasinglulu } 633*91f16700Schasinglulu 634*91f16700Schasinglulu ret = ops->read(lba, buf, size); 635*91f16700Schasinglulu if (ret != 0) { 636*91f16700Schasinglulu return 0; 637*91f16700Schasinglulu } 638*91f16700Schasinglulu 639*91f16700Schasinglulu /* Wait buffer empty */ 640*91f16700Schasinglulu do { 641*91f16700Schasinglulu ret = mmc_device_state(); 642*91f16700Schasinglulu if (ret < 0) { 643*91f16700Schasinglulu return 0; 644*91f16700Schasinglulu } 645*91f16700Schasinglulu } while ((ret != MMC_STATE_TRAN) && (ret != MMC_STATE_DATA)); 646*91f16700Schasinglulu 647*91f16700Schasinglulu if (!is_cmd23_enabled() && (size > MMC_BLOCK_SIZE)) { 648*91f16700Schasinglulu ret = mmc_send_cmd(MMC_CMD(12), 0, MMC_RESPONSE_R1B, NULL); 649*91f16700Schasinglulu if (ret != 0) { 650*91f16700Schasinglulu return 0; 651*91f16700Schasinglulu } 652*91f16700Schasinglulu } 653*91f16700Schasinglulu 654*91f16700Schasinglulu return size; 655*91f16700Schasinglulu } 656*91f16700Schasinglulu 657*91f16700Schasinglulu size_t mmc_write_blocks(int lba, const uintptr_t buf, size_t size) 658*91f16700Schasinglulu { 659*91f16700Schasinglulu int ret; 660*91f16700Schasinglulu unsigned int cmd_idx, cmd_arg; 661*91f16700Schasinglulu 662*91f16700Schasinglulu assert((ops != NULL) && 663*91f16700Schasinglulu (ops->write != NULL) && 664*91f16700Schasinglulu (size != 0U) && 665*91f16700Schasinglulu ((buf & MMC_BLOCK_MASK) == 0U) && 666*91f16700Schasinglulu ((size & MMC_BLOCK_MASK) == 0U)); 667*91f16700Schasinglulu 668*91f16700Schasinglulu ret = ops->prepare(lba, buf, size); 669*91f16700Schasinglulu if (ret != 0) { 670*91f16700Schasinglulu return 0; 671*91f16700Schasinglulu } 672*91f16700Schasinglulu 673*91f16700Schasinglulu if (is_cmd23_enabled()) { 674*91f16700Schasinglulu /* Set block count */ 675*91f16700Schasinglulu ret = mmc_send_cmd(MMC_CMD(23), size / MMC_BLOCK_SIZE, 676*91f16700Schasinglulu MMC_RESPONSE_R1, NULL); 677*91f16700Schasinglulu if (ret != 0) { 678*91f16700Schasinglulu return 0; 679*91f16700Schasinglulu } 680*91f16700Schasinglulu 681*91f16700Schasinglulu cmd_idx = MMC_CMD(25); 682*91f16700Schasinglulu } else { 683*91f16700Schasinglulu if (size > MMC_BLOCK_SIZE) { 684*91f16700Schasinglulu cmd_idx = MMC_CMD(25); 685*91f16700Schasinglulu } else { 686*91f16700Schasinglulu cmd_idx = MMC_CMD(24); 687*91f16700Schasinglulu } 688*91f16700Schasinglulu } 689*91f16700Schasinglulu 690*91f16700Schasinglulu if ((mmc_ocr_value & OCR_ACCESS_MODE_MASK) == OCR_BYTE_MODE) { 691*91f16700Schasinglulu cmd_arg = lba * MMC_BLOCK_SIZE; 692*91f16700Schasinglulu } else { 693*91f16700Schasinglulu cmd_arg = lba; 694*91f16700Schasinglulu } 695*91f16700Schasinglulu 696*91f16700Schasinglulu ret = mmc_send_cmd(cmd_idx, cmd_arg, MMC_RESPONSE_R1, NULL); 697*91f16700Schasinglulu if (ret != 0) { 698*91f16700Schasinglulu return 0; 699*91f16700Schasinglulu } 700*91f16700Schasinglulu 701*91f16700Schasinglulu ret = ops->write(lba, buf, size); 702*91f16700Schasinglulu if (ret != 0) { 703*91f16700Schasinglulu return 0; 704*91f16700Schasinglulu } 705*91f16700Schasinglulu 706*91f16700Schasinglulu /* Wait buffer empty */ 707*91f16700Schasinglulu do { 708*91f16700Schasinglulu ret = mmc_device_state(); 709*91f16700Schasinglulu if (ret < 0) { 710*91f16700Schasinglulu return 0; 711*91f16700Schasinglulu } 712*91f16700Schasinglulu } while ((ret != MMC_STATE_TRAN) && (ret != MMC_STATE_RCV)); 713*91f16700Schasinglulu 714*91f16700Schasinglulu if (!is_cmd23_enabled() && (size > MMC_BLOCK_SIZE)) { 715*91f16700Schasinglulu ret = mmc_send_cmd(MMC_CMD(12), 0, MMC_RESPONSE_R1B, NULL); 716*91f16700Schasinglulu if (ret != 0) { 717*91f16700Schasinglulu return 0; 718*91f16700Schasinglulu } 719*91f16700Schasinglulu } 720*91f16700Schasinglulu 721*91f16700Schasinglulu return size; 722*91f16700Schasinglulu } 723*91f16700Schasinglulu 724*91f16700Schasinglulu size_t mmc_erase_blocks(int lba, size_t size) 725*91f16700Schasinglulu { 726*91f16700Schasinglulu int ret; 727*91f16700Schasinglulu 728*91f16700Schasinglulu assert(ops != NULL); 729*91f16700Schasinglulu assert((size != 0U) && ((size & MMC_BLOCK_MASK) == 0U)); 730*91f16700Schasinglulu 731*91f16700Schasinglulu ret = mmc_send_cmd(MMC_CMD(35), lba, MMC_RESPONSE_R1, NULL); 732*91f16700Schasinglulu if (ret != 0) { 733*91f16700Schasinglulu return 0; 734*91f16700Schasinglulu } 735*91f16700Schasinglulu 736*91f16700Schasinglulu ret = mmc_send_cmd(MMC_CMD(36), lba + (size / MMC_BLOCK_SIZE) - 1U, 737*91f16700Schasinglulu MMC_RESPONSE_R1, NULL); 738*91f16700Schasinglulu if (ret != 0) { 739*91f16700Schasinglulu return 0; 740*91f16700Schasinglulu } 741*91f16700Schasinglulu 742*91f16700Schasinglulu ret = mmc_send_cmd(MMC_CMD(38), lba, MMC_RESPONSE_R1B, NULL); 743*91f16700Schasinglulu if (ret != 0) { 744*91f16700Schasinglulu return 0; 745*91f16700Schasinglulu } 746*91f16700Schasinglulu 747*91f16700Schasinglulu do { 748*91f16700Schasinglulu ret = mmc_device_state(); 749*91f16700Schasinglulu if (ret < 0) { 750*91f16700Schasinglulu return 0; 751*91f16700Schasinglulu } 752*91f16700Schasinglulu } while (ret != MMC_STATE_TRAN); 753*91f16700Schasinglulu 754*91f16700Schasinglulu return size; 755*91f16700Schasinglulu } 756*91f16700Schasinglulu 757*91f16700Schasinglulu static int mmc_part_switch(unsigned char part_type) 758*91f16700Schasinglulu { 759*91f16700Schasinglulu unsigned char part_config = mmc_ext_csd[CMD_EXTCSD_PARTITION_CONFIG]; 760*91f16700Schasinglulu 761*91f16700Schasinglulu part_config &= ~EXT_CSD_PART_CONFIG_ACC_MASK; 762*91f16700Schasinglulu part_config |= part_type; 763*91f16700Schasinglulu 764*91f16700Schasinglulu return mmc_send_part_switch_cmd(part_config); 765*91f16700Schasinglulu } 766*91f16700Schasinglulu 767*91f16700Schasinglulu static unsigned char mmc_current_boot_part(void) 768*91f16700Schasinglulu { 769*91f16700Schasinglulu return PART_CFG_CURRENT_BOOT_PARTITION(mmc_ext_csd[CMD_EXTCSD_PARTITION_CONFIG]); 770*91f16700Schasinglulu } 771*91f16700Schasinglulu 772*91f16700Schasinglulu int mmc_part_switch_current_boot(void) 773*91f16700Schasinglulu { 774*91f16700Schasinglulu unsigned char current_boot_part = mmc_current_boot_part(); 775*91f16700Schasinglulu int ret; 776*91f16700Schasinglulu 777*91f16700Schasinglulu if ((current_boot_part != 1U) && (current_boot_part != 2U)) { 778*91f16700Schasinglulu ERROR("Got unexpected value for active boot partition, %u\n", current_boot_part); 779*91f16700Schasinglulu return -EIO; 780*91f16700Schasinglulu } 781*91f16700Schasinglulu 782*91f16700Schasinglulu ret = mmc_part_switch(current_boot_part); 783*91f16700Schasinglulu if (ret < 0) { 784*91f16700Schasinglulu ERROR("Failed to switch to boot partition, %d\n", ret); 785*91f16700Schasinglulu } 786*91f16700Schasinglulu 787*91f16700Schasinglulu return ret; 788*91f16700Schasinglulu } 789*91f16700Schasinglulu 790*91f16700Schasinglulu int mmc_part_switch_user(void) 791*91f16700Schasinglulu { 792*91f16700Schasinglulu int ret; 793*91f16700Schasinglulu 794*91f16700Schasinglulu ret = mmc_part_switch(PART_CFG_BOOT_PARTITION_NO_ACCESS); 795*91f16700Schasinglulu if (ret < 0) { 796*91f16700Schasinglulu ERROR("Failed to switch to user partition, %d\n", ret); 797*91f16700Schasinglulu } 798*91f16700Schasinglulu 799*91f16700Schasinglulu return ret; 800*91f16700Schasinglulu } 801*91f16700Schasinglulu 802*91f16700Schasinglulu size_t mmc_boot_part_size(void) 803*91f16700Schasinglulu { 804*91f16700Schasinglulu return mmc_ext_csd[CMD_EXTCSD_BOOT_SIZE_MULT] * SZ_128K; 805*91f16700Schasinglulu } 806*91f16700Schasinglulu 807*91f16700Schasinglulu size_t mmc_boot_part_read_blocks(int lba, uintptr_t buf, size_t size) 808*91f16700Schasinglulu { 809*91f16700Schasinglulu size_t size_read; 810*91f16700Schasinglulu int ret; 811*91f16700Schasinglulu 812*91f16700Schasinglulu ret = mmc_part_switch_current_boot(); 813*91f16700Schasinglulu if (ret < 0) { 814*91f16700Schasinglulu return 0; 815*91f16700Schasinglulu } 816*91f16700Schasinglulu 817*91f16700Schasinglulu size_read = mmc_read_blocks(lba, buf, size); 818*91f16700Schasinglulu 819*91f16700Schasinglulu ret = mmc_part_switch_user(); 820*91f16700Schasinglulu if (ret < 0) { 821*91f16700Schasinglulu return 0; 822*91f16700Schasinglulu } 823*91f16700Schasinglulu 824*91f16700Schasinglulu return size_read; 825*91f16700Schasinglulu } 826*91f16700Schasinglulu 827*91f16700Schasinglulu int mmc_init(const struct mmc_ops *ops_ptr, unsigned int clk, 828*91f16700Schasinglulu unsigned int width, unsigned int flags, 829*91f16700Schasinglulu struct mmc_device_info *device_info) 830*91f16700Schasinglulu { 831*91f16700Schasinglulu assert((ops_ptr != NULL) && 832*91f16700Schasinglulu (ops_ptr->init != NULL) && 833*91f16700Schasinglulu (ops_ptr->send_cmd != NULL) && 834*91f16700Schasinglulu (ops_ptr->set_ios != NULL) && 835*91f16700Schasinglulu (ops_ptr->prepare != NULL) && 836*91f16700Schasinglulu (ops_ptr->read != NULL) && 837*91f16700Schasinglulu (ops_ptr->write != NULL) && 838*91f16700Schasinglulu (device_info != NULL) && 839*91f16700Schasinglulu (clk != 0) && 840*91f16700Schasinglulu ((width == MMC_BUS_WIDTH_1) || 841*91f16700Schasinglulu (width == MMC_BUS_WIDTH_4) || 842*91f16700Schasinglulu (width == MMC_BUS_WIDTH_8) || 843*91f16700Schasinglulu (width == MMC_BUS_WIDTH_DDR_4) || 844*91f16700Schasinglulu (width == MMC_BUS_WIDTH_DDR_8))); 845*91f16700Schasinglulu 846*91f16700Schasinglulu ops = ops_ptr; 847*91f16700Schasinglulu mmc_flags = flags; 848*91f16700Schasinglulu mmc_dev_info = device_info; 849*91f16700Schasinglulu 850*91f16700Schasinglulu return mmc_enumerate(clk, width); 851*91f16700Schasinglulu } 852