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