/** * @file sdrv_mmc_sdhci.c * @brief sdrv mmc sdhci drv source. * * @copyright Copyright (c) 2020 Semidrive Semiconductor. * All rights reserved. */ #include #include #include #include #include #include #include #include #include #include #include #define SEHC_MAX_TUNING_LOOP 140 /* SDHCI SEHC REG */ #define SDHCI_DLL_CTRL (0x100) #define SDHCI_DLL_STATUS (0x104) #define SDHCI_EMMC_CTRL_REG (0x10C) #define SDHCI_TUNING_CTRL_REG (0x118) #define SDHCI_TUNING_STATUS_REG (0x11C) #define SDHCI_OE_MASK_SEL_REG (0x124) /* dll related macros */ #define SDHCI_DLL_SLV_TARGET_MASK 0x3f #define SDHCI_DLL_SLV_TARGET_OFFSET 0x1 #define SDHCI_DLL_EN 0x00000001 #define SDHCI_DLL_REF_LOCK 0x00000001 /* emmc related macros */ #define SDHCI_RST_N 0x100 #define SDHCI_FIX_BLK_SIZE 0x20 #define SDHCI_CLK_STP_BLK_GAP 0x10 #define SDHCI_EMMC_EXT 0x2 #define SDHCI_ENHANCE_HS400_EN 0x1 /* tuning related macros */ #define SDHCI_TUNING_CLK_STOP_EN 0x80000000 #define SDHCI_DELAY_TAP_VALUE_MASK 0x3f #define SDHCI_DELAY_TAP_VALUE_OFFSET 0x10 #define SDHCI_OVERRIDE_VAL_MASK 0x7f #define SDHCI_OVERRIDE_VAL_OFFSET 0x9 #define SDHCI_OVERRIDE_EN 0x00000100 #define SDHCI_TAP_STEP_MASK 0x3 #define SDHCI_TAP_STEP_OFFSET 0x6 #define SDHCI_START_TAP_MASK 0x3f #define SDHCI_START_TAP_OFFSET 0x0 #define SDHCI_TUNING_TAP_VALUE_MASK 0x7f #define SDHCI_TUNING_TAP_VALUE_OFFSET 0x14 #define SDHCI_FAIL_NUM_MASK 0x7f #define SDHCI_FAIL_NUM_OFFSET 0xc #define SDHCI_PASS_NUM_MASK 0x7f #define SDHCI_PASS_NUM_OFFSET 0x4 #define SDHCI_SEC_FAIL_FLAG 0x00000008 #define SDHCI_FIR_PASS_FLAG 0x00000004 #define SDHCI_FIR_FAIL_FLAG 0x00000002 #define SDHCI_TUNING_FAIL 0x00000001 /* SEHC TUNING related macros */ #define SEHC_TUNE_CTRL_MIN 0 #define SEHC_1_0_TUNE_CTRL_MIN 20 #define SEHC_TUNE_CTRL_MAX 128 #define SEHC_TUNE_CTRL_STEP 1 #define SEHC_TUNE_WINDOW_MIN 5 /* SDHCI OE related macros */ #define SDHCI_CMD_OE_MASK_SEL 0x3 #define SDHCI_CMD_OE_OFFSET 0x0 #define SDHCI_DAT_OE_MASK_SEL 0xc #define SDHCI_DAT_OE_OFFSET 0x2 // NOTE: for test on zone, need define WITH_ON_ZONE macro //#define WITH_ON_ZONE 1 #define USE_TARGET_HS200_CAPS 1 /* data access time unit in ns */ static const uint32_t taac_unit[] = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000 }; /* data access time value x 10 */ static const uint32_t taac_value[] = {0, 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80 }; /* data transfer rate in kbit/s */ static const uint32_t xfer_rate_unit[] = {100, 1000, 10000, 100000, 0, 0, 0, 0}; /* data transfer rate value x 10*/ static const uint32_t xfer_rate_value[] = {0, 10, 12, 13, 15, 20, 26, 30, 35, 40, 45, 52, 55, 60, 70, 80 }; #define TUNING_BLK_SIZE 128 static uint8_t tuning_data[TUNING_BLK_SIZE] __ALIGNED(CONFIG_ARCH_CACHE_LINE); static const uint8_t tuning_blk_pattern_4bit[] = { 0xff, 0x0f, 0xff, 0x00, 0xff, 0xcc, 0xc3, 0xcc, 0xc3, 0x3c, 0xcc, 0xff, 0xfe, 0xff, 0xfe, 0xef, 0xff, 0xdf, 0xff, 0xdd, 0xff, 0xfb, 0xff, 0xfb, 0xbf, 0xff, 0x7f, 0xff, 0x77, 0xf7, 0xbd, 0xef, 0xff, 0xf0, 0xff, 0xf0, 0x0f, 0xfc, 0xcc, 0x3c, 0xcc, 0x33, 0xcc, 0xcf, 0xff, 0xef, 0xff, 0xee, 0xff, 0xfd, 0xff, 0xfd, 0xdf, 0xff, 0xbf, 0xff, 0xbb, 0xff, 0xf7, 0xff, 0xf7, 0x7f, 0x7b, 0xde, }; static const uint8_t tuning_blk_pattern_8bit[] = { 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, 0xcc, 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, 0xff, 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, 0xff, 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, 0xdd, 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, 0xbb, 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, 0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, 0xcc, 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, 0xff, 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, 0xff, 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, 0xdd, 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, 0xbb, 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, 0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, }; /* * Function: mmc decode and save csd * Arg : Card structure & raw csd * Return : 0 on Success, 1 on Failure * Flow : Decodes CSD response received from the card. * Note that we have defined only few of the CSD elements * in csd structure. We'll only decode those values. */ static status_t sdrv_mmc_decode_and_save_csd(struct mmc_card *card) { uint32_t mmc_sizeof = 0; uint32_t mmc_unit = 0; uint32_t mmc_value = 0; uint32_t mmc_temp = 0; uint32_t *raw_csd = card->raw_csd; struct mmc_csd mmc_csd; mmc_sizeof = sizeof(uint32_t) * 8; mmc_csd.cmmc_structure = UNPACK_BITS(raw_csd, 126, 2, mmc_sizeof); if (MMC_CARD_SD(card)) { /* Parse CSD according to SD card spec. */ /* * CSD register is little bit differnet for CSD version 2.0 High * Capacity and CSD version 1.0/2.0 Standard memory cards. * In Version 2.0 some of the fields have fixed values and it's * not necessary for host to refer these fields in CSD sent by * card */ if (mmc_csd.cmmc_structure == 1) { /* CSD Version 2.0 */ mmc_csd.card_cmd_class = UNPACK_BITS(raw_csd, 84, 12, mmc_sizeof); /* Fixed value is 9 = 2^9 = 512 */ mmc_csd.write_blk_len = 512; /* Fixed value is 9 = 512 */ mmc_csd.read_blk_len = 512; /* Fixed value: 010b */ mmc_csd.r2w_factor = 0x2; /* Not there in version 2.0 */ mmc_csd.c_size_mult = 0; mmc_csd.c_size = UNPACK_BITS(raw_csd, 48, 22, mmc_sizeof); mmc_csd.nsac_clk_cycle = UNPACK_BITS(raw_csd, 104, 8, mmc_sizeof) * 100; mmc_unit = UNPACK_BITS(raw_csd, 112, 3, mmc_sizeof); mmc_value = UNPACK_BITS(raw_csd, 115, 4, mmc_sizeof); mmc_csd.taac_ns = 0; /* Unused */ mmc_csd.taac_clks = 0; /* Unused */ mmc_csd.erase_blk_len = 1; mmc_csd.read_blk_misalign = 0; mmc_csd.write_blk_misalign = 0; mmc_csd.read_blk_partial = 0; mmc_csd.write_blk_partial = 0; mmc_unit = UNPACK_BITS(raw_csd, 96, 3, mmc_sizeof); mmc_value = UNPACK_BITS(raw_csd, 99, 4, mmc_sizeof); mmc_csd.tran_speed = (xfer_rate_value[mmc_value] * xfer_rate_unit[mmc_unit]) / 10; mmc_csd.wp_grp_size = 0x0; mmc_csd.wp_grp_enable = 0x0; mmc_csd.perm_wp = UNPACK_BITS(raw_csd, 13, 1, mmc_sizeof); mmc_csd.temp_wp = UNPACK_BITS(raw_csd, 12, 1, mmc_sizeof); /* Calculate the card capcity */ card->capacity = (unsigned long long)(1 + mmc_csd.c_size) * 512 * 1024; } else { /* CSD Version 1.0 */ mmc_csd.card_cmd_class = UNPACK_BITS(raw_csd, 84, 12, mmc_sizeof); mmc_temp = UNPACK_BITS(raw_csd, 22, 4, mmc_sizeof); mmc_csd.write_blk_len = (mmc_temp > 8 && mmc_temp < 12) ? (1 << mmc_temp) : 512; mmc_temp = UNPACK_BITS(raw_csd, 80, 4, mmc_sizeof); mmc_csd.read_blk_len = (mmc_temp > 8 && mmc_temp < 12) ? (1 << mmc_temp) : 512; mmc_unit = UNPACK_BITS(raw_csd, 112, 3, mmc_sizeof); mmc_value = UNPACK_BITS(raw_csd, 115, 4, mmc_sizeof); mmc_csd.taac_ns = (taac_value[mmc_value] * taac_unit[mmc_unit] + 9) / 10; mmc_csd.taac_clks = UNPACK_BITS(raw_csd, 104, 8, mmc_sizeof) * 100; mmc_unit = UNPACK_BITS(raw_csd, 96, 3, mmc_sizeof); mmc_value = UNPACK_BITS(raw_csd, 99, 4, mmc_sizeof); mmc_csd.tran_speed = (xfer_rate_value[mmc_value] * xfer_rate_unit[mmc_unit]) / 10; mmc_csd.nsac_clk_cycle = UNPACK_BITS(raw_csd, 104, 8, mmc_sizeof) * 100; mmc_csd.r2w_factor = UNPACK_BITS(raw_csd, 26, 3, mmc_sizeof); mmc_csd.sector_size = UNPACK_BITS(raw_csd, 39, 7, mmc_sizeof) + 1; mmc_csd.erase_blk_len = UNPACK_BITS(raw_csd, 46, 1, mmc_sizeof); mmc_csd.read_blk_misalign = UNPACK_BITS(raw_csd, 77, 1, mmc_sizeof); mmc_csd.write_blk_misalign = UNPACK_BITS(raw_csd, 78, 1, mmc_sizeof); mmc_csd.read_blk_partial = UNPACK_BITS(raw_csd, 79, 1, mmc_sizeof); mmc_csd.write_blk_partial = UNPACK_BITS(raw_csd, 21, 1, mmc_sizeof); mmc_csd.c_size_mult = UNPACK_BITS(raw_csd, 47, 3, mmc_sizeof); mmc_csd.c_size = UNPACK_BITS(raw_csd, 62, 12, mmc_sizeof); mmc_csd.wp_grp_size = UNPACK_BITS(raw_csd, 32, 7, mmc_sizeof); mmc_csd.wp_grp_enable = UNPACK_BITS(raw_csd, 31, 1, mmc_sizeof); mmc_csd.perm_wp = UNPACK_BITS(raw_csd, 13, 1, mmc_sizeof); mmc_csd.temp_wp = UNPACK_BITS(raw_csd, 12, 1, mmc_sizeof); /* Calculate the card capacity */ mmc_temp = (1 << (mmc_csd.c_size_mult + 2)) * (mmc_csd.c_size + 1); card->capacity = (unsigned long long)mmc_temp * mmc_csd.read_blk_len; } } else { /* Parse CSD according to MMC card spec. */ mmc_csd.spec_vers = UNPACK_BITS(raw_csd, 122, 4, mmc_sizeof); mmc_csd.card_cmd_class = UNPACK_BITS(raw_csd, 84, 12, mmc_sizeof); mmc_csd.write_blk_len = 1 << UNPACK_BITS(raw_csd, 22, 4, mmc_sizeof); mmc_csd.read_blk_len = 1 << UNPACK_BITS(raw_csd, 80, 4, mmc_sizeof); mmc_csd.r2w_factor = UNPACK_BITS(raw_csd, 26, 3, mmc_sizeof); mmc_csd.c_size_mult = UNPACK_BITS(raw_csd, 47, 3, mmc_sizeof); mmc_csd.c_size = UNPACK_BITS(raw_csd, 62, 12, mmc_sizeof); mmc_csd.nsac_clk_cycle = UNPACK_BITS(raw_csd, 104, 8, mmc_sizeof) * 100; mmc_unit = UNPACK_BITS(raw_csd, 112, 3, mmc_sizeof); mmc_value = UNPACK_BITS(raw_csd, 115, 4, mmc_sizeof); mmc_csd.taac_ns = (taac_value[mmc_value] * taac_unit[mmc_unit] + 9) / 10; mmc_csd.taac_clks = UNPACK_BITS(raw_csd, 104, 8, mmc_sizeof) * 100; mmc_csd.read_blk_misalign = UNPACK_BITS(raw_csd, 77, 1, mmc_sizeof); mmc_csd.write_blk_misalign = UNPACK_BITS(raw_csd, 78, 1, mmc_sizeof); mmc_csd.read_blk_partial = UNPACK_BITS(raw_csd, 79, 1, mmc_sizeof); mmc_csd.write_blk_partial = UNPACK_BITS(raw_csd, 21, 1, mmc_sizeof); /* Ignore -- no use of this value. */ mmc_csd.tran_speed = 0x00; mmc_csd.erase_grp_size = UNPACK_BITS(raw_csd, 42, 5, mmc_sizeof); mmc_csd.erase_grp_mult = UNPACK_BITS(raw_csd, 37, 5, mmc_sizeof); mmc_csd.wp_grp_size = UNPACK_BITS(raw_csd, 32, 5, mmc_sizeof); mmc_csd.wp_grp_enable = UNPACK_BITS(raw_csd, 31, 1, mmc_sizeof); mmc_csd.perm_wp = UNPACK_BITS(raw_csd, 13, 1, mmc_sizeof); mmc_csd.temp_wp = UNPACK_BITS(raw_csd, 12, 1, mmc_sizeof); /* Calculate the card capcity */ if (mmc_csd.c_size != 0xFFF) { /* For cards less than or equal to 2GB */ mmc_temp = (1 << (mmc_csd.c_size_mult + 2)) * (mmc_csd.c_size + 1); card->capacity = (unsigned long long)mmc_temp * mmc_csd.read_blk_len; } else { /* For cards greater than 2GB, Ext CSD register's SEC_COUNT * is used to calculate the size. */ uint64_t sec_count; sec_count = (card->ext_csd[MMC_SEC_COUNT4] << MMC_SEC_COUNT4_SHIFT) | (card->ext_csd[MMC_SEC_COUNT3] << MMC_SEC_COUNT3_SHIFT) | (card->ext_csd[MMC_SEC_COUNT2] << MMC_SEC_COUNT2_SHIFT) | card->ext_csd[MMC_SEC_COUNT1]; card->capacity = sec_count * MMC_BLK_SZ; } } /* save the information in card structure */ memcpy(&card->csd, &mmc_csd, sizeof(struct mmc_csd)); /* Calculate the wp grp size */ if (MMC_CARD_MMC(card)) { if (card->ext_csd[MMC_ERASE_GRP_DEF]) card->wp_grp_size = MMC_HC_ERASE_MULT * card->ext_csd[MMC_HC_ERASE_GRP_SIZE] / MMC_BLK_SZ; else card->wp_grp_size = (card->csd.wp_grp_size + 1) * (card->csd.erase_grp_size + 1) * (card->csd.erase_grp_mult + 1); card->boot_size = BOOT_PART_MIN_SIZE * card->ext_csd[BOOT_SIZE_MULT]; card->rpmb_size = RPMB_PART_MIN_SIZE * card->ext_csd[RPMB_SIZE_MULT]; card->rel_wr_count = card->ext_csd[REL_WR_SEC_C]; } else { card->wp_grp_size = (card->csd.wp_grp_size + 1) * (card->csd.erase_grp_size + 1) * (card->csd.erase_grp_mult + 1); } ssdk_printf(SSDK_INFO, "Decoded CSD fields:\r\n"); ssdk_printf(SSDK_INFO, "cmmc_structure: %u\r\n", mmc_csd.cmmc_structure); ssdk_printf(SSDK_INFO, "card_cmd_class: %x\r\n", mmc_csd.card_cmd_class); ssdk_printf(SSDK_INFO, "write_blk_len: %u\r\n", mmc_csd.write_blk_len); ssdk_printf(SSDK_INFO, "read_blk_len: %u\r\n", mmc_csd.read_blk_len); ssdk_printf(SSDK_INFO, "r2w_factor: %u\r\n", mmc_csd.r2w_factor); ssdk_printf(SSDK_INFO, "sector_size: %u\r\n", mmc_csd.sector_size); ssdk_printf(SSDK_INFO, "c_size_mult:%u\r\n", mmc_csd.c_size_mult); ssdk_printf(SSDK_INFO, "c_size: %u\r\n", mmc_csd.c_size); ssdk_printf(SSDK_INFO, "nsac_clk_cycle: %u\r\n", mmc_csd.nsac_clk_cycle); ssdk_printf(SSDK_INFO, "taac_ns: %u\r\n", mmc_csd.taac_ns); ssdk_printf(SSDK_INFO, "taac_clks: %u\r\n", mmc_csd.taac_clks); ssdk_printf(SSDK_INFO, "tran_speed: %u kbps\r\n", mmc_csd.tran_speed); ssdk_printf(SSDK_INFO, "erase_blk_len: %u\r\n", mmc_csd.erase_blk_len); ssdk_printf(SSDK_INFO, "read_blk_misalign: %u\r\n", mmc_csd.read_blk_misalign); ssdk_printf(SSDK_INFO, "write_blk_misalign: %u\r\n", mmc_csd.write_blk_misalign); ssdk_printf(SSDK_INFO, "read_blk_partial: %u\r\n", mmc_csd.read_blk_partial); ssdk_printf(SSDK_INFO, "write_blk_partial: %u\r\n", mmc_csd.write_blk_partial); ssdk_printf(SSDK_INFO, "wp_grp_size: %u\r\n", card->wp_grp_size); ssdk_printf(SSDK_INFO, "Card Capacity: %llu Bytes\r\n", card->capacity); return SDRV_STATUS_OK; } /* * Function: mmc decode & save cid * Arg : card structure & raw cid * Return : 0 on Success, 1 on Failure * Flow : Decode CID sent by the card. */ static status_t sdrv_mmc_decode_and_save_cid(struct mmc_card *card, uint32_t *raw_cid) { struct mmc_cid mmc_cid; uint32_t mmc_sizeof = 0; int i = 0; if (!raw_cid) { return SDRV_STATUS_INVALID_PARAM; } mmc_sizeof = sizeof(uint32_t) * 8; if (MMC_CARD_SD(card)) { mmc_cid.mid = UNPACK_BITS(raw_cid, 120, 8, mmc_sizeof); mmc_cid.oid = UNPACK_BITS(raw_cid, 104, 16, mmc_sizeof); for (i = 0; i < 5; i++) { mmc_cid.pnm[i] = (uint8_t)UNPACK_BITS(raw_cid, (104 - 8 * (i + 1)), 8, mmc_sizeof); } mmc_cid.pnm[5] = 0; mmc_cid.pnm[6] = 0; mmc_cid.prv = UNPACK_BITS(raw_cid, 56, 8, mmc_sizeof); mmc_cid.psn = UNPACK_BITS(raw_cid, 24, 32, mmc_sizeof); mmc_cid.month = UNPACK_BITS(raw_cid, 8, 4, mmc_sizeof); mmc_cid.year = UNPACK_BITS(raw_cid, 12, 8, mmc_sizeof); mmc_cid.year += 2000; } else { mmc_cid.mid = UNPACK_BITS(raw_cid, 120, 8, mmc_sizeof); mmc_cid.oid = UNPACK_BITS(raw_cid, 104, 16, mmc_sizeof); for (i = 0; i < 6; i++) { mmc_cid.pnm[i] = (uint8_t)UNPACK_BITS(raw_cid, (104 - 8 * (i + 1)), 8, mmc_sizeof); } mmc_cid.pnm[6] = 0; mmc_cid.prv = UNPACK_BITS(raw_cid, 48, 8, mmc_sizeof); mmc_cid.psn = UNPACK_BITS(raw_cid, 16, 32, mmc_sizeof); mmc_cid.month = UNPACK_BITS(raw_cid, 8, 4, mmc_sizeof); mmc_cid.year = UNPACK_BITS(raw_cid, 12, 4, mmc_sizeof); mmc_cid.year += 1997; } /* save it in card database */ memcpy(&card->cid, &mmc_cid, sizeof(struct mmc_cid)); ssdk_printf(SSDK_INFO, "Decoded CID fields:\r\n"); ssdk_printf(SSDK_INFO, "Manufacturer ID: %x\r\n", mmc_cid.mid); ssdk_printf(SSDK_INFO, "OEM ID: 0x%x\r\n", mmc_cid.oid); ssdk_printf(SSDK_INFO, "Product Name: %s\r\n", mmc_cid.pnm); ssdk_printf(SSDK_INFO, "Product revision: %d.%d\r\n", (mmc_cid.prv >> 4), (mmc_cid.prv & 0xF)); ssdk_printf(SSDK_INFO, "Product serial number: %X\r\n", mmc_cid.psn); ssdk_printf(SSDK_INFO, "Manufacturing date: %d %d\r\n", mmc_cid.month, mmc_cid.year); return SDRV_STATUS_OK; } /* * Function: mmc reset cards * Arg : host structure * Return : 0 on Success, 1 on Failure * Flow : Reset all the cards to idle condition (CMD 0) */ static status_t sdrv_mmc_reset_card(struct sdhci_host *host) { struct mmc_command cmd; memset(&cmd, 0, sizeof(struct mmc_command)); cmd.cmd_index = CMD0_GO_IDLE_STATE; #ifdef WITH_ON_ZONE /* if on zone, need use argument for go to pre-idel state */ cmd.argument = 0xF0F0F0F0; #else cmd.argument = 0; #endif cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL; cmd.resp_type = SDHCI_CMD_RESP_NONE; /* send command */ return sdrv_sdhci_send_command(host, &cmd); } /* * Function: mmc operations command * Arg : host & card structure * Return : 0 on Success, 1 on Failure * Flow : Send CMD1 to know whether the card supports host VDD profile or * not. */ static status_t sdrv_mmc_send_op_cond(struct sdhci_host *host, struct mmc_card *card) { struct mmc_command cmd; uint32_t mmc_resp = 0; status_t mmc_ret = SDRV_STATUS_OK; uint32_t mmc_retry = 0; memset(&cmd, 0, sizeof(struct mmc_command)); /* CMD1 format: * [31] Busy bit * [30:29] Access mode * [28:24] reserved * [23:15] 2.7-3.6 * [14:8] 2.0-2.6 * [7] 1.7-1.95 * [6:0] reserved */ cmd.cmd_index = CMD1_SEND_OP_COND; cmd.argument = card->ocr; cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL; cmd.resp_type = SDHCI_CMD_RESP_R3; do { mmc_ret = sdrv_sdhci_send_command(host, &cmd); if (mmc_ret) return mmc_ret; /* Command returned success, now it's time to examine response */ mmc_resp = cmd.resp[0]; /* Check the response for busy status */ if (!(mmc_resp & MMC_OCR_BUSY)) { mmc_retry++; udelay(1); continue; } else break; } while (mmc_retry < MMC_MAX_COMMAND_RETRY); /* If we reached here after max retries, we failed to get OCR */ if (mmc_retry == MMC_MAX_COMMAND_RETRY && !(mmc_resp & MMC_OCR_BUSY)) { DETAIL_PRINTF(SSDK_CRIT, "Card has busy status set. Init did not complete\r\n"); return SDRV_STATUS_BUSY; } /* Response contains card's ocr. Update card's information */ card->ocr = mmc_resp; if (mmc_resp & MMC_OCR_SEC_MODE) card->type = MMC_TYPE_MMCHC; else card->type = MMC_TYPE_STD_MMC; return mmc_ret; } /* * Function: mmc send cid * Arg : host & card structure * Return : 0 on Success, 1 on Failure * Flow : Request any card to send its uniquie card identification * (CID) number (CMD2). */ static status_t sdrv_mmc_all_send_cid(struct sdhci_host *host, struct mmc_card *card) { struct mmc_command cmd; status_t mmc_ret = SDRV_STATUS_OK; memset(&cmd, 0, sizeof(struct mmc_command)); /* CMD2 Format: * [31:0] stuff bits */ cmd.cmd_index = CMD2_ALL_SEND_CID; cmd.argument = 0; cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL; cmd.resp_type = SDHCI_CMD_RESP_R2; cmd.retries = MMC_CMD_RETRIES; /* send command */ mmc_ret = sdrv_sdhci_send_command(host, &cmd); if (mmc_ret) { return mmc_ret; } /* Response contains card's 128 bits CID register */ mmc_ret = sdrv_mmc_decode_and_save_cid(card, cmd.resp); if (mmc_ret) { return mmc_ret; } return mmc_ret; } /* * Function: mmc send relative address * Arg : host & card structure * Return : 0 on Success, 1 on Failure * Flow : Ask card to send it's relative card address (RCA). * This RCA number is shorter than CID and is used by * the host to address the card in future (CMD3) */ static status_t sdrv_mmc_send_relative_address(struct sdhci_host *host, struct mmc_card *card) { struct mmc_command cmd; status_t mmc_ret = SDRV_STATUS_OK; memset(&cmd, 0, sizeof(struct mmc_command)); /* CMD3 Format: * [31:0] stuff bits */ if (MMC_CARD_SD(card)) { cmd.cmd_index = CMD3_SEND_RELATIVE_ADDR; cmd.argument = 0; cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL; cmd.resp_type = SDHCI_CMD_RESP_R6; cmd.retries = MMC_CMD_RETRIES; /* send command */ mmc_ret = sdrv_sdhci_send_command(host, &cmd); if (mmc_ret) return mmc_ret; /* For sD, card will send RCA. Store it */ card->rca = (cmd.resp[0] >> 16); } else { cmd.cmd_index = CMD3_SEND_RELATIVE_ADDR; cmd.argument = (MMC_RCA << 16); card->rca = (cmd.argument >> 16); cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL; cmd.resp_type = SDHCI_CMD_RESP_R6; cmd.retries = MMC_CMD_RETRIES; /* send command */ mmc_ret = sdrv_sdhci_send_command(host, &cmd); if (mmc_ret) return mmc_ret; } return mmc_ret; } /* * Function: mmc send csd * Arg : host, card structure & o/p arg to store csd * Return : 0 on Success, 1 on Failure * Flow : Requests card to send it's CSD register's contents. (CMD9) */ static status_t sdrv_mmc_send_csd(struct sdhci_host *host, struct mmc_card *card) { struct mmc_command cmd; uint32_t mmc_arg = 0; status_t mmc_ret = SDRV_STATUS_OK; memset(&cmd, 0, sizeof(struct mmc_command)); /* CMD9 Format: * [31:16] RCA * [15:0] stuff bits */ mmc_arg |= card->rca << 16; cmd.cmd_index = CMD9_SEND_CSD; cmd.argument = mmc_arg; cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL; cmd.resp_type = SDHCI_CMD_RESP_R2; cmd.retries = MMC_CMD_RETRIES; /* send command */ mmc_ret = sdrv_sdhci_send_command(host, &cmd); if (mmc_ret) return mmc_ret; /* response contains the card csd */ memcpy(card->raw_csd, cmd.resp, sizeof(cmd.resp)); return mmc_ret; } /* * Function: mmc select card * Arg : host, card structure * Return : 0 on Success, 1 on Failure * Flow : Selects a card by sending CMD7 to the card with its RCA. * If RCA field is set as 0 ( or any other address ), * the card will be de-selected. (CMD7) */ static status_t sdrv_mmc_select_card(struct sdhci_host *host, struct mmc_card *card) { struct mmc_command cmd; uint32_t mmc_arg = 0; status_t mmc_ret = SDRV_STATUS_OK; memset(&cmd, 0, sizeof(struct mmc_command)); /* CMD7 Format: * [31:16] RCA * [15:0] stuff bits */ mmc_arg |= card->rca << 16; cmd.cmd_index = CMD7_SELECT_DESELECT_CARD; cmd.argument = mmc_arg; cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL; cmd.retries = MMC_CMD_RETRIES; /* If we are deselecting card, we do not get response */ if (card->rca) { if (MMC_CARD_SD(card)) cmd.resp_type = SDHCI_CMD_RESP_R1B; else cmd.resp_type = SDHCI_CMD_RESP_R1; } else cmd.resp_type = SDHCI_CMD_RESP_NONE; /* send command */ mmc_ret = sdrv_sdhci_send_command(host, &cmd); if (mmc_ret) return mmc_ret; return mmc_ret; } #if 0 /* * Function: mmc set block len * Arg : host, card structure & block length * Return : 0 on Success, 1 on Failure * Flow : Send command to set block length. */ static uint32_t sdrv_mmc_set_block_len(struct sdhci_host *host, struct mmc_card *card, uint32_t block_len) { struct mmc_command cmd; uint32_t mmc_ret = 0; memset(&cmd, 0, sizeof(struct mmc_command)); /* CMD16 Format: * [31:0] block length */ cmd.cmd_index = CMD16_SET_BLOCKLEN; cmd.argument = block_len; cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL; cmd.resp_type = SDHCI_CMD_RESP_R1; /* send command */ mmc_ret = sdrv_sdhci_send_command(host, &cmd); if (mmc_ret) return mmc_ret; /* * If blocklength is larger than 512 bytes, * the card sets BLOCK_LEN_ERROR bit. */ if (cmd.resp[0] & MMC_R1_BLOCK_LEN_ERR) { DETAIL_PRINTF(SSDK_CRIT, "The block length is not supported by the card\r\n"); return 1; } return 0; } #endif /* * Function: mmc get card status * Arg : host, card structure & o/p argument card status * Return : 0 on Success, 1 on Failure * Flow : Get the current status of the card */ static status_t sdrv_mmc_get_card_status(struct sdhci_host *host, struct mmc_card *card, uint32_t *status) { struct mmc_command cmd; status_t mmc_ret = SDRV_STATUS_OK; memset(&cmd, 0, sizeof(struct mmc_command)); /* CMD13 Format: * [31:16] RCA * [15:0] stuff bits */ cmd.cmd_index = CMD13_SEND_STATUS; cmd.argument = card->rca << 16; cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL; cmd.resp_type = SDHCI_CMD_RESP_R1; cmd.retries = MMC_CMD_RETRIES; /* send command */ mmc_ret = sdrv_sdhci_send_command(host, &cmd); if (mmc_ret) return mmc_ret; /* Checking ADDR_OUT_OF_RANGE error in CMD13 response */ if ((cmd.resp[0] >> 31) & 0x01) { DETAIL_PRINTF(SSDK_CRIT, "CMD13 response ADDR_OUT_OF_RANGE failed\r\n"); return SDRV_STATUS_INVALID_PARAM; } *status = cmd.resp[0]; return mmc_ret; } /* * Function: mmc get ext csd * Arg : host, card structure & array to hold ext attributes * Return : 0 on Success, 1 on Failure * Flow : Send ext csd command & get the card attributes */ static status_t sdrv_mmc_get_ext_csd(struct sdhci_host *host, struct mmc_card *card) { struct mmc_command cmd; status_t mmc_ret = SDRV_STATUS_OK; #if WITH_KERNEL_VM void *vptr; uint8_t align_pow2 = log2_uint(CONFIG_ARCH_CACHE_LINE); if (vmm_alloc_contiguous(vmm_get_kernel_aspace(), "mmc_ext", EXT_CSD_BUF_SIZE, &vptr, align_pow2, 0, ARCH_MMU_FLAG_CACHED) < 0) { printf("Failed to allocate ext csd buf\r\n"); return SDRV_STATUS_FAIL; } card->ext_csd = vptr; #endif ASSERT(card->ext_csd); memset(card->ext_csd, 0, EXT_CSD_BUF_SIZE); memset(&cmd, 0, sizeof(struct mmc_command)); /* CMD8 */ cmd.cmd_index = CMD8_SEND_EXT_CSD; cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL; cmd.resp_type = SDHCI_CMD_RESP_R1; cmd.data.data_ptr = card->ext_csd; cmd.data.num_blocks = 1; cmd.data_present = 0x1; cmd.trans_mode = SDHCI_MMC_READ; cmd.retries = MMC_CMD_RETRIES; /* send command */ mmc_ret = sdrv_sdhci_send_command(host, &cmd); if (mmc_ret) return mmc_ret; return mmc_ret; } /* * Function: mmc switch command * Arg : Host, card structure, access mode, index & value to be set * Return : 0 on Success, 1 on Failure * Flow : Send switch command to the card to set the ext attribute @ index */ static status_t sdrv_mmc_switch_cmd(struct sdhci_host *host, struct mmc_card *card, uint32_t access, uint32_t index, uint32_t value) { struct mmc_command cmd; status_t mmc_ret = SDRV_STATUS_OK; uint32_t mmc_status; memset(&cmd, 0, sizeof(struct mmc_command)); /* * CMD6 Format: * [31:26] set to 0 * [25:24] access * [23:16] index * [15:8] value * [7:3] set to 0 * [2:0] cmd set */ cmd.cmd_index = CMD6_SWITCH_FUNC; cmd.argument |= (access << 24); cmd.argument |= (index << 16); cmd.argument |= (value << 8); cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL; cmd.resp_type = SDHCI_CMD_RESP_R1B; cmd.retries = MMC_CMD_RETRIES; mmc_ret = sdrv_sdhci_send_command(host, &cmd); if (mmc_ret) { DETAIL_PRINTF(SSDK_CRIT, "CMD6 send failed\r\n"); return mmc_ret; } if (index == MMC_EXT_MMC_HS_TIMING && value == SDHCI_EMMC_HISPEED_MODE) { /* Set the high speed mode in controller */ if (host->ops->set_uhs_mode) host->ops->set_uhs_mode(host, SDHCI_EMMC_HISPEED_MODE); if (host->ops->set_clock) mmc_ret = host->ops->set_clock(host, MMC_CLK_50MHZ); } /* Check if the card completed the switch command processing */ mmc_ret = sdrv_mmc_get_card_status(host, card, &mmc_status); if (mmc_ret) { DETAIL_PRINTF(SSDK_CRIT, "Get card status failed\r\n"); return mmc_ret; } if (MMC_CARD_STATUS(mmc_status) != MMC_TRAN_STATE) { DETAIL_PRINTF(SSDK_CRIT, "Switch cmd failed. Card not in tran state %x\r\n", mmc_status); mmc_ret = SDRV_STATUS_MMC_CARD_STATUS_ERR; } if (mmc_status & MMC_SWITCH_FUNC_ERR_FLAG) { DETAIL_PRINTF(SSDK_CRIT, "Switch cmd failed. Switch Error.\r\n"); mmc_ret = SDRV_STATUS_MMC_SWITCH_FUNC_ERR; } return mmc_ret; } bool sdrv_mmc_set_drv_type(struct sdhci_host *host, struct mmc_card *card, uint8_t drv_type) { uint32_t ret = 0; bool drv_type_changed = false; uint32_t value = ((drv_type << 4) | MMC_HS200_TIMING); if (card->ext_csd[MMC_EXT_MMC_DRV_STRENGTH] & (1 << drv_type)) ret = sdrv_mmc_switch_cmd(host, card, MMC_ACCESS_WRITE, MMC_EXT_MMC_HS_TIMING, value); if (!ret) drv_type_changed = true; return drv_type_changed; } /* * Function: mmc set bus width * Arg : Host, card structure & width * Return : 0 on Success, 1 on Failure * Flow : Send switch command to set bus width */ static status_t sdrv_mmc_set_bus_width(struct sdhci_host *host, struct mmc_card *card, uint32_t width) { status_t mmc_ret = SDRV_STATUS_OK; mmc_ret = sdrv_mmc_switch_cmd(host, card, MMC_ACCESS_WRITE, MMC_EXT_MMC_BUS_WIDTH, width); if (mmc_ret) { DETAIL_PRINTF(SSDK_CRIT, "Switch cmd failed\r\n"); return mmc_ret; } return mmc_ret; } /* * Function: mmc card supports hs400 mode * Arg : None * Return : 1 if hs400 mode is supported, 0 otherwise * Flow : Check the ext csd attributes of the card */ static uint8_t sdrv_mmc_card_supports_hs400_mode(struct mmc_card *card) { if (card->ext_csd[MMC_DEVICE_TYPE] & MMC_HS_HS400_MODE) return 1; else return 0; } /* * Function: mmc card supports hs200 mode * Arg : None * Return : 1 if HS200 mode is supported, 0 otherwise * Flow : Check the ext csd attributes of the card */ static uint8_t sdrv_mmc_card_supports_hs200_mode(struct mmc_card *card) { if (card->ext_csd[MMC_DEVICE_TYPE] & MMC_HS_HS200_MODE) return 1; else return 0; } /* * Function: mmc card supports ddr mode * Arg : None * Return : 1 if DDR mode is supported, 0 otherwise * Flow : Check the ext csd attributes of the card */ static uint8_t sdrv_mmc_card_supports_ddr_mode(struct mmc_card *card) { if (card->ext_csd[MMC_DEVICE_TYPE] & MMC_HS_DDR_MODE) return 1; else return 0; } /* * Function : Enable HS200 mode * Arg : Host, card structure and bus width * Return : 0 on Success, 1 on Failure * Flow : * - Set the bus width to 4/8 bit SDR as supported by the target & * host * - Set the HS_TIMING on ext_csd 185 for the card */ static status_t sdrv_mmc_set_hs200_mode(struct sdhci_host *host, struct mmc_card *card, uint32_t width) { status_t mmc_ret = SDRV_STATUS_OK; DETAIL_PRINTF(SSDK_DEBUG, "\r\n Enabling HS200 Mode Start\r\n"); /* Set 4/8 bit SDR bus width */ mmc_ret = sdrv_mmc_set_bus_width(host, card, width); if (mmc_ret) { DETAIL_PRINTF(SSDK_CRIT, "Failure to set wide bus for Card(RCA:%x)\r\n", card->rca); return mmc_ret; } /* Setting HS200 in HS_TIMING using EXT_CSD (CMD6) */ mmc_ret = sdrv_mmc_switch_cmd(host, card, MMC_ACCESS_WRITE, MMC_EXT_MMC_HS_TIMING, MMC_HS200_TIMING); if (mmc_ret) { DETAIL_PRINTF(SSDK_CRIT, "Switch cmd returned failure %d\r\n", __LINE__); return mmc_ret; } /* Enable HS200 mode in controller */ MMC_SAVE_TIMING(host, SDHCI_EMMC_HS200_MODE); if (host->ops->set_uhs_mode) host->ops->set_uhs_mode(host, SDHCI_EMMC_HS200_MODE); if (host->ops->set_clock) { mmc_ret = host->ops->set_clock(host, MMC_CLK_200MHZ); if (mmc_ret) return mmc_ret; } /* Execute Tuning for hs200 mode */ if ((mmc_ret = sdrv_sdhci_execute_tuning(host, CMD21_SEND_TUNING_BLOCK, width))) DETAIL_PRINTF(SSDK_CRIT, "Tuning for hs200 failed\r\n"); DETAIL_PRINTF(SSDK_DEBUG, "\r\n Enabling HS200 Mode Done\r\n"); return mmc_ret; } /* * Function: mmc set ddr mode * Arg : Host, card structure and bus width * Return : 0 on Success, 1 on Failure * Flow : Set bus width for ddr mode & set controller in DDR mode */ static status_t sdrv_mmc_set_ddr_mode(struct sdhci_host *host, struct mmc_card *card, uint32_t width) { status_t mmc_ret = SDRV_STATUS_OK; DETAIL_PRINTF(SSDK_DEBUG, "\r\n Enabling DDR Mode Start\r\n"); /* Set 4/8 bit DDR bus width */ if (width == MMC_DATA_BUS_WIDTH_4BIT) mmc_ret = sdrv_mmc_set_bus_width(host, card, MMC_DATA_DDR_BUS_WIDTH_4BIT); else if (width == MMC_DATA_BUS_WIDTH_8BIT) mmc_ret = sdrv_mmc_set_bus_width(host, card, MMC_DATA_DDR_BUS_WIDTH_8BIT); else { DETAIL_PRINTF(SSDK_CRIT, "DDR mode not suport bus width: %u\r\n", width); return SDRV_STATUS_INVALID_PARAM; } if (mmc_ret) { DETAIL_PRINTF(SSDK_CRIT, "Failure to set DDR mode for Card(RCA:%x)\r\n", card->rca); return mmc_ret; } /* Save the timing value, before changing the clock */ MMC_SAVE_TIMING(host, SDHCI_EMMC_DDR52_MODE); /* Set the DDR mode in controller */ if (host->ops->set_uhs_mode) host->ops->set_uhs_mode(host, SDHCI_EMMC_DDR52_MODE); if (host->ops->set_clock) mmc_ret = host->ops->set_clock(host, MMC_CLK_50MHZ); DETAIL_PRINTF(SSDK_DEBUG, "\r\n Enabling DDR Mode Done\r\n"); return mmc_ret; } /* * Function: mmc set high speed interface * Arg : Host & card structure * Return : None * Flow : Sets the host uhs mode & clock * Adjust the interface speed to optimal speed */ static status_t sdrv_mmc_set_hs_interface(struct sdhci_host *host, struct mmc_card *card) { status_t mmc_ret = SDRV_STATUS_OK; /* Setting HS_TIMING in EXT_CSD (CMD6) */ mmc_ret = sdrv_mmc_switch_cmd(host, card, MMC_ACCESS_WRITE, MMC_EXT_MMC_HS_TIMING, MMC_HS_TIMING); if (mmc_ret) { DETAIL_PRINTF(SSDK_CRIT, "Switch cmd returned failure %d\r\n", __LINE__); return mmc_ret; } /* Save the timing value, before changing the clock */ MMC_SAVE_TIMING(host, SDHCI_EMMC_HISPEED_MODE); return mmc_ret; } /* * Function : Enable HS400 mode * Arg : Host, card structure and bus width * Return : 0 on Success, 1 on Failure * Flow : * - Set the bus width to 8 bit DDR * - Set the HS_TIMING on ext_csd 185 for the card */ status_t sdrv_mmc_set_hs400_mode(struct sdhci_host *host, struct mmc_card *card, uint32_t width) { status_t mmc_ret = SDRV_STATUS_OK; /* * Emmc 5.0 spec does not allow changing to hs400 mode directly * Need to follow the sequence to change to hs400 mode * 1. Enable HS200 mode, perform tuning * 2. Change to high speed mode * 3. Enable DDR mode * 4. Enable HS400 mode, note that hs400 tuning is done in enable hs200 step */ DETAIL_PRINTF(SSDK_DEBUG, "\r\n Enabling HS400 Mode Start\r\n"); /* HS400 mode is supported only in DDR 8-bit */ if (width != MMC_DATA_BUS_WIDTH_8BIT) { DETAIL_PRINTF(SSDK_CRIT, "Bus width is not 8-bit, cannot switch to hs400: %u\r\n", width); return SDRV_STATUS_INVALID_PARAM; } /* 1.Enable HS200 mode */ mmc_ret = sdrv_mmc_set_hs200_mode(host, card, width); if (mmc_ret) { DETAIL_PRINTF(SSDK_CRIT, "Failure Setting HS200 mode %s\t%d\r\n", __func__, __LINE__); return mmc_ret; } /* 2. Enable High speed mode */ mmc_ret = sdrv_mmc_set_hs_interface(host, card); if (mmc_ret) { DETAIL_PRINTF(SSDK_CRIT, "Error adjusting interface speed!:%s\t%d\r\n", __func__, __LINE__); return mmc_ret; } /*3. Enable DDR mode */ mmc_ret = sdrv_mmc_set_ddr_mode(host, card, width); if (mmc_ret) { DETAIL_PRINTF(SSDK_CRIT, "Failure setting DDR mode:%s\t%d\r\n", __func__, __LINE__); return mmc_ret; } /*4. Set hs400 timing */ mmc_ret = sdrv_mmc_switch_cmd(host, card, MMC_ACCESS_WRITE, MMC_EXT_MMC_HS_TIMING, MMC_HS400_TIMING); if (mmc_ret) { DETAIL_PRINTF(SSDK_CRIT, "Switch cmd returned failure %s\t%d\r\n", __func__, __LINE__); return mmc_ret; } /* Enable HS400 mode in controller */ /* Save the timing value, before changing the clock */ MMC_SAVE_TIMING(host, SDHCI_EMMC_HS400_MODE); /* Set the clock back to 200 MHZ */ if (host->ops->set_clock) { mmc_ret = host->ops->set_clock(host, MMC_CLK_200MHZ); if (mmc_ret) return mmc_ret; } if (host->ops->set_uhs_mode) host->ops->set_uhs_mode(host, SDHCI_EMMC_HS400_MODE); DETAIL_PRINTF(SSDK_DEBUG, "\r\n Enabling HS400 Mode Done\r\n"); return mmc_ret; } status_t sdrv_mmc_send_tuning(struct mmc_device *dev, uint32_t opcode, uint32_t bus_width) { status_t mmc_ret = SDRV_STATUS_OK; struct mmc_command cmd; const uint8_t *tuning_block_pattern = NULL; int size; /* Judgment tuning data */ if (opcode == CMD21_SEND_TUNING_BLOCK && bus_width == MMC_DATA_BUS_WIDTH_8BIT) { tuning_block_pattern = tuning_blk_pattern_8bit; size = sizeof(tuning_blk_pattern_8bit); } else if (bus_width == MMC_DATA_BUS_WIDTH_4BIT) { tuning_block_pattern = tuning_blk_pattern_4bit; size = sizeof(tuning_blk_pattern_4bit); } else return SDRV_STATUS_INVALID_PARAM; /* Configuration commands */ memset(&cmd, 0, sizeof(struct mmc_command)); cmd.cmd_index = opcode; cmd.argument = 0x0; cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL; cmd.resp_type = SDHCI_CMD_RESP_R1; cmd.trans_mode = SDHCI_MMC_READ; cmd.data_present = 0x1; /* Configuration data */ cmd.data.data_ptr = tuning_data; cmd.data.num_blocks = 0x1; cmd.data.blk_sz = size; memset(tuning_data, 0, size); /* send command */ mmc_ret = sdrv_sdhci_send_command(&dev->host, &cmd); if (mmc_ret) { udelay(100); DETAIL_PRINTF(SSDK_INFO, "sdrv_mmc_send_tuning send error!\r\n"); return mmc_ret; } /* Bad judgment */ if (cmd.error) { udelay(100); DETAIL_PRINTF(SSDK_INFO, "sdrv_mmc_send_tuning cmd error! reg = 0x%08x\r\n", cmd.error); return SDRV_STATUS_MMC_CMD_ERR; } if (cmd.data_present && dev->host.data_cmd.error) { udelay(100); DETAIL_PRINTF(SSDK_INFO, "sdrv_mmc_send_tuning data error! 0x%08x\r\n", dev->host.data_cmd.error); return SDRV_STATUS_MMC_DAT_ERR; } /* Data comparison */ if (memcmp(tuning_data, tuning_block_pattern, size)) { udelay(100); DETAIL_PRINTF(SSDK_INFO, "memcmp tuning_data error\r\n"); return SDRV_STATUS_MMC_TUNING_FAIL; } return mmc_ret; } /* * Function: sdrv_mmc_host_init * Arg : mmc device structure * Return : 0 on success, 1 on Failure * Flow : Initialize the host contoller * Set the clock rate to 400 KHZ for init */ static status_t sdrv_mmc_host_init(struct mmc_device *dev) { status_t mmc_ret = SDRV_STATUS_OK; struct sdhci_host *host; struct mmc_config_data *cfg; host = &dev->host; cfg = &dev->config; host->base = cfg->sdhc_base; host->slot = cfg->slot; host->irq = cfg->irq; host->caps.hs200_support = cfg->hs200_support; host->caps.hs400_support = cfg->hs400_support; host->caps.uhs_support = cfg->uhs_support; host->caps.hw_reset_support = cfg->hw_reset_support; host->max_clk_rate = cfg->max_clk_rate; if (cfg->voltage) host->caps.voltage = cfg->voltage; /* * Initialize the controller, read the host capabilities * set power on mode */ sdrv_sdhci_init(host); host->caps.ddr_support &= cfg->ddr50_support; if (host->ops->config_pin) host->ops->config_pin(host); return mmc_ret; } /* * Function: mmc identify card * Arg : host & card structure * Return : 0 on Success, 1 on Failure * Flow : Performs card identification process: * 1. Get card's unique identification number (CID) * 2. Get(for sd)/set (for mmc) relative card address (RCA) * 3. Select the card to put it in TRAN state */ static status_t sdrv_mmc_identify_card(struct sdhci_host *host, struct mmc_card *card) { status_t mmc_ret = SDRV_STATUS_OK; /* Ask card to send its unique card identification (CID) number (CMD2) */ mmc_ret = sdrv_mmc_all_send_cid(host, card); if (mmc_ret) { DETAIL_PRINTF(SSDK_CRIT, "Failure getting card's CID number!\r\n"); return mmc_ret; } /* Ask card to send a relative card address (RCA) (CMD3) */ mmc_ret = sdrv_mmc_send_relative_address(host, card); if (mmc_ret) { DETAIL_PRINTF(SSDK_CRIT, "Failure getting card's RCA!\r\n"); return mmc_ret; } /* Get card's CSD register (CMD9) */ mmc_ret = sdrv_mmc_send_csd(host, card); if (mmc_ret) { DETAIL_PRINTF(SSDK_CRIT, "Failure getting card's CSD information!\r\n"); return mmc_ret; } /* Select the card (CMD7) */ mmc_ret = sdrv_mmc_select_card(host, card); if (mmc_ret) { DETAIL_PRINTF(SSDK_CRIT, "Failure selecting the Card with RCA: %x\r\n", card->rca); return mmc_ret; } /* Set the card status as active */ card->status = MMC_STATUS_ACTIVE; return mmc_ret; } /* * Function: sdrv_mmc_reset_card_and_send_op * Arg : Host & Card structure * Return : 0 on Success, 1 on Failure * Flow : Routine to initialize MMC card. It resets a card to idle state, * verify operating voltage and set the card in ready state. */ static status_t sdrv_mmc_reset_card_and_send_op(struct sdhci_host *host, struct mmc_card *card) { status_t mmc_ret = SDRV_STATUS_OK; /* 1. Card Reset - CMD0, for card powerup need some delay */ udelay(1000); mmc_ret = sdrv_mmc_reset_card(host); if (mmc_ret) { DETAIL_PRINTF(SSDK_CRIT, "Failure resetting MMC cards!\r\n"); return mmc_ret; } /* 2. Card Initialization process */ /* * Send CMD1 to identify and reject cards that do not match host's VDD range * profile. Cards sends its OCR register in response. */ mmc_ret = sdrv_mmc_send_op_cond(host, card); /* OCR is not received, init could not complete */ if (mmc_ret) { DETAIL_PRINTF(SSDK_ERR, "Failure getting OCR response from MMC Card\r\n"); return mmc_ret; } return mmc_ret; } static status_t sdrv_mmc_send_app_cmd(struct sdhci_host *host, struct mmc_card *card) { status_t mmc_ret = SDRV_STATUS_OK; struct mmc_command cmd = {0}; cmd.cmd_index = CMD55_APP_CMD; cmd.argument = (card->rca << 16); cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL; cmd.resp_type = SDHCI_CMD_RESP_R1; mmc_ret = sdrv_sdhci_send_command(host, &cmd); if (mmc_ret) { DETAIL_PRINTF(SSDK_CRIT, "Failed Sending CMD55\r\n"); return mmc_ret; } return mmc_ret; } static status_t sdrv_mmc_switch_uhs_voltage(struct sdhci_host *host) { status_t mmc_ret = SDRV_STATUS_OK; struct mmc_command cmd = {0}; cmd.cmd_index = CMD11_SWITCH_VOLTAGE; cmd.argument = 0; cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL; cmd.resp_type = SDHCI_CMD_RESP_R1; mmc_ret = sdrv_sdhci_send_command(host, &cmd); if (mmc_ret) { DETAIL_PRINTF(SSDK_CRIT, "The CMD11 no response\r\n"); return mmc_ret; } udelay(1000); if (host->ops->set_clock) { mmc_ret = host->ops->set_clock(host, 0); if (mmc_ret) return mmc_ret; } host->caps.voltage = SDHCI_VOL_1_8; host->ops->set_power(host); udelay(10000); if (host->ops->set_clock) { mmc_ret = host->ops->set_clock(host, SDHCI_CLK_25MHZ); if (mmc_ret) return mmc_ret; } udelay(1000); return mmc_ret; } status_t sdrv_mmc_sd_card_init(struct sdhci_host *host, struct mmc_card *card) { uint8_t i; status_t mmc_ret = SDRV_STATUS_OK; struct mmc_command cmd; memset(&cmd, 0, sizeof(struct mmc_command)); /* Use the SD card RCA 0x0 during init */ card->rca = SD_CARD_RCA; /* Send CMD8 for voltage check*/ for (i = 0; i < SD_CMD8_MAX_RETRY; i++) { cmd.cmd_index = CMD8_SEND_IF_COND; cmd.argument = MMC_SD_HC_VOLT_SUPPLIED; cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL; cmd.resp_type = SDHCI_CMD_RESP_R7; cmd.retries = MMC_CMD_RETRIES; mmc_ret = sdrv_sdhci_send_command(host, &cmd); if (mmc_ret) { DETAIL_PRINTF(SSDK_CRIT, "The response for CMD8 does not match the supplied value\r\n"); return mmc_ret; } else { /* If the command response echos the voltage back */ if (cmd.resp[0] == MMC_SD_HC_VOLT_SUPPLIED) break; } udelay(1); } if (i == SD_CMD8_MAX_RETRY && (cmd.resp[0] != MMC_SD_HC_VOLT_SUPPLIED)) { DETAIL_PRINTF(SSDK_CRIT, "Error: CMD8 response timed out\r\n"); return SDRV_STATUS_TIMEOUT; } /* Send ACMD41 for OCR */ for (i = 0; i < SD_ACMD41_MAX_RETRY; i++) { /* Send APP_CMD before ACMD41*/ mmc_ret = sdrv_mmc_send_app_cmd(host, card); if (mmc_ret) { DETAIL_PRINTF(SSDK_CRIT, "Failed sending App command\r\n"); return mmc_ret; } /* APP_CMD is successful, send ACMD41 now */ cmd.cmd_index = ACMD41_SEND_OP_COND; cmd.argument = MMC_SD_OCR | MMC_SD_HC_HCS | MMC_SD_S18R; cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL; cmd.resp_type = SDHCI_CMD_RESP_R3; mmc_ret = sdrv_sdhci_send_command(host, &cmd); if (mmc_ret) { DETAIL_PRINTF(SSDK_CRIT, "Failure sending ACMD41\r\n"); return mmc_ret; } else { if (cmd.resp[0] & MMC_SD_DEV_READY) { if (cmd.resp[0] & (1 << 30)) { if (host->caps.uhs_support && cmd.resp[0] & (1 << 24)) card->type = MMC_CARD_TYPE_UHS; else card->type = MMC_CARD_TYPE_SDHC; } else { card->type = MMC_CARD_TYPE_STD_SD; } break; } } udelay(50000); } if (i == SD_ACMD41_MAX_RETRY && !(cmd.resp[0] & MMC_SD_DEV_READY)) { DETAIL_PRINTF(SSDK_CRIT, "Error: ACMD41 response timed out\r\n"); return SDRV_STATUS_TIMEOUT; } if (card->type == MMC_CARD_TYPE_UHS) { mmc_ret = sdrv_mmc_switch_uhs_voltage(host); if (mmc_ret) { DETAIL_PRINTF(SSDK_CRIT, "Error: switch voltage to uhs mode failed\r\n"); return mmc_ret; } } return mmc_ret; } /* Function to read SD card information from SD status */ static status_t sdrv_mmc_sd_get_card_ssr(struct sdhci_host *host, struct mmc_card *card) { status_t mmc_ret = SDRV_STATUS_OK; static uint8_t raw_sd_status[ROUNDUP(64, CONFIG_ARCH_CACHE_LINE)] __ALIGNED(CONFIG_ARCH_CACHE_LINE); struct mmc_command cmd = {0}; uint32_t sd_status[16]; uint32_t *status = sd_status; uint32_t au_size; int i; int j; mmc_ret = sdrv_mmc_send_app_cmd(host, card); if (mmc_ret) { DETAIL_PRINTF(SSDK_CRIT, "Failed sending App command\r\n"); return mmc_ret; } cmd.cmd_index = ACMD13_SEND_SD_STATUS; cmd.argument = 0x0; cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL; cmd.resp_type = SDHCI_CMD_RESP_R1; cmd.trans_mode = SDHCI_MMC_READ; cmd.data_present = 0x1; cmd.data.data_ptr = raw_sd_status; cmd.data.num_blocks = 0x1; cmd.data.blk_sz = 0x40; cmd.retries = MMC_CMD_RETRIES; /* send command */ mmc_ret = sdrv_sdhci_send_command(host, &cmd); if (mmc_ret) return mmc_ret; memcpy(sd_status, raw_sd_status, sizeof(sd_status)); for (i = 15, j = 0; i >= 0; i--, j++) sd_status[i] = swap_endian32(sd_status[j]); au_size = UNPACK_BITS(status, MMC_SD_AU_SIZE_BIT, MMC_SD_AU_SIZE_LEN, 32); /* Card AU size in sectors */ card->ssr.au_size = 1 << (au_size + 4); card->ssr.num_aus = UNPACK_BITS(status, MMC_SD_ERASE_SIZE_BIT, MMC_SD_ERASE_SIZE_LEN, 32); /* When Erase Time-out Calculation is not supported. set the num_aus 1 */ card->ssr.num_aus = MAX(card->ssr.num_aus, 1); card->ssr.erase_timeout = UNPACK_BITS(status, MMC_SD_ERASE_TOUT_BIT, MMC_SD_ERASE_TOUT_LEN, 32); card->ssr.erase_offset = UNPACK_BITS(status, MMC_SD_ERASE_OFFSET_BIT, MMC_SD_ERASE_OFFSET_LEN, 32); return mmc_ret; } /* Function to read the SD CARD configuration register */ static uint32_t sdrv_mmc_sd_get_card_scr(struct sdhci_host *host, struct mmc_card *card) { status_t mmc_ret = SDRV_STATUS_OK; static uint8_t scr_resp[ROUNDUP(8, CONFIG_ARCH_CACHE_LINE)] __ALIGNED(CONFIG_ARCH_CACHE_LINE); struct mmc_command cmd = {0}; uint32_t raw_scr[2]; /* Now read the SCR register */ /* Send APP_CMD before ACMD51*/ mmc_ret = sdrv_mmc_send_app_cmd(host, card); if (mmc_ret) { DETAIL_PRINTF(SSDK_CRIT, "Failed sending App command\r\n"); return mmc_ret; } cmd.cmd_index = ACMD51_READ_CARD_SCR; cmd.argument = 0x0; cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL; cmd.resp_type = SDHCI_CMD_RESP_R1; cmd.trans_mode = SDHCI_MMC_READ; cmd.data_present = 0x1; cmd.data.data_ptr = scr_resp; cmd.data.num_blocks = 0x1; cmd.data.blk_sz = 0x8; cmd.retries = MMC_CMD_RETRIES; /* send command */ mmc_ret = sdrv_sdhci_send_command(host, &cmd); if (mmc_ret) return mmc_ret; memcpy(raw_scr, scr_resp, sizeof(raw_scr)); card->raw_scr[0] = swap_endian32(raw_scr[0]); card->raw_scr[1] = swap_endian32(raw_scr[1]); /* * Parse & Populate the SCR data as per sdcc spec */ card->scr.bus_widths = (card->raw_scr[0] & SD_SCR_BUS_WIDTH_MASK) >> SD_SCR_BUS_WIDTH; card->scr.cmd23_support = (card->raw_scr[0] & SD_SCR_CMD23_SUPPORT); card->scr.sd_spec = (card->raw_scr[0] & SD_SCR_SD_SPEC_MASK) >> SD_SCR_SD_SPEC; card->scr.sd3_spec = (card->raw_scr[0] & SD_SCR_SD_SPEC3_MASK) >> SD_SCR_SD_SPEC3; card->scr.data_stat_after_erase = (card->raw_scr[0] & SD_SCR_STAT_AFTER_ERASE_MASK) >> SD_SCR_SD_STAT_AFTER_ERASE; return mmc_ret; } /* * Function: mmc_set_sd_bus_width * Arg : host, device structure & width * Return : 0 on Success, 1 on Failure * Flow : Set the bus width for the card */ status_t sdrv_mmc_sd_set_bus_width(struct sdhci_host *host, struct mmc_card *card, uint8_t width) { status_t mmc_ret = SDRV_STATUS_OK; struct mmc_command cmd = {0}; /* Send APP_CMD before ACMD6*/ mmc_ret = sdrv_mmc_send_app_cmd(host, card); if (mmc_ret) { DETAIL_PRINTF(SSDK_CRIT, "Failed sending App command\r\n"); return mmc_ret; } cmd.cmd_index = ACMD6_SET_BUS_WIDTH; cmd.argument = (width == MMC_DATA_BUS_WIDTH_4BIT) ? (1 << 1) : 0; cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL; cmd.resp_type = SDHCI_CMD_RESP_R1; cmd.retries = MMC_CMD_RETRIES; /* send command */ mmc_ret = sdrv_sdhci_send_command(host, &cmd); if (mmc_ret) return mmc_ret; return mmc_ret; } status_t sdrv_mmc_sd_set_hs(struct sdhci_host *host, struct mmc_card *card) { status_t mmc_ret = SDRV_STATUS_OK; struct mmc_command cmd = {0}; static uint8_t switch_resp[ROUNDUP(64, CONFIG_ARCH_CACHE_LINE)] __ALIGNED(CONFIG_ARCH_CACHE_LINE); cmd.cmd_index = CMD6_SWITCH_FUNC; cmd.argument = MMC_SD_SWITCH_HS; cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL; cmd.resp_type = SDHCI_CMD_RESP_R1; cmd.trans_mode = SDHCI_MMC_READ; cmd.data_present = 0x1; cmd.data.data_ptr = switch_resp; cmd.data.num_blocks = 0x1; cmd.data.blk_sz = 0x40; cmd.retries = MMC_CMD_RETRIES; /* send command */ mmc_ret = sdrv_sdhci_send_command(host, &cmd); if (mmc_ret) return mmc_ret; MMC_SAVE_TIMING(host, SDHCI_UHS_SDR25_MODE); /* Set the SDR25 mode in controller*/ if (host->ops->set_uhs_mode) host->ops->set_uhs_mode(host, SDHCI_UHS_SDR25_MODE); if (host->ops->set_clock) { mmc_ret = host->ops->set_clock(host, SDHCI_CLK_50MHZ); if (mmc_ret) return mmc_ret; } return mmc_ret; } status_t sdrv_mmc_sd_switch(struct sdhci_host *host, struct mmc_card *card, int mode, int group, uint8_t value, uint8_t *resp) { status_t mmc_ret = SDRV_STATUS_OK; struct mmc_command cmd = {0}; cmd.cmd_index = CMD6_SWITCH_FUNC; cmd.argument = (mode << 31) | 0xFFFFFF; cmd.argument &= ~(0xF << (4 * (group - 1))); cmd.argument |= (value << (4 * (group - 1))); cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL; cmd.resp_type = SDHCI_CMD_RESP_R1; cmd.trans_mode = SDHCI_MMC_READ; cmd.data_present = 0x1; cmd.data.data_ptr = resp; cmd.data.num_blocks = 0x1; cmd.data.blk_sz = 0x40; cmd.retries = MMC_CMD_RETRIES; /* send command */ mmc_ret = sdrv_sdhci_send_command(host, &cmd); if (mmc_ret) return mmc_ret; return mmc_ret; } status_t sdrv_mmc_sd_init_uhs_sdr25(struct sdhci_host *host, struct mmc_card *card) { status_t mmc_ret = SDRV_STATUS_OK; static uint8_t switch_resp[ROUNDUP(64, CONFIG_ARCH_CACHE_LINE)] __ALIGNED(CONFIG_ARCH_CACHE_LINE); /* set max current 200mA */ mmc_ret = sdrv_mmc_sd_switch(host, card, 1, 4, 0, switch_resp); if (mmc_ret) return mmc_ret; mmc_ret = sdrv_mmc_sd_switch(host, card, 1, 1, 1, switch_resp); if (mmc_ret) return mmc_ret; MMC_SAVE_TIMING(host, SDHCI_UHS_SDR25_MODE); /* Set the SDR25 mode in controller*/ if (host->ops->set_uhs_mode) host->ops->set_uhs_mode(host, SDHCI_UHS_SDR25_MODE); if (host->ops->set_clock) { mmc_ret = host->ops->set_clock(host, SDHCI_CLK_50MHZ); if (mmc_ret) return mmc_ret; } return mmc_ret; } uint32_t sdrv_mmc_sd_init_uhs_ddr50(struct sdhci_host *host, struct mmc_card *card) { status_t mmc_ret = SDRV_STATUS_OK; static uint8_t switch_resp[ROUNDUP(64, CONFIG_ARCH_CACHE_LINE)] __ALIGNED(CONFIG_ARCH_CACHE_LINE); /* set max current 400mA */ mmc_ret = sdrv_mmc_sd_switch(host, card, 1, 4, 1, switch_resp); if (mmc_ret) return mmc_ret; mmc_ret = sdrv_mmc_sd_switch(host, card, 1, 1, 4, switch_resp); if (mmc_ret) return mmc_ret; MMC_SAVE_TIMING(host, SDHCI_UHS_DDR50_MODE); /* Set the DDR50 mode in controller*/ if (host->ops->set_uhs_mode) host->ops->set_uhs_mode(host, SDHCI_UHS_DDR50_MODE); if (host->ops->set_clock) { mmc_ret = host->ops->set_clock(host, SDHCI_CLK_50MHZ); if (mmc_ret) return mmc_ret; } return mmc_ret; } /* * Function: mmc_init_card * Arg : mmc device structure * Return : 0 on Success, 1 on Failure * Flow : Performs initialization and identification of eMMC cards connected * to the host. */ static status_t sdrv_mmc_card_init(struct mmc_device *dev) { status_t mmc_ret = SDRV_STATUS_OK; uint8_t bus_width = 0; struct sdhci_host *host; struct mmc_card *card; struct mmc_config_data *cfg; host = &dev->host; card = &dev->card; cfg = &dev->config; host->card_type = SDHCI_EMMC_CARD; /* card hw reset */ if ((host->caps.hw_reset_support) && (host->ops->hw_reset)) host->ops->hw_reset(host); /* host init */ if (host->ops->priv_init) host->ops->priv_init(host); if (host->ops->set_clock) { mmc_ret = host->ops->set_clock(host, SDHCI_CLK_400KHZ); if (mmc_ret) { DETAIL_PRINTF(SSDK_CRIT, "Failed to set card clk\r\n"); return mmc_ret; } } /* Initialize MMC card structure */ card->status = MMC_STATUS_INACTIVE; /* If config 1.8v voltage, set ocr 1.7v-1.9v params, else set 2.7v-3.6v */ card->ocr = MMC_OCR_27_36 | MMC_OCR_SEC_MODE; if (host->caps.voltage == SDHCI_VOL_1_8) card->ocr = MMC_OCR_17_19 | MMC_OCR_SEC_MODE; /* Initialize the internal MMC */ mmc_ret = sdrv_mmc_reset_card_and_send_op(host, card); if (mmc_ret) { DETAIL_PRINTF(SSDK_ERR, "MMC card failed to respond, try for SD card\r\n"); host->card_type = SDHCI_SD_CARD; /* host init */ if (host->ops->priv_init) host->ops->priv_init(host); /* need reinit clock */ if (host->ops->set_clock) { mmc_ret = host->ops->set_clock(host, SDHCI_CLK_400KHZ); if (mmc_ret) { DETAIL_PRINTF(SSDK_CRIT, "Failed to set card clk\r\n"); return mmc_ret; } } /* Reset the card & get the OCR */ mmc_ret = sdrv_mmc_sd_card_init(host, card); if (mmc_ret) { DETAIL_PRINTF(SSDK_CRIT, "Failed to initialize SD card\r\n"); return mmc_ret; } } /* Identify (CMD2, CMD3 & CMD9) and select the card (CMD7) */ mmc_ret = sdrv_mmc_identify_card(host, card); if (mmc_ret) return mmc_ret; /* set interface speed */ if (MMC_CARD_SD(card)) { if (card->type == MMC_CARD_TYPE_UHS) { if (cfg->bus_width == MMC_BUS_WIDTH_4BIT) { /* uhs card only support 4bit bus width */ bus_width = MMC_DATA_BUS_WIDTH_4BIT; } else { DETAIL_PRINTF(SSDK_CRIT, "uhs card only support 4bit bus widt\r\n"); return SDRV_STATUS_INVALID_PARAM; } mmc_ret = sdrv_mmc_sd_set_bus_width(host, card, bus_width); if (mmc_ret) { DETAIL_PRINTF(SSDK_CRIT, "Failed to set bus width for the card\r\n"); return mmc_ret; } /* Set bit bus width in controller */ mmc_ret = sdrv_sdhci_set_bus_width(host, bus_width); if (mmc_ret) { DETAIL_PRINTF(SSDK_CRIT, "Failed to set bus width for host controller\r\n"); return mmc_ret; } if (host->caps.ddr_support) { DETAIL_PRINTF(SSDK_INFO, "SDHC Running in DDR mode\r\n"); mmc_ret = sdrv_mmc_sd_init_uhs_ddr50(host, card); } else { DETAIL_PRINTF(SSDK_INFO, "SDHC Running in SDR mode\r\n"); mmc_ret = sdrv_mmc_sd_init_uhs_sdr25(host, card); } if (mmc_ret) { DETAIL_PRINTF(SSDK_CRIT, "Failed to set SDR or DDR for SD card\r\n"); return mmc_ret; } } else { DETAIL_PRINTF(SSDK_INFO, "SDHC Running in HS mode\r\n"); mmc_ret = sdrv_mmc_sd_set_hs(host, card); if (mmc_ret) { DETAIL_PRINTF(SSDK_CRIT, "Failed to set HS for SD card\r\n"); return mmc_ret; } } } else { mmc_ret = sdrv_mmc_set_hs_interface(host, card); if (mmc_ret) { DETAIL_PRINTF(SSDK_CRIT, "Error adjusting interface speed!\r\n"); return mmc_ret; } } /* Now get the extended CSD for the card */ if (MMC_CARD_MMC(card)) { /* For MMC cards, also get the extended csd */ mmc_ret = sdrv_mmc_get_ext_csd(host, card); if (mmc_ret) { DETAIL_PRINTF(SSDK_CRIT, "Failure getting card's ExtCSD information!\r\n"); return mmc_ret; } } else { /*Read SCR for sd card */ mmc_ret = sdrv_mmc_sd_get_card_scr(host, card); if (mmc_ret) { DETAIL_PRINTF(SSDK_CRIT, "Failure getting card's SCR register\r\n"); return mmc_ret; } /* Read SSR for the SD card */ mmc_ret = sdrv_mmc_sd_get_card_ssr(host, card); if (mmc_ret) { DETAIL_PRINTF(SSDK_CRIT, "Failed to get SSR from the card\r\n"); return mmc_ret; } } /* Decode and save the CSD register */ mmc_ret = sdrv_mmc_decode_and_save_csd(card); if (mmc_ret) { DETAIL_PRINTF(SSDK_CRIT, "Failure decoding card's CSD information!\r\n"); return mmc_ret; } if (MMC_CARD_MMC(card)) { /* Set the bus width based on host, target capbilities */ if (cfg->bus_width == MMC_BUS_WIDTH_8BIT && host->caps.bus_width_8bit) bus_width = MMC_DATA_BUS_WIDTH_8BIT; /* * Host contoller by default supports 4 bit & 1 bit mode. * No need to check for host support here */ else if (cfg->bus_width == MMC_BUS_WIDTH_4BIT) bus_width = MMC_DATA_BUS_WIDTH_4BIT; else bus_width = MMC_DATA_BUS_WIDTH_1BIT; /* Set 4/8 bit SDR bus width in controller */ mmc_ret = sdrv_sdhci_set_bus_width(host, bus_width); if (mmc_ret) { DETAIL_PRINTF(SSDK_CRIT, "Failed to set bus width for host controller\r\n"); return mmc_ret; } /* * Enable high speed mode in the follwing order: * 1. HS400 mode if supported by host & card * 1. HS200 mode if supported by host & card * 2. DDR mode host, if supported by host & card * 3. Use normal speed mode with supported bus width */ if (host->caps.hs400_support && sdrv_mmc_card_supports_hs400_mode(card)) { DETAIL_PRINTF(SSDK_INFO, "SDHC Running in HS400 mode\r\n"); mmc_ret = sdrv_mmc_set_hs400_mode(host, card, bus_width); if (mmc_ret) { DETAIL_PRINTF(SSDK_CRIT, "Failure to set HS400 mode for Card(RCA:%x)\r\n", card->rca); return mmc_ret; } } #if USE_TARGET_HS200_CAPS else if (host->caps.hs200_support && host->caps.sdr104_support && sdrv_mmc_card_supports_hs200_mode(card)) #else else if (host->caps.sdr104_support && sdrv_mmc_card_supports_hs200_mode(card)) #endif { DETAIL_PRINTF(SSDK_INFO, "SDHC Running in HS200 mode\r\n"); mmc_ret = sdrv_mmc_set_hs200_mode(host, card, bus_width); if (mmc_ret) { DETAIL_PRINTF(SSDK_CRIT, "Failure to set HS200 mode for Card(RCA:%x)\r\n", card->rca); return mmc_ret; } } else if (host->caps.ddr_support && sdrv_mmc_card_supports_ddr_mode(card)) { DETAIL_PRINTF(SSDK_INFO, "SDHC Running in DDR mode\r\n"); mmc_ret = sdrv_mmc_set_ddr_mode(host, card, bus_width); if (mmc_ret) { DETAIL_PRINTF(SSDK_CRIT, "Failure to set DDR mode for Card(RCA:%x)\r\n", card->rca); return mmc_ret; } } else { DETAIL_PRINTF(SSDK_INFO, "SDHC Running in High Speed mode\r\n"); /* Set HS_TIMING mode */ mmc_ret = sdrv_mmc_set_hs_interface(host, card); if (mmc_ret) { DETAIL_PRINTF(SSDK_CRIT, "Failure to enalbe HS mode for Card(RCA:%x)\r\n", card->rca); return mmc_ret; } /* Set wide bus mode */ mmc_ret = sdrv_mmc_set_bus_width(host, card, bus_width); if (mmc_ret) { DETAIL_PRINTF(SSDK_CRIT, "Failure to set wide bus for Card(RCA:%x)\r\n", card->rca); return mmc_ret; } } } else if (card->type != MMC_CARD_TYPE_UHS) { /* Check the supported bus width for the card from SCR register */ if ((card->scr.bus_widths & SD_SCR_WIDTH_4BIT) && (cfg->bus_width == MMC_BUS_WIDTH_4BIT)) bus_width = MMC_DATA_BUS_WIDTH_4BIT; else bus_width = MMC_DATA_BUS_WIDTH_1BIT; mmc_ret = sdrv_mmc_sd_set_bus_width(host, card, bus_width); if (mmc_ret) { DETAIL_PRINTF(SSDK_CRIT, "Failed to set bus width for the card\r\n"); return mmc_ret; } /* Set bit SDR bus width in controller */ mmc_ret = sdrv_sdhci_set_bus_width(host, bus_width); if (mmc_ret) { DETAIL_PRINTF(SSDK_CRIT, "Failed to set bus width for host controller\r\n"); return mmc_ret; } } card->block_size = MMC_BLK_SZ; #ifdef MMC_ENABLE_RST_N_FUNC if (MMC_CARD_MMC(card)) { /* Enable RST_n_FUNCTION */ if (!card->ext_csd[MMC_EXT_CSD_RST_N_FUNC]) { mmc_ret = sdrv_mmc_switch_cmd(host, card, MMC_SET_BIT, MMC_EXT_CSD_RST_N_FUNC, RST_N_FUNC_ENABLE); if (mmc_ret) { DETAIL_PRINTF(SSDK_CRIT, "Failed to enable RST_n_FUNCTION\r\n"); return mmc_ret; } } } #endif if (MMC_CARD_MMC(card) && dev->card.ext_csd[MMC_EXT_CSD_REV] >= 6) { mmc_ret = sdrv_mmc_switch_cmd(&dev->host, &dev->card, MMC_ACCESS_WRITE, MMC_POWER_OFF_NOTIFICATION, MMC_POWER_ON); if (mmc_ret) { DETAIL_PRINTF(SSDK_CRIT, "Failed to power off notification MMC_POWER_ON\r\n"); return mmc_ret; } card->ext_csd[MMC_POWER_OFF_NOTIFICATION] = MMC_POWER_ON; } return mmc_ret; } /* * Function: mmc display csd * Arg : None * Return : None * Flow : Displays the csd information */ static void sdrv_mmc_display_csd(struct mmc_card *card) { ssdk_printf(SSDK_INFO, "erase_grpsize: %d\r\n", card->csd.erase_grp_size); ssdk_printf(SSDK_INFO, "erase_grpmult: %d\r\n", card->csd.erase_grp_mult); ssdk_printf(SSDK_INFO, "wp_grpsize: %d\r\n", card->csd.wp_grp_size); ssdk_printf(SSDK_INFO, "wp_grpen: %d\r\n", card->csd.wp_grp_enable); ssdk_printf(SSDK_INFO, "perm_wp: %d\r\n", card->csd.perm_wp); ssdk_printf(SSDK_INFO, "temp_wp: %d\r\n", card->csd.temp_wp); } uint32_t sdrv_mmc_get_erase_group_size(struct mmc_device *dev) { struct mmc_csd *mmc_csd = &dev->card.csd; if (dev->card.type < MMC_TYPE_MMCHC) { DETAIL_PRINTF(SSDK_INFO, "\r\n sd card au_size %d, num_aus %d\r\n", dev->card.ssr.au_size, dev->card.ssr.num_aus); if (mmc_csd->cmmc_structure == 1) { /* CSD Version 2.0 */ dev->erase_grp_size = MMC_BLK_SZ; } else { /* CSD Version 1.0 */ if (mmc_csd->erase_blk_len) dev->erase_grp_size = MMC_BLK_SZ; else dev->erase_grp_size = mmc_csd->sector_size * MMC_BLK_SZ; } } else { DETAIL_PRINTF(SSDK_INFO, "\r\n mmc card erase_size %d, erase_mult %d\r\n", dev->card.csd.erase_grp_size, dev->card.csd.erase_grp_mult); dev->erase_grp_size = (dev->card.csd.erase_grp_size + 1) * (dev->card.csd.erase_grp_mult + 1) * MMC_BLK_SZ; } return dev->erase_grp_size; } uint64_t sdrv_mmc_get_size(struct mmc_device *dev, uint32_t type) { struct mmc_card *card = &dev->card; if (MMC_CARD_MMC(card)) { switch (type) { case PART_ACCESS_DEFAULT: return card->capacity; break; case PART_ACCESS_BOOT1: return card->boot_size; break; case PART_ACCESS_BOOT2: return card->boot_size; break; case PART_ACCESS_RPMB: return card->rpmb_size; break; case PART_ACCESS_GP1: return 0; break; case PART_ACCESS_GP2: return 0; break; case PART_ACCESS_GP3: return 0; break; case PART_ACCESS_GP4: return 0; break; default: return 0; } } else if (MMC_CARD_SD(card)) { switch (type) { case PART_ACCESS_DEFAULT: return card->capacity; break; default: return 0; } } else return 0; } uint32_t sdrv_mmc_get_block_size(struct mmc_device *dev) { struct mmc_card *card = &dev->card; return card->block_size; } uint32_t sdrv_mmc_get_data_after_erase(struct mmc_device *dev) { struct mmc_card *card = &dev->card; return MMC_CARD_SD(card) ? card->scr.data_stat_after_erase : 0; } /* * Function: sdrv_mmc_alloc_dev * Arg : None * Return : Pointer to mmc device * Flow : Alloc mmc device memory */ struct mmc_device *sdrv_mmc_alloc_dev(void) { struct mmc_device *dev; dev = (struct mmc_device *)malloc(sizeof(struct mmc_device)); if (!dev) { DETAIL_PRINTF(SSDK_CRIT, "Error allocating mmc device\r\n"); return NULL; } memset(dev, 0, sizeof(struct mmc_device)); return dev; } /* * Function: sdrv_mmc_sdrv_sdhci_init * Arg : mmc device structure * MMC configuration data * Return : 0 on Success, 1 on Failure * Flow : Entry point to MMC boot process * Initialize the sd host controller * Initialize the mmc card * Set the clock & high speed mode */ status_t sdrv_mmc_sdrv_sdhci_init(struct mmc_device *dev) { status_t mmc_ret = SDRV_STATUS_OK; ASSERT(dev); memset(&dev->card, 0, sizeof(struct mmc_card)); dev->part_curr = PART_ACCESS_DEFAULT; /* Initialize the host & clock */ DETAIL_PRINTF(SSDK_INFO, " Initializing MMC host data structure and clock!\r\n"); mmc_ret = sdrv_mmc_host_init(dev); if (mmc_ret) { DETAIL_PRINTF(SSDK_CRIT, "Error Initializing MMC host : %u\r\n", mmc_ret); return mmc_ret; } /* Initialize and identify cards connected to host */ mmc_ret = sdrv_mmc_card_init(dev); if (mmc_ret) { DETAIL_PRINTF(SSDK_CRIT, "Failed detecting MMC/SDC @ slot%d\r\n", dev->config.slot); return mmc_ret; } DETAIL_PRINTF(SSDK_INFO, "Done initialization of the card\r\n"); sdrv_mmc_display_csd(&dev->card); return mmc_ret; } static status_t sdrv_mmc_parse_response(uint32_t resp) { status_t mmc_ret = SDRV_STATUS_OK; /* Trying to write beyond card capacity */ if (resp & MMC_R1_ADDR_OUT_OF_RANGE) { DETAIL_PRINTF(SSDK_CRIT, "Attempting to read or write beyond the Device capacity\r\n"); mmc_ret = SDRV_STATUS_MMC_CMD_RSP_ERR; } /* Misaligned address not matching block length */ if (resp & MMC_R1_ADDR_ERR) { DETAIL_PRINTF(SSDK_CRIT, "The misaligned address did not match the block length used\r\n"); mmc_ret = SDRV_STATUS_MMC_CMD_RSP_ERR; } /* Invalid block length */ if (resp & MMC_R1_BLOCK_LEN_ERR) { DETAIL_PRINTF(SSDK_CRIT, "The transferred bytes does not match the block length\r\n"); mmc_ret = SDRV_STATUS_MMC_CMD_RSP_ERR; } /* Tried to program write protected block */ if (resp & MMC_R1_WP_VIOLATION) { DETAIL_PRINTF(SSDK_CRIT, "Attempt to program a write protected block\r\n"); mmc_ret = SDRV_STATUS_MMC_CMD_RSP_ERR; } /* card controller error */ if (resp & MMC_R1_CC_ERROR) { DETAIL_PRINTF(SSDK_CRIT, "Device error occurred, which is not related to the host command\r\n"); mmc_ret = SDRV_STATUS_MMC_CMD_RSP_ERR; } /* Generic error */ if (resp & MMC_R1_GENERIC_ERR) { DETAIL_PRINTF(SSDK_CRIT, "A generic Device error\r\n"); mmc_ret = SDRV_STATUS_MMC_CMD_RSP_ERR; } /* Finally check for card in TRAN state */ if (MMC_CARD_STATUS(resp) != MMC_TRAN_STATE) { DETAIL_PRINTF(SSDK_CRIT, "MMC card is not in TRAN state\r\n"); mmc_ret = SDRV_STATUS_MMC_CMD_RSP_ERR; } return mmc_ret; } static status_t sdrv_mmc_stop_command(struct mmc_device *dev) { struct mmc_command cmd; status_t mmc_ret = SDRV_STATUS_OK; memset(&cmd, 0, sizeof(struct mmc_command)); if (dev->host.card_type == SDHCI_SDIO_CARD) cmd.cmd_index = CMD52_SDIO_STOP_TRANSMISSION; else cmd.cmd_index = CMD12_STOP_TRANSMISSION; cmd.argument = (dev->card.rca << 16) | BIT(0); cmd.cmd_type = SDHCI_CMD_TYPE_ABORT; cmd.resp_type = SDHCI_CMD_RESP_R1; mmc_ret = sdrv_sdhci_send_command(&dev->host, &cmd); if (mmc_ret) { DETAIL_PRINTF(SSDK_CRIT, "Failed to send stop command\r\n"); return mmc_ret; } /* Response contains 32 bit Card status. * Parse the errors & provide relevant information */ return sdrv_mmc_parse_response(cmd.resp[0]); } static uint32_t sdrv_mmc_set_data_timeout(struct mmc_device *dev, struct mmc_command *cmd) { struct sdhci_host *host = &dev->host; struct mmc_card *card = &dev->card; uint32_t mult = 1; uint32_t timeout_ns; uint32_t timeout_clks; if (!cmd->data_present) return 0; /* * SDIO cards only define an upper 1 s limit on access. */ if (MMC_CARD_SDIO(card)) cmd->cmd_timeout = 1000000; /* * SD cards use a 100 multiplier rather than 10 */ mult = MMC_CARD_SD(card) ? 100 : 10; /* * Scale up the multiplier (and therefore the timeout) by * the r2w factor for writes. */ if (cmd->trans_mode == SDHCI_MMC_WRITE) mult <<= card->csd.r2w_factor; timeout_ns = card->csd.taac_ns * mult; timeout_clks = card->csd.taac_clks * mult; /* * SD cards also have an upper limit on the timeout. */ if (MMC_CARD_SD(card)) { uint32_t timeout_us, limit_us; timeout_us = timeout_ns / 1000; if (host->cur_clk_rate) timeout_us += timeout_clks * 1000 / (host->cur_clk_rate / 1000); if (cmd->trans_mode == SDHCI_MMC_WRITE) /* * The MMC spec "It is strongly recommended * for hosts to implement more than 500ms * timeout value even if the card indicates * the 250ms maximum busy length." Even the * previous value of 300ms is known to be * insufficient for some cards. */ limit_us = 3000000; else limit_us = 100000; /* * SDHC cards always use these fixed values. */ if (timeout_us > limit_us) { timeout_ns = limit_us * 1000; timeout_clks = 0; } /* assign limit value if invalid */ if (timeout_us == 0) timeout_ns = limit_us * 1000; } cmd->cmd_timeout = timeout_ns / 1000; return 0; } /* * Function: actual mmc sdhci read * Arg : mmc device structure, block address, number of blocks & destination * Return : 0 on Success, non zero on success * Flow : Fill in the command structure & send the command */ static status_t sdrv_mmc_send_read(struct mmc_device *dev, void *dest, uint32_t blk_addr, uint32_t num_blocks) { status_t mmc_ret = SDRV_STATUS_OK; struct mmc_command cmd; uint32_t status; uint32_t retry = 0; struct mmc_card *card = &dev->card; memset(&cmd, 0, sizeof(struct mmc_command)); /* CMD17/18 Format: * [31:0] Data Address */ if (num_blocks == 1) cmd.cmd_index = CMD17_READ_SINGLE_BLOCK; else cmd.cmd_index = CMD18_READ_MULTIPLE_BLOCK; /* * Standard emmc cards use byte mode addressing * convert the block address to byte address before * sending the command */ if (card->type == MMC_TYPE_STD_MMC) cmd.argument = blk_addr * card->block_size; else cmd.argument = blk_addr; cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL; cmd.resp_type = SDHCI_CMD_RESP_R1; cmd.trans_mode = SDHCI_MMC_READ; cmd.data_present = 0x1; /* Use CMD23 If card supports CMD23: * For SD card use the value read from SCR register * For emmc by default use CMD23. * Also as per SDCC spec always use CMD23 to stop * multiblock read/write if UHS (Ultra High Speed) is * enabled */ if (MMC_CARD_SD(card)) cmd.cmd23_support = dev->card.scr.cmd23_support; else cmd.cmd23_support = 0x1; cmd.data.data_ptr = dest; cmd.data.num_blocks = num_blocks; cmd.retries = MMC_CMD_RETRIES; /* config cmd data hw NAC timeout. * delay between the end bit of the read command * and the start bit of the data block. * interrupt mode, hw timeout valid. */ sdrv_mmc_set_data_timeout(dev, &cmd); /* send command */ mmc_ret = sdrv_sdhci_send_command(&dev->host, &cmd); /* For multi block read failures send stop command */ if (mmc_ret && num_blocks > 1) { DETAIL_PRINTF(SSDK_CRIT, "Failed to send read cmd\n"); return mmc_ret; } /* * Response contains 32 bit Card status. * Parse the errors & provide relevant information */ mmc_ret = sdrv_mmc_parse_response(cmd.resp[0]); if (mmc_ret) return mmc_ret; while (1) { mmc_ret = sdrv_mmc_get_card_status(&dev->host, &dev->card, &status); if (mmc_ret) { DETAIL_PRINTF(SSDK_CRIT, "Failed to get card status after read\r\n"); return mmc_ret; } if ((status & MMC_READY_FOR_DATA) && (MMC_CARD_STATUS(status) == MMC_TRAN_STATE)) break; retry++; udelay(1000); if (retry == MMC_MAX_CARD_STAT_RETRY) { DETAIL_PRINTF(SSDK_CRIT, "Card status check timed out after sending read command\r\n"); return SDRV_STATUS_TIMEOUT; } } return mmc_ret; } /* * Function: mmc sdhci read * Arg : mmc device structure, block address, number of blocks & destination * Return : 0 on Success, non zero on success * Flow : Fill in the command structure & send the command */ status_t sdrv_mmc_sdhci_read(struct mmc_device *dev, void *dest, uint32_t blk_addr, uint32_t num_blocks) { status_t mmc_ret = SDRV_STATUS_OK; struct sdhci_host *host = &dev->host; uint32_t desc_len_max = 0; uint32_t blocks_num_max = 0; uint32_t rblocks_num = 0; uint64_t dest_offset = 0; uint64_t addr_offset = 0; if (host->caps.addr_64bit_v4) { desc_len_max = SDHCI_ADMA2_DESC_LINE_SZ_V4 * (ADMA_DESC_LIST_SIZE - 1); } else { desc_len_max = SDHCI_ADMA_DESC_LINE_SZ * (ADMA_DESC_LIST_SIZE - 1); } blocks_num_max = desc_len_max / SDHCI_MMC_BLK_SZ; blocks_num_max = MIN(blocks_num_max, MMC_BLOCK_COUNT_MASK); while (num_blocks) { rblocks_num = MIN(blocks_num_max, num_blocks); mmc_ret = sdrv_mmc_send_read(dev, (uint8_t *)dest + dest_offset, blk_addr + addr_offset, rblocks_num); if (mmc_ret) return mmc_ret; num_blocks -= rblocks_num; addr_offset += rblocks_num; dest_offset += rblocks_num * SDHCI_MMC_BLK_SZ; } return 0; } /* * Function: actual mmc sdhci write * Arg : mmc device structure, block address, number of blocks & source * Return : 0 on Success, non zero on success * Flow : Fill in the command structure & send the command */ static status_t sdrv_mmc_send_write(struct mmc_device *dev, void *src, uint32_t blk_addr, uint32_t num_blocks) { status_t mmc_ret = SDRV_STATUS_OK; uint32_t status; uint32_t retry = 0; struct mmc_command cmd; struct mmc_card *card = &dev->card; memset(&cmd, 0, sizeof(struct mmc_command)); /* CMD24/25 Format: * [31:0] Data Address */ if (num_blocks == 1) cmd.cmd_index = CMD24_WRITE_SINGLE_BLOCK; else cmd.cmd_index = CMD25_WRITE_MULTIPLE_BLOCK; /* * Standard emmc cards use byte mode addressing * convert the block address to byte address before * sending the command */ if (card->type == MMC_TYPE_STD_MMC) cmd.argument = blk_addr * card->block_size; else cmd.argument = blk_addr; cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL; cmd.resp_type = SDHCI_CMD_RESP_R1; cmd.trans_mode = SDHCI_MMC_WRITE; /* Use CMD23 If card supports CMD23: * For SD card use the value read from SCR register * For emmc by default use CMD23. * Also as per SDCC spec always use CMD23 to stop * multiblock read/write if UHS (Ultra High Speed) is * enabled */ if (MMC_CARD_SD(card)) cmd.cmd23_support = dev->card.scr.cmd23_support; else cmd.cmd23_support = 0x1; cmd.data_present = 0x1; cmd.data.data_ptr = src; cmd.data.num_blocks = num_blocks; cmd.retries = MMC_CMD_RETRIES; /* config cmd data hw NAC timeout. * delay between the end bit of the read command * and the start bit of the data block. * interrupt mode, hw timeout valid. */ sdrv_mmc_set_data_timeout(dev, &cmd); /* send command */ mmc_ret = sdrv_sdhci_send_command(&dev->host, &cmd); /* For multi block write failures send stop command */ if (mmc_ret && num_blocks > 1) { DETAIL_PRINTF(SSDK_CRIT, "Failed to send write cmd\n"); return mmc_ret; } /* * Response contains 32 bit Card status. * Parse the errors & provide relevant information */ mmc_ret = sdrv_mmc_parse_response(cmd.resp[0]); if (mmc_ret) return mmc_ret; while (1) { mmc_ret = sdrv_mmc_get_card_status(&dev->host, &dev->card, &status); if (mmc_ret) { DETAIL_PRINTF(SSDK_CRIT, "Failed to get card status after write\r\n"); return mmc_ret; } if ((status & MMC_READY_FOR_DATA) && (MMC_CARD_STATUS(status) == MMC_TRAN_STATE)) break; retry++; udelay(1000); if (retry == MMC_MAX_CARD_STAT_RETRY) { DETAIL_PRINTF(SSDK_CRIT, "Card status check timed out after sending write command\r\n"); return SDRV_STATUS_TIMEOUT; } } return mmc_ret; } /* * Function: mmc sdhci write * Arg : mmc device structure, block address, number of blocks & source * Return : 0 on Success, non zero on success * Flow : Fill in the command structure & send the command */ status_t sdrv_mmc_sdhci_write(struct mmc_device *dev, void *src, uint32_t blk_addr, uint32_t num_blocks) { status_t mmc_ret = SDRV_STATUS_OK; struct sdhci_host *host = &dev->host; uint32_t desc_len_max = 0; uint32_t blocks_num_max = 0; uint32_t rblocks_num = 0; uint64_t src_offset = 0; uint64_t addr_offset = 0; if (host->caps.addr_64bit_v4) { desc_len_max = SDHCI_ADMA2_DESC_LINE_SZ_V4 * (ADMA_DESC_LIST_SIZE - 1); } else { desc_len_max = SDHCI_ADMA_DESC_LINE_SZ * (ADMA_DESC_LIST_SIZE - 1); } blocks_num_max = desc_len_max / SDHCI_MMC_BLK_SZ; blocks_num_max = MIN(blocks_num_max, MMC_BLOCK_COUNT_MASK); while (num_blocks) { rblocks_num = MIN(blocks_num_max, num_blocks); mmc_ret = sdrv_mmc_send_write(dev, (uint8_t *)src + src_offset, blk_addr + addr_offset, rblocks_num); if (mmc_ret) return mmc_ret; num_blocks -= rblocks_num; addr_offset += rblocks_num; src_offset += rblocks_num * SDHCI_MMC_BLK_SZ; } return mmc_ret; } /* * Send the erase group start address using CMD35 */ static status_t sdrv_mmc_send_erase_grp_start(struct mmc_device *dev, uint32_t erase_start) { status_t mmc_ret = SDRV_STATUS_OK; struct mmc_command cmd; struct mmc_card *card = &dev->card; memset(&cmd, 0, sizeof(struct mmc_command)); if (MMC_CARD_MMC(card)) cmd.cmd_index = CMD35_ERASE_GROUP_START; else cmd.cmd_index = CMD32_ERASE_WR_BLK_START; /* * Standard emmc cards use byte mode addressing * convert the block address to byte address before * sending the command */ if (card->type == MMC_TYPE_STD_MMC) cmd.argument = erase_start * card->block_size; else cmd.argument = erase_start; cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL; cmd.resp_type = SDHCI_CMD_RESP_R1; cmd.retries = MMC_CMD_RETRIES; /* send command */ mmc_ret = sdrv_sdhci_send_command(&dev->host, &cmd); if (mmc_ret) return mmc_ret; /* * CMD35 on failure returns address out of range error */ if (MMC_ADDR_OUT_OF_RANGE(cmd.resp[0])) { DETAIL_PRINTF(SSDK_CRIT, "Address for CMD35 is out of range\r\n"); return SDRV_STATUS_MMC_CMD_RSP_ERR; } return mmc_ret; } /* * Send the erase group end address using CMD36 */ static status_t sdrv_mmc_send_erase_grp_end(struct mmc_device *dev, uint32_t erase_end) { status_t mmc_ret = SDRV_STATUS_OK; struct mmc_command cmd; struct mmc_card *card = &dev->card; memset(&cmd, 0, sizeof(struct mmc_command)); if (MMC_CARD_MMC(card)) cmd.cmd_index = CMD36_ERASE_GROUP_END; else cmd.cmd_index = CMD33_ERASE_WR_BLK_END; /* * Standard emmc cards use byte mode addressing * convert the block address to byte address before * sending the command */ if (card->type == MMC_TYPE_STD_MMC) cmd.argument = erase_end * card->block_size; else cmd.argument = erase_end; cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL; cmd.resp_type = SDHCI_CMD_RESP_R1; cmd.retries = MMC_CMD_RETRIES; /* send command */ mmc_ret = sdrv_sdhci_send_command(&dev->host, &cmd); if (mmc_ret) return mmc_ret; /* * CMD3 on failure returns address out of range error */ if (MMC_ADDR_OUT_OF_RANGE(cmd.resp[0])) { DETAIL_PRINTF(SSDK_CRIT, "Address for CMD36 is out of range\r\n"); return SDRV_STATUS_MMC_CMD_RSP_ERR; } return mmc_ret; } /* * Send the erase CMD38, to erase the selected erase groups */ static status_t sdrv_mmc_send_erase(struct mmc_device *dev, uint64_t erase_timeout) { status_t mmc_ret = SDRV_STATUS_OK; struct mmc_command cmd; uint32_t status; uint32_t retry = 0; memset(&cmd, 0, sizeof(struct mmc_command)); cmd.cmd_index = CMD38_ERASE; cmd.argument = 0x00000000; cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL; cmd.resp_type = SDHCI_CMD_RESP_R1B; cmd.cmd_timeout = erase_timeout; cmd.retries = MMC_CMD_RETRIES; /* send command */ mmc_ret = sdrv_sdhci_send_command(&dev->host, &cmd); if (mmc_ret) return mmc_ret; do { mmc_ret = sdrv_mmc_get_card_status(&dev->host, &dev->card, &status); if (mmc_ret) { DETAIL_PRINTF(SSDK_CRIT, "Failed to get card status after erase\r\n"); return mmc_ret; } /* Check if the response of erase command has eras skip status set */ if (status & MMC_R1_WP_ERASE_SKIP) DETAIL_PRINTF(SSDK_CRIT, "Write Protect set for the region, only partial space was erased\r\n"); retry++; udelay(1000); if (retry == MMC_MAX_CARD_STAT_RETRY) { DETAIL_PRINTF(SSDK_CRIT, "Card status check timed out after sending erase command\r\n"); return SDRV_STATUS_TIMEOUT; } } while (!(status & MMC_READY_FOR_DATA) || (MMC_CARD_STATUS(status) == MMC_PROG_STATE)); return mmc_ret; } /* * Function: mmc sdhci erase * Arg : mmc device structure, block address and length * Return : 0 on Success, non zero on failure * Flow : Fill in the command structure & send the command */ status_t sdrv_mmc_sdhci_erase(struct mmc_device *dev, uint32_t blk_addr, uint64_t len) { status_t mmc_ret = SDRV_STATUS_OK; uint32_t erase_unit_sz = 0; uint32_t erase_start; uint32_t erase_end; uint32_t blk_end; uint32_t num_erase_grps; uint64_t erase_timeout = 0; struct mmc_card *card; card = &dev->card; /* * Calculate the erase unit size, * 1. Based on emmc 4.5 spec for emmc card * 2. Use SD Card Status info for SD cards */ if (MMC_CARD_MMC(card)) { /* * Calculate the erase unit size as per the emmc specification v4.5 */ if (dev->card.ext_csd[MMC_ERASE_GRP_DEF]) erase_unit_sz = (MMC_HC_ERASE_MULT * dev->card.ext_csd[MMC_HC_ERASE_GRP_SIZE]) / MMC_BLK_SZ; else erase_unit_sz = (dev->card.csd.erase_grp_size + 1) * (dev->card.csd.erase_grp_mult + 1); } else { struct mmc_csd *mmc_csd = &card->csd; if (mmc_csd->cmmc_structure == 1) { /* CSD Version 2.0 */ erase_unit_sz = 1; } else { /* CSD Version 1.0 */ if (mmc_csd->erase_blk_len) erase_unit_sz = 1; else erase_unit_sz = mmc_csd->sector_size; } } uint32_t num_blocks = len / MMC_BLK_SZ; if (num_blocks < erase_unit_sz) { DETAIL_PRINTF(SSDK_CRIT, "Requested length is less than min erase group size\r\n"); return SDRV_STATUS_INVALID_PARAM; } /* Calculate erase groups based on the length in blocks */ num_erase_grps = num_blocks / erase_unit_sz; /* Start address of the erase range */ erase_start = blk_addr; if (MMC_CARD_MMC(card)) /* Last address of the erase range */ erase_end = blk_addr + ((num_erase_grps - 1) * erase_unit_sz); else erase_end = blk_addr + num_blocks - 1; /* Boundary check for overlap */ blk_end = blk_addr + num_blocks; if (erase_end > blk_end) { DETAIL_PRINTF(SSDK_CRIT, "The erase group overlaps the max requested for erase\r\n"); erase_end -= erase_unit_sz; } /* Send CMD35 for erase group start */ mmc_ret = sdrv_mmc_send_erase_grp_start(dev, erase_start); if (mmc_ret) { DETAIL_PRINTF(SSDK_CRIT, "Failed to send erase grp start address\r\n"); return mmc_ret; } /* Send CMD36 for erase group end */ mmc_ret = sdrv_mmc_send_erase_grp_end(dev, erase_end); if (mmc_ret) { DETAIL_PRINTF(SSDK_CRIT, "Failed to send erase grp end address\r\n"); return mmc_ret; } if (MMC_CARD_MMC(card)) { /* * As per emmc 4.5 spec section 7.4.27, calculate the erase timeout * erase_timeout = 300ms * ERASE_TIMEOUT_MULT * num_erase_grps */ erase_timeout = (300 * 1000 * card->ext_csd[MMC_ERASE_TIMEOUT_MULT] * num_erase_grps); } else { /* * For sd card, calculate the erase timeout * erase_timeout = (earse_timeout * num_erase_grps + erase_offset) * 1s */ erase_timeout = card->ssr.erase_timeout * num_erase_grps + card->ssr.erase_offset; erase_timeout = MAX(erase_timeout, 1); erase_timeout *= 1000 * 1000; DETAIL_PRINTF(SSDK_DEBUG, "\r\n ssr erase_timeout %d, num_erase_grps %d, ssr erase_offset %d\r\n", card->ssr.erase_timeout, num_erase_grps, card->ssr.erase_offset); } /* Send CMD38 to perform erase */ mmc_ret = sdrv_mmc_send_erase(dev, erase_timeout); if (mmc_ret) { DETAIL_PRINTF(SSDK_CRIT, "Failed to erase the specified partition\r\n"); return mmc_ret; } return mmc_ret; } /* * Function: mmc sdhci cancel * Arg : mmc device structure * Return : 0 on Success, non zero on failure * Flow : call sdrv_mmc_stop_command */ status_t sdrv_mmc_sdhci_cancel(struct mmc_device *dev) { return sdrv_mmc_stop_command(dev); } /* * Function: mmc get wp status * Arg : mmc device structure, block address and buffer for getting wp * status Return : 0 on Success, 1 on Failure Flow : Get the WP group status * by sending CMD31 */ status_t sdrv_mmc_get_wp_status(struct mmc_device *dev, uint32_t addr, uint8_t *wp_status) { status_t mmc_ret = SDRV_STATUS_OK; struct mmc_command cmd; memset(&cmd, 0, sizeof(struct mmc_command)); cmd.cmd_index = CMD31_SEND_WRITE_PROT_TYPE; cmd.argument = addr; cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL; cmd.resp_type = SDHCI_CMD_RESP_R1; cmd.trans_mode = SDHCI_MMC_READ; cmd.data_present = 0x1; cmd.data.data_ptr = wp_status; cmd.data.num_blocks = 0x1; cmd.data.blk_sz = 0x8; mmc_ret = sdrv_sdhci_send_command(&dev->host, &cmd); if (mmc_ret) { DETAIL_PRINTF(SSDK_CRIT, "Failed to get status of write protect bits\r\n"); return mmc_ret; } return mmc_ret; } /* * Function: mmc set/clear WP on user area * Arg : mmc device structure, block address,len, & flag to set or clear * Return : 0 on success, 1 on failure * Flow : Function to set/clear power on write protect on user area */ status_t sdrv_mmc_set_clr_power_on_wp_user(struct mmc_device *dev, uint32_t addr, uint64_t len, uint8_t set_clr) { struct mmc_command cmd; struct mmc_card *card = &dev->card; uint32_t wp_grp_size; uint32_t status; uint32_t num_wp_grps; status_t ret = SDRV_STATUS_OK; uint32_t retry = 0; uint32_t i; memset(&cmd, 0, sizeof(struct mmc_command)); /* Convert len into blocks */ len = len / MMC_BLK_SZ; wp_grp_size = dev->card.wp_grp_size; /* Disable PERM WP */ ret = sdrv_mmc_switch_cmd(&dev->host, &dev->card, MMC_SET_BIT, MMC_USR_WP, MMC_US_PERM_WP_DIS); if (ret) { DETAIL_PRINTF(SSDK_CRIT, "Failed to Disable PERM WP\r\n"); return ret; } /* Read the default values for user WP */ ret = sdrv_mmc_get_ext_csd(&dev->host, &dev->card); if (ret) { DETAIL_PRINTF(SSDK_CRIT, "Failed to read ext csd for the card\r\n"); return ret; } /* Check if user power on WP is disabled or perm WP is enabled */ if ((dev->card.ext_csd[MMC_USR_WP] & MMC_US_PWR_WP_DIS) || (dev->card.ext_csd[MMC_USR_WP] & MMC_US_PERM_WP_EN)) { DETAIL_PRINTF(SSDK_CRIT, "Power on protection is disabled, cannot be set\r\n"); return SDRV_STATUS_FAIL; } if (len < wp_grp_size) { DETAIL_PRINTF(SSDK_CRIT, "Length is less than min WP size, WP was not set\r\n"); return SDRV_STATUS_FAIL; } /* Set power on USER WP */ ret = sdrv_mmc_switch_cmd(&dev->host, &dev->card, MMC_SET_BIT, MMC_USR_WP, MMC_US_PWR_WP_EN); if (ret) { DETAIL_PRINTF(SSDK_CRIT, "Failed to set power on WP for user\r\n"); return ret; } num_wp_grps = ROUNDUP(len, wp_grp_size) / wp_grp_size; if (set_clr) cmd.cmd_index = CMD28_SET_WRITE_PROTECT; else cmd.cmd_index = CMD29_CLEAR_WRITE_PROTECT; cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL; cmd.resp_type = SDHCI_CMD_RESP_R1B; for (i = 0; i < num_wp_grps; i++) { /* * Standard emmc cards use byte mode addressing * convert the block address to byte address before * sending the command */ if (card->type == MMC_TYPE_STD_MMC) cmd.argument = (addr + (i * wp_grp_size)) * card->block_size; else cmd.argument = addr + (i * wp_grp_size); ret = sdrv_sdhci_send_command(&dev->host, &cmd); if (ret) return ret; /* CMD28/CMD29 On failure returns address out of range error */ if (MMC_ADDR_OUT_OF_RANGE(cmd.resp[0])) { DETAIL_PRINTF(SSDK_CRIT, "Address for CMD28/29 is out of range\r\n"); return SDRV_STATUS_MMC_CMD_RSP_ERR; } /* Check the card status */ do { ret = sdrv_mmc_get_card_status(&dev->host, &dev->card, &status); if (ret) { DETAIL_PRINTF(SSDK_CRIT, "Failed to get card status afterapplying write protect\r\n"); return ret; } /* Time out for WP command */ retry++; udelay(1000); if (retry == MMC_MAX_CARD_STAT_RETRY) { DETAIL_PRINTF(SSDK_CRIT, "Card status timed out after sending write protect command\r\n"); return SDRV_STATUS_TIMEOUT; } } while (!(status & MMC_READY_FOR_DATA) || (MMC_CARD_STATUS(status) == MMC_PROG_STATE)); } return ret; } /* Function to put the mmc card to sleep */ void sdrv_mmc_put_card_to_sleep(struct mmc_device *dev) { struct mmc_command cmd = {0}; struct mmc_card *card = &dev->card; cmd.cmd_index = CMD7_SELECT_DESELECT_CARD; cmd.argument = 0x00000000; cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL; cmd.resp_type = SDHCI_CMD_RESP_NONE; cmd.retries = MMC_CMD_RETRIES; /* send command */ if (sdrv_sdhci_send_command(&dev->host, &cmd)) { DETAIL_PRINTF(SSDK_CRIT, "card deselect error: %s\r\n", __func__); return; } cmd.cmd_index = CMD5_SLEEP_AWAKE; cmd.argument = (card->rca << MMC_CARD_RCA_BIT) | MMC_CARD_SLEEP; cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL; cmd.resp_type = SDHCI_CMD_RESP_R1B; /* send command */ if (sdrv_sdhci_send_command(&dev->host, &cmd)) DETAIL_PRINTF(SSDK_CRIT, "card sleep error: %s\r\n", __func__); } static status_t sdrv_mmc_can_poweroff_notify(struct mmc_device *dev) { struct mmc_card *card; card = &dev->card; return MMC_CARD_MMC(card) && card->ext_csd[MMC_POWER_OFF_NOTIFICATION] == MMC_POWER_ON; } /* Function to power off Notification mmc card */ status_t sdrv_mmc_power_off_notification(struct mmc_device *dev, uint32_t pon_type) { status_t ret = SDRV_STATUS_OK; ret = sdrv_mmc_can_poweroff_notify(dev); if (ret == false) { DETAIL_PRINTF(SSDK_CRIT, "emmc not support power off notification\r\n"); return SDRV_STATUS_FAIL; } ret = sdrv_mmc_switch_cmd(&dev->host, &dev->card, MMC_ACCESS_WRITE, MMC_POWER_OFF_NOTIFICATION, pon_type); if (ret) { DETAIL_PRINTF(SSDK_CRIT, "Failed to power off notification: %u\r\n", pon_type); return ret; } return ret; } /* * Switch the partition access type to rpmb or default */ status_t sdrv_mmc_sdhci_switch_part(struct mmc_device *dev, uint32_t type) { uint32_t part_access; status_t ret = SDRV_STATUS_OK; struct mmc_card *card; card = &dev->card; if (!MMC_CARD_MMC(card)) return SDRV_STATUS_MMC_DEV_TYPE_ERR; /* Clear the partition access */ part_access = dev->card.ext_csd[MMC_PARTITION_CONFIG] & ~PARTITION_ACCESS_MASK; part_access |= type; ret = sdrv_mmc_switch_cmd(&dev->host, &dev->card, MMC_ACCESS_WRITE, MMC_PARTITION_CONFIG, part_access); if (ret) { DETAIL_PRINTF(SSDK_CRIT, "Failed to switch partition to type: %u\r\n", type); return ret; } dev->card.ext_csd[MMC_PARTITION_CONFIG] = part_access; return ret; } static status_t sdrv_mmc_sdhci_set_blk_cnt(struct mmc_device *dev, uint32_t blk_cnt, uint32_t rel_write) { status_t mmc_ret = SDRV_STATUS_OK; struct mmc_command cmd = {0}; cmd.cmd_index = CMD23_SET_BLOCK_COUNT; cmd.argument = blk_cnt & MMC_BLOCK_COUNT_MASK; cmd.argument |= rel_write; cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL; cmd.resp_type = SDHCI_CMD_RESP_R1; cmd.retries = MMC_CMD_RETRIES; mmc_ret = sdrv_sdhci_send_command(&dev->host, &cmd); if (mmc_ret) { DETAIL_PRINTF(SSDK_CRIT, "Set block count failed: %s\r\n", __func__); return mmc_ret; } return mmc_ret; } status_t sdrv_mmc_sdhci_rpmb_send(struct mmc_device *dev, struct mmc_command *cmd) { int i; uint32_t retry = 5; uint32_t status; uint32_t rel_write = 0; status_t ret = SDRV_STATUS_OK; ASSERT(cmd); /* 1. Set the partition type to rpmb */ ret = sdrv_mmc_sdhci_switch_part(dev, PART_ACCESS_RPMB); if (ret) return ret; for (i = 0; i < MAX_RPMB_CMDS; i++) { if (!cmd[i].cmd_index) break; if (cmd[i].write_flag == true) rel_write = BIT(31); else rel_write = 0; /* 2. Set the block count using cmd23 */ ret = sdrv_mmc_sdhci_set_blk_cnt(dev, cmd[i].data.num_blocks, rel_write); if (ret) goto err; /* 3. Send the command */ ret = sdrv_sdhci_send_command(&dev->host, &cmd[i]); if (ret) goto err; do { /* 4. Poll for card status to ensure rpmb operation completeness */ ret = sdrv_mmc_get_card_status(&dev->host, &dev->card, &status); if (ret) { DETAIL_PRINTF(SSDK_CRIT, "Failed to get card status after rpmb operations\r\n"); goto err; } retry--; udelay(500); if (!retry) { DETAIL_PRINTF(SSDK_CRIT, "Card status check timed out after rpmb operations\r\n"); ret = SDRV_STATUS_TIMEOUT; goto err; } } while (!(status & MMC_READY_FOR_DATA) || (MMC_CARD_STATUS(status) == MMC_PROG_STATE)); } /* If we reach here, that means success */ ret = SDRV_STATUS_OK; err: /* 5. Switch the partition back to default type */ if (sdrv_mmc_sdhci_switch_part(dev, PART_ACCESS_DEFAULT)) return ret; return ret; } status_t sdrv_mmc_sdhci_read_part(struct mmc_device *dev, void *dest, uint32_t blk_addr, uint32_t num_blocks, uint32_t type) { status_t mmc_ret = SDRV_STATUS_OK; if ((NULL == dev) || (NULL == dest)) { DETAIL_PRINTF(SSDK_CRIT, "The passed pointer is null\n"); return SDRV_STATUS_INVALID_PARAM; } struct mmc_card *card = &dev->card; uint64_t mmc_size = sdrv_mmc_get_size(dev, type); if (mmc_size == 0) { DETAIL_PRINTF(SSDK_CRIT, "mmc part %d not support\n", type); return SDRV_STATUS_INVALID_PARAM; } if (!IS_ALIGNED(dest, CONFIG_ARCH_CACHE_LINE)) { DETAIL_PRINTF(SSDK_CRIT, "dest address %p not aligned to cache line %d\n", dest, CONFIG_ARCH_CACHE_LINE); return SDRV_STATUS_INVALID_PARAM; } if (num_blocks == 0 || ((blk_addr + num_blocks) > (mmc_size / card->block_size))) { DETAIL_PRINTF(SSDK_CRIT, "num_blocks == 0 or blk_addr + num_blocks out of the mmc size range\n"); DETAIL_PRINTF(SSDK_CRIT, "blk_addr:%x num_blocks:%x mmc block size:%llx\n", blk_addr, num_blocks, (mmc_size / card->block_size)); return SDRV_STATUS_INVALID_PARAM; } if (MMC_CARD_SD(card) && dev->part_curr != PART_ACCESS_DEFAULT) { DETAIL_PRINTF(SSDK_CRIT, "sd card only support access default part, part type %d\r\n", type); return SDRV_STATUS_INVALID_PARAM; } else if (MMC_CARD_MMC(card) && type != dev->part_curr) { mmc_ret = sdrv_mmc_sdhci_switch_part(dev, type); if (mmc_ret) { DETAIL_PRINTF(SSDK_CRIT, "mmc switch %d part error\r\n", type); return mmc_ret; } dev->part_curr = type; } mmc_ret = sdrv_mmc_sdhci_read(dev, dest, blk_addr, num_blocks); return mmc_ret; } status_t sdrv_mmc_sdhci_write_part(struct mmc_device *dev, void *src, uint32_t blk_addr, uint32_t num_blocks, uint32_t type) { status_t mmc_ret = SDRV_STATUS_OK; if ((NULL == dev) || (NULL == src)) { DETAIL_PRINTF(SSDK_CRIT, "The passed pointer is null\n"); return SDRV_STATUS_INVALID_PARAM; } struct mmc_card *card = &dev->card; uint64_t mmc_size = sdrv_mmc_get_size(dev, type); if (mmc_size == 0) { DETAIL_PRINTF(SSDK_CRIT, "mmc part %d not support\n", type); return SDRV_STATUS_INVALID_PARAM; } if (!IS_ALIGNED(src, CONFIG_ARCH_CACHE_LINE)) { DETAIL_PRINTF(SSDK_CRIT, "src address %p not aligned to cache line %d\n", src, CONFIG_ARCH_CACHE_LINE); return SDRV_STATUS_INVALID_PARAM; } if (num_blocks == 0 || ((blk_addr + num_blocks) > (mmc_size / card->block_size))) { DETAIL_PRINTF(SSDK_CRIT, "num_blocks == 0 or blk_addr + num_blocks out of the mmc size range\n"); DETAIL_PRINTF(SSDK_CRIT, "blk_addr:%x num_blocks:%x mmc block size:%llx\n", blk_addr, num_blocks, (mmc_size / card->block_size)); return SDRV_STATUS_INVALID_PARAM; } if (MMC_CARD_SD(card) && dev->part_curr != PART_ACCESS_DEFAULT) { DETAIL_PRINTF(SSDK_CRIT, "sd card only support access default part, part type %d\r\n", type); return SDRV_STATUS_INVALID_PARAM; } else if (MMC_CARD_MMC(card) && type != dev->part_curr) { mmc_ret = sdrv_mmc_sdhci_switch_part(dev, type); if (mmc_ret) { DETAIL_PRINTF(SSDK_CRIT, "mmc switch %d part error\r\n", type); return mmc_ret; } dev->part_curr = type; } mmc_ret = sdrv_mmc_sdhci_write(dev, src, blk_addr, num_blocks); return mmc_ret; } status_t sdrv_mmc_sdhci_erase_part(struct mmc_device *dev, uint32_t blk_addr, uint32_t num_blocks, uint32_t type) { status_t mmc_ret = SDRV_STATUS_OK; if (NULL == dev) { DETAIL_PRINTF(SSDK_CRIT, "The passed pointer is null\n"); return SDRV_STATUS_INVALID_PARAM; } struct mmc_card *card = &dev->card; uint64_t mmc_size = sdrv_mmc_get_size(dev, type); uint32_t erase_group_size = sdrv_mmc_get_erase_group_size(dev); if (mmc_size == 0) { DETAIL_PRINTF(SSDK_CRIT, "mmc part %d not support\n", type); return SDRV_STATUS_INVALID_PARAM; } if (num_blocks == 0 || ((blk_addr + num_blocks) > (mmc_size / card->block_size))) { DETAIL_PRINTF(SSDK_CRIT, "num_blocks == 0 or blk_addr + num_blocks out of the mmc size range\n"); DETAIL_PRINTF(SSDK_CRIT, "blk_addr:%x num_blocks:%x mmc block size:%llx\n", blk_addr, num_blocks, (mmc_size / card->block_size)); return SDRV_STATUS_INVALID_PARAM; } if (!IS_ALIGNED(blk_addr, (erase_group_size / card->block_size)) || !IS_ALIGNED(num_blocks, (erase_group_size / card->block_size))) { DETAIL_PRINTF(SSDK_CRIT, "blk_addr %x or num_blocks %x not aligned to erase group size %x\n", blk_addr, num_blocks, erase_group_size / card->block_size); return SDRV_STATUS_INVALID_PARAM; } if (MMC_CARD_SD(card) && dev->part_curr != PART_ACCESS_DEFAULT) { DETAIL_PRINTF(SSDK_CRIT, "sd card only support access default part, part type %d\r\n", type); return SDRV_STATUS_INVALID_PARAM; } else if (MMC_CARD_MMC(card) && type != dev->part_curr) { mmc_ret = sdrv_mmc_sdhci_switch_part(dev, type); if (mmc_ret) { DETAIL_PRINTF(SSDK_CRIT, "mmc switch %d part error\r\n", type); return mmc_ret; } dev->part_curr = type; } mmc_ret = sdrv_mmc_sdhci_erase(dev, blk_addr, (uint64_t)num_blocks * MMC_BLK_SZ); return mmc_ret; } static status_t sdrv_sehc_set_clk(struct sdhci_host *host, unsigned int clock) { status_t ret = SDRV_STATUS_OK; uint16_t clk_ctrl = 0; struct mmc_device *mmc = host->parent; struct mmc_config_data *mmc_cfg = &mmc->config; sdrv_ckgen_node_t *clk = mmc_cfg->clk; /* Disable the clock */ REG_WRITE16(host, clk_ctrl, SDHCI_CLK_CTRL_REG); if (clock == 0u) return SDRV_STATUS_OK; /* * DDR TIMING need twice base frequency. */ if (clk != NULL) { if ((host->timing == SDHCI_EMMC_HS400_MODE) || (host->timing == SDHCI_EMMC_DDR52_MODE) || (host->timing == SDHCI_UHS_DDR50_MODE)) { if (sdrv_ckgen_set_rate(clk, MIN(clock, host->max_clk_rate) * 2)) return SDRV_STATUS_FAIL; } else { if (sdrv_ckgen_set_rate(clk, MIN(clock, host->max_clk_rate))) return SDRV_STATUS_FAIL; } } DETAIL_PRINTF(SSDK_INFO, "switch card clock to %d\r\n", MIN(clock, host->max_clk_rate)); clk_ctrl |= SDHCI_INT_CLK_EN; REG_WRITE16(host, clk_ctrl, SDHCI_CLK_CTRL_REG); /* Check for clock stable, timeout 150ms */ ret = sdrv_sdhci_wait_for_bit(host, SDHCI_CLK_CTRL_REG, SDHCI_CLK_STABLE, 0, 150); if (ret) { DETAIL_PRINTF(SSDK_CRIT, "Error: sdhci clock wait stable timeout!"); return ret; } clk_ctrl |= SDHCI_CLK_PLL_EN; REG_WRITE16(host, clk_ctrl, SDHCI_CLK_CTRL_REG); /* Check for clock stable, timeout 150ms */ ret = sdrv_sdhci_wait_for_bit(host, SDHCI_CLK_CTRL_REG, SDHCI_CLK_STABLE, 0, 150); if (ret) { DETAIL_PRINTF(SSDK_CRIT, "Error: sdhci clock wait stable timeout!"); return ret; } /* Now clock is stable, enable it */ clk_ctrl = REG_READ16(host, SDHCI_CLK_CTRL_REG); clk_ctrl |= SDHCI_CLK_EN; REG_WRITE16(host, clk_ctrl, SDHCI_CLK_CTRL_REG); host->cur_clk_rate = clock; return ret; } static inline status_t sdrv_sehc_dll_config(struct sdhci_host *host) { status_t ret = SDRV_STATUS_OK; uint16_t clk_ctrl = 0; uint32_t dll_ctrl = 0; DETAIL_PRINTF(SSDK_INFO, "sehc dll config!\r\n"); /* Disable the clock */ clk_ctrl = REG_READ16(host, SDHCI_CLK_CTRL_REG); clk_ctrl &= ~SDHCI_CLK_EN; REG_WRITE16(host, clk_ctrl, SDHCI_CLK_CTRL_REG); /* config dll_ctrl */ dll_ctrl = REG_READ32(host, SDHCI_DLL_CTRL); dll_ctrl |= SDHCI_DLL_EN; dll_ctrl &= ~(SDHCI_DLL_SLV_TARGET_MASK << SDHCI_DLL_SLV_TARGET_OFFSET); dll_ctrl |= (0x1f << SDHCI_DLL_SLV_TARGET_OFFSET); REG_WRITE32(host, dll_ctrl, SDHCI_DLL_CTRL); /* Enable the clock */ clk_ctrl |= SDHCI_CLK_EN; REG_WRITE16(host, clk_ctrl, SDHCI_CLK_CTRL_REG); ret = sdrv_sdhci_wait_for_bit(host, SDHCI_DLL_STATUS, SDHCI_DLL_REF_LOCK, 0, 200); if (ret) { DETAIL_PRINTF(SSDK_CRIT, "sehc dll timeout!\r\n"); return ret; } return ret; } static void sdrv_sehc_set_uhs_mode(struct sdhci_host *host, uint32_t mode) { sdrv_sdhci_set_uhs_mode(host, mode); #if CONFIG_E3L /* taishanL DDR50 mode need config DAT_OE_MASK */ if (mode == SDHCI_UHS_DDR50_MODE) { uint32_t oe_mask; oe_mask = REG_READ32(host, SDHCI_OE_MASK_SEL_REG); oe_mask &= ~SDHCI_DAT_OE_MASK_SEL; oe_mask |= 0x1 << SDHCI_DAT_OE_OFFSET; REG_WRITE32(host, oe_mask, SDHCI_OE_MASK_SEL_REG); } #endif /* HS400 mode need config dll frequency */ if (mode == SDHCI_EMMC_HS400_MODE) { if (sdrv_sehc_dll_config(host)) DETAIL_PRINTF(SSDK_CRIT, "sehc dll config failed!\r\n"); } return; } static bool sdrv_sehc_mmc_ending_trans(struct sdhci_host *host) { struct mmc_device *dev = host->parent; struct mmc_config_data *mmc_cfg = &dev->config; sdrv_scr_t *scr_ctr = mmc_cfg->scr_ctrl; scr_signal_t *scr_signal = mmc_cfg->scr_signal; if ((NULL == scr_ctr) || (NULL == scr_signal)) { DETAIL_PRINTF(SSDK_CRIT, "sehc ending trans check, not config scr_ctr || scr_signal!\r\n"); return true; } return (0x1 == scr_get(scr_ctr, scr_signal)); } static void sdrv_sehc_hw_reset(struct sdhci_host *host) { uint32_t emmc_ctrl; emmc_ctrl = REG_READ32(host, SDHCI_EMMC_CTRL_REG); emmc_ctrl &= ~SDHCI_RST_N; REG_WRITE32(host, emmc_ctrl, SDHCI_EMMC_CTRL_REG); udelay(5); emmc_ctrl |= SDHCI_RST_N; REG_WRITE32(host, emmc_ctrl, SDHCI_EMMC_CTRL_REG); } static status_t sdrv_sehc_tuning_sequence(struct sdhci_host *host, uint32_t opcode, uint32_t bus_width) { status_t ret = SDRV_STATUS_OK; uint32_t reg; struct mmc_command cmd; memset(&cmd, 0, sizeof(struct mmc_command)); cmd.cmd_index = opcode; cmd.argument = 0x0; cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL; cmd.resp_type = SDHCI_CMD_RESP_R1; cmd.trans_mode = SDHCI_MMC_READ; cmd.data_present = 0x0; cmd.data.data_ptr = NULL; cmd.data.num_blocks = 0x1; if (cmd.cmd_index == CMD21_SEND_TUNING_BLOCK && bus_width == MMC_DATA_BUS_WIDTH_8BIT) cmd.data.blk_sz = 128; else cmd.data.blk_sz = 64; REG_WRITE16(host, cmd.data.blk_sz, SDHCI_BLKSZ_REG); if (host->caps.spec_version >= SDHCI_SPEC_VER4_NUM) REG_WRITE32(host, cmd.data.num_blocks, SDHCI_SDMASA_BLKCNT_REG); else REG_WRITE16(host, cmd.data.num_blocks, SDHCI_BLK_CNT_REG); /* Write to transfer mode register */ REG_WRITE16(host, SDHCI_READ_MODE, SDHCI_TRANS_MODE_REG); for (int i = 0; i < SEHC_MAX_TUNING_LOOP; i++) { ret = sdrv_sdhci_send_command(host, &cmd); if (ret) { DETAIL_PRINTF(SSDK_CRIT, "sdhci send hw tuning cmd error!\r\n"); return ret; } /* wait for read buf ready, timeout 50ms */ ret = sdrv_sdhci_wait_for_bit(host, SDHCI_NRML_INT_STS_REG, SDHCI_INT_DATA_AVAIL, 0, 50); if (ret) { DETAIL_PRINTF(SSDK_CRIT, "sdhci tuning timeout!\r\n"); return ret; } reg = REG_READ16(host, SDHCI_HOST_CTRL2_REG); if (!(reg & SDHCI_EXEC_TUNING)) { /* check SDHCI_SAMPLE_CLK_SEL set,tuning is successful */ if (reg & SDHCI_SAMPLE_CLK_SEL) { DETAIL_PRINTF(SSDK_INFO, "sdhci: tuning cycle count = %d\r\n", i); if (i < SDHCI_HW_TUNING_MIN_COUNT) DETAIL_PRINTF(SSDK_CRIT, "SDHC: tuning cycle abnormal, num is %d!\r\n", i); return SDRV_STATUS_OK; } /* check FAIL_NUM_ > 0,also tuning is successful */ reg = REG_READ32(host, SDHCI_TUNING_STATUS_REG); if ((reg >> SDHCI_FAIL_NUM_OFFSET) & SDHCI_FAIL_NUM_MASK) { DETAIL_PRINTF(SSDK_INFO, "sdhci: tuning cycle count = %d\r\n", i); if (i < 40) DETAIL_PRINTF(SSDK_CRIT, "SDHC: tuning cycle abnormal, num is %d!\r\n", i); DETAIL_PRINTF(SSDK_INFO, "sdhci: tuning sw config override\r\n"); uint32_t fail_num = 0; uint32_t pass_num = 0; uint32_t override_val = 0; fail_num = (reg >> SDHCI_FAIL_NUM_OFFSET) & SDHCI_FAIL_NUM_MASK; pass_num = (reg >> SDHCI_PASS_NUM_OFFSET) & SDHCI_PASS_NUM_MASK; override_val = (fail_num + pass_num) / 2; /* set override */ reg = REG_READ32(host, SDHCI_TUNING_CTRL_REG); reg |= SDHCI_OVERRIDE_EN; reg &= ~(SDHCI_OVERRIDE_VAL_MASK << SDHCI_OVERRIDE_VAL_OFFSET); reg |= override_val << SDHCI_OVERRIDE_VAL_OFFSET; REG_WRITE32(host, reg, SDHCI_TUNING_CTRL_REG); /* set SAMPLE_CLK_SEL */ reg = REG_READ16(host, SDHCI_HOST_CTRL2_REG); reg |= SDHCI_SAMPLE_CLK_SEL; REG_WRITE16(host, reg, SDHCI_HOST_CTRL2_REG); return SDRV_STATUS_OK; } break; } } return SDRV_STATUS_MMC_TUNING_FAIL; } status_t sdrv_sehc_execute_tuning(struct sdhci_host *host, uint32_t opcode, uint32_t bus_width) { status_t ret = SDRV_STATUS_OK; uint32_t reg; /* reset the tuning circuit */ sdrv_sdhci_reset_tuning(host); /* set tuning_clk_stop_en */ reg = REG_READ32(host, SDHCI_TUNING_CTRL_REG); reg |= SDHCI_TUNING_CLK_STOP_EN; REG_WRITE32(host, reg, SDHCI_TUNING_CTRL_REG); /* start the tuning circuit */ sdrv_sdhci_start_tuning(host); host->tuning_in_progress = 1; udelay(1); /* disable SDHCI_INT_DATA_AVAIL interrupt */ reg = REG_READ16(host, SDHCI_NRML_INT_SIG_EN_REG); reg &= ~SDHCI_INT_DATA_AVAIL; REG_WRITE16(host, reg, SDHCI_NRML_INT_SIG_EN_REG); ret = sdrv_sehc_tuning_sequence(host, opcode, bus_width); if (ret) { DETAIL_PRINTF(SSDK_CRIT, "sdhci tuning failed, abort tuning state!\r\n"); sdrv_sdhci_abort_tuning(host); } /* clear SDHCI_INT_DATA_AVAIL */ REG_WRITE16(host, SDHCI_INT_DATA_AVAIL, SDHCI_NRML_INT_STS_REG); /* enable SDHCI_INT_DATA_AVAIL interrupt */ reg = REG_READ16(host, SDHCI_NRML_INT_SIG_EN_REG); reg |= SDHCI_INT_DATA_AVAIL; REG_WRITE16(host, reg, SDHCI_NRML_INT_SIG_EN_REG); /* clear tuning_clk_stop_en */ reg = REG_READ32(host, SDHCI_TUNING_CTRL_REG); reg &= ~SDHCI_TUNING_CLK_STOP_EN; REG_WRITE32(host, reg, SDHCI_TUNING_CTRL_REG); host->tuning_in_progress = 0; return ret; } static void sdrv_sehc_prepare_tuning(struct sdhci_host *host, uint32_t val) { uint32_t reg; uint16_t clk = 0; clk = REG_READ16(host, SDHCI_CLK_CTRL_REG); clk &= ~SDHCI_CLK_EN; REG_WRITE16(host, clk, SDHCI_CLK_CTRL_REG); reg = REG_READ32(host, SDHCI_TUNING_CTRL_REG); reg |= SDHCI_OVERRIDE_EN; reg &= ~(SDHCI_OVERRIDE_VAL_MASK << SDHCI_OVERRIDE_VAL_OFFSET); reg |= val << SDHCI_OVERRIDE_VAL_OFFSET; REG_WRITE32(host, reg, SDHCI_TUNING_CTRL_REG); clk = REG_READ16(host, SDHCI_CLK_CTRL_REG); clk |= SDHCI_CLK_EN; REG_WRITE16(host, clk, SDHCI_CLK_CTRL_REG); } __UNUSED static void sdrv_sehc_post_tuning(struct sdhci_host *host) { sdrv_sdhci_reset_tuning(host); } status_t sdrv_sehc_sw_execute_tuning(struct sdhci_host *host, uint32_t opcode, uint32_t bus_width) { status_t ret = SDRV_STATUS_OK; uint32_t min = 0; uint32_t max = 0; uint32_t avg = 0; uint32_t reg = 0; /* reset the tuning circuit */ sdrv_sdhci_reset_tuning(host); /* set tuning_clk_stop_en */ reg = REG_READ32(host, SDHCI_TUNING_CTRL_REG); reg |= SDHCI_TUNING_CLK_STOP_EN; REG_WRITE32(host, reg, SDHCI_TUNING_CTRL_REG); /* config the sample tuning circuit */ uint16_t ctrl2; ctrl2 = REG_READ16(host, SDHCI_HOST_CTRL2_REG); ctrl2 |= SDHCI_SAMPLE_CLK_SEL; REG_WRITE16(host, ctrl2, SDHCI_HOST_CTRL2_REG); host->sw_tuning_in_progress = 1; udelay(1); /* find the mininum delay first which can not pass tuning */ min = SEHC_TUNE_CTRL_MIN; #if (CONFIG_E3 || CONFIG_D3) if (IS_P0) min = SEHC_1_0_TUNE_CTRL_MIN; #endif while (min < SEHC_TUNE_CTRL_MAX) { sdrv_sehc_prepare_tuning(host, min); if (sdrv_mmc_send_tuning((struct mmc_device *)host->parent, opcode, bus_width)) break; min += SEHC_TUNE_CTRL_STEP; } DETAIL_PRINTF(SSDK_INFO, "sw tuning not pass tuning %d\r\n", min); /* find the mininum delay first which can pass tuning */ min = min + SEHC_TUNE_CTRL_STEP; SW_TUNING: while (min < SEHC_TUNE_CTRL_MAX) { sdrv_sehc_prepare_tuning(host, min); if (!sdrv_mmc_send_tuning((struct mmc_device *)host->parent, opcode, bus_width)) break; min += SEHC_TUNE_CTRL_STEP; } DETAIL_PRINTF(SSDK_INFO, "sw tuning pass tuning %d\r\n", min); /* find the mininum delay first which can not pass tuning */ max = min + SEHC_TUNE_CTRL_STEP; while (max < SEHC_TUNE_CTRL_MAX) { sdrv_sehc_prepare_tuning(host, max); if (sdrv_mmc_send_tuning((struct mmc_device *)host->parent, opcode, bus_width)) break; max += SEHC_TUNE_CTRL_STEP; } DETAIL_PRINTF(SSDK_INFO, "sw tuning not pass tuning %d\r\n", max); if (min >= SEHC_TUNE_CTRL_MAX) { ret = SDRV_STATUS_MMC_TUNING_FAIL; DETAIL_PRINTF(SSDK_CRIT, "sw tuning find pass window error\r\n"); goto out; } if ((max - min) > SEHC_TUNE_WINDOW_MIN) { avg = (min + max) / 2; DETAIL_PRINTF(SSDK_INFO, "sw tuning window %d ~ %d avg:%d\r\n", min, max, avg); sdrv_sehc_prepare_tuning(host, avg); ret = sdrv_mmc_send_tuning((struct mmc_device *)host->parent, opcode, bus_width); if (ret) { DETAIL_PRINTF(SSDK_CRIT, "sw tuning window %d ~ %d avg:%d, tuning cmd error\r\n", min, max, avg); goto out; } } else { min = max + SEHC_TUNE_CTRL_STEP; DETAIL_PRINTF(SSDK_INFO, "sw tuning window < 5,goto sw_tuning\r\n"); goto SW_TUNING; } out: /* clear tuning_clk_stop_en */ reg = REG_READ32(host, SDHCI_TUNING_CTRL_REG); reg &= ~SDHCI_TUNING_CLK_STOP_EN; REG_WRITE32(host, reg, SDHCI_TUNING_CTRL_REG); host->sw_tuning_in_progress = 0; return ret; } struct sdhci_ops sdhci_sehc_ops = { .hw_reset = sdrv_sehc_hw_reset, .set_clock = sdrv_sehc_set_clk, .set_uhs_mode = sdrv_sehc_set_uhs_mode, .mmc_ending_trans = sdrv_sehc_mmc_ending_trans, .platform_execute_tuning = sdrv_sehc_execute_tuning, }; status_t sdrv_mmc_platform_init(struct mmc_device *dev, void *priv_data) { status_t mmc_ret = SDRV_STATUS_OK; if (NULL == dev) { DETAIL_PRINTF(SSDK_CRIT, "\r\n %s: mmc_device parameter is null\r\n", __func__); return SDRV_STATUS_INVALID_PARAM ; } struct sdhci_host *host; struct mmc_config_data *mmc_cfg = &dev->config; sdrv_ckgen_node_t *clk = mmc_cfg->clk; struct mmc_sehc *sehc = priv_data; host = &dev->host; host->priv_data = sehc; host->ops = &sdhci_sehc_ops; host->parent = dev; #if (CONFIG_E3 || CONFIG_D3) if (IS_P0) host->ops->platform_execute_tuning = sdrv_sehc_sw_execute_tuning; #endif if (clk != NULL) { /* Init the ref clock: 400Khz */ if (sdrv_ckgen_set_rate(clk, 400000)) { DETAIL_PRINTF(SSDK_CRIT, "mmc set ref clock failed!\r\n"); return SDRV_STATUS_FAIL; } } mmc_ret = sdrv_mmc_sdrv_sdhci_init(dev); if (mmc_ret) { DETAIL_PRINTF(SSDK_CRIT, "mmc init failed!\r\n"); return mmc_ret; } return mmc_ret; }