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