/* * Copyright (c) 2023, Artinchip Technology Co., Ltd * * SPDX-License-Identifier: Apache-2.0 * * Xiong Hao */ #include #include #include #include #include #include #include #include #include #include "sdmc.h" #define MAX_MMC_DEV_NUM 3 #define CONFIG_SYS_MMC_MAX_BLK_COUNT 300 #define be32_to_cpu(x) \ ((0x000000ff & ((x) >> 24)) | (0x0000ff00 & ((x) >> 8)) | \ (0x00ff0000 & ((x) << 8)) | (0xff000000 & ((x) << 24))) static void *mmc_dev[MAX_MMC_DEV_NUM]; static struct aic_sdmc_pdata sdmc_pdata[] = { #if defined(AIC_USING_SDMC0) { .id = 0, .base = SDMC0_BASE, .irq = SDMC0_IRQn, .clk = CLK_SDMC0, #if defined(AIC_SDMC0_BUSWIDTH8) .buswidth8 = 1, #endif .drv_phase = AIC_SDMC0_DRV_PHASE, .smp_phase = AIC_SDMC0_SMP_PHASE, }, #endif #if defined(AIC_USING_SDMC1) { .id = 1, .base = SDMC1_BASE, .irq = SDMC1_IRQn, .clk = CLK_SDMC1, #if defined(AIC_SDMC1_IS_SDIO) .is_sdio = 1, #endif .drv_phase = AIC_SDMC1_DRV_PHASE, .smp_phase = AIC_SDMC1_SMP_PHASE, }, #endif #if defined(AIC_USING_SDMC2) { .id = 2, .base = SDMC2_BASE, .irq = SDMC2_IRQn, .clk = CLK_SDMC2, #if defined(AIC_SDMC2_IS_SDIO) .is_sdio = 1, #endif .drv_phase = AIC_SDMC2_DRV_PHASE, .smp_phase = AIC_SDMC2_SMP_PHASE, }, #endif }; static inline u32 GET_BITS(u32 *resp, u32 start, u32 size) { const s32 __size = size; const u32 __mask = (__size < 32 ? 1 << __size : 0) - 1; const s32 __off = 3 - ((start) / 32); const s32 __shft = (start) & 31; u32 __res; __res = resp[__off] >> __shft; if (__size + __shft > 32) __res |= resp[__off-1] << ((32 - __shft) % 32); return __res & __mask; } static void mmc_trace_before_send(struct aic_sdmc_cmd *cmd) { #ifdef SDMC_DUMP_CMD printf("CMD_SEND: %d\n", cmd->cmd_code); printf("\t\tARG\t\t\t 0x%08x\n", cmd->arg); #endif } static void mmc_trace_after_send(struct aic_sdmc_cmd *cmd) { #ifdef SDMC_DUMP_CMD int i; u8 *ptr; switch (cmd->resp_type) { case MMC_RSP_NONE: printf("\t\tRSP_NONE\n\n"); break; case MMC_RSP_R1: printf("\t\tRSP_R1,5,6,7 \t\t 0x%08x \n", cmd->resp[0]); break; case MMC_RSP_R1b: printf("\t\tRSP_R1B\t\t 0x%08x \n", cmd->resp[0]); break; case MMC_RSP_R2: printf("\t\tRSP_R2\t\t\t 0x%08x \n", cmd->resp[0]); printf("\t\t \t\t 0x%08x \n", cmd->resp[1]); printf("\t\t \t\t 0x%08x \n", cmd->resp[2]); printf("\t\t \t\t 0x%08x \n", cmd->resp[3]); printf("\n"); printf("\t\t\t\t\tDUMPING DATA\n\n"); for (i = 0; i < 4; i++) { int j; printf("\t\t\t\t\t%03d - ", i*4); ptr = (u8 *)&cmd->resp[i]; ptr += 3; for (j = 0; j < 4; j++) printf("%02x ", *ptr--); printf("\n"); } break; case MMC_RSP_R3: printf("\t\tRSP_R3,4\t\t 0x%08x \n", cmd->resp[0]); break; default: printf("\t\tERROR MMCSD rsp not supported 0x%x\n", cmd->resp_type); break; } #endif } int mmc_send_cmd(struct aic_sdmc *host, struct aic_sdmc_cmd *cmd, struct aic_sdmc_data *data) { memset(cmd->resp, 0, sizeof(cmd->resp)); mmc_trace_before_send(cmd); aic_sdmc_request(host, cmd, data); mmc_trace_after_send(cmd); return cmd->err; } static int mmc_go_idle(struct aic_sdmc *host) { struct aic_sdmc_cmd cmd = {0}; int err; memset(&cmd, 0, sizeof(struct aic_sdmc_cmd)); cmd.cmd_code = MMC_CMD_GO_IDLE_STATE; cmd.resp_type = MMC_RSP_NONE; cmd.arg = 0; cmd.flags = 0; err = mmc_send_cmd(host, &cmd, NULL); if (err) return err; aicos_mdelay(1); return 0; } static int sd_send_op_cond(struct aic_sdmc *host) { struct aic_sdmc_cmd cmd = {0}; int err, timeout = 1000; do { cmd.cmd_code = MMC_CMD_APP_CMD; cmd.resp_type = MMC_RSP_R1; cmd.arg = 0; cmd.flags = 0; err = mmc_send_cmd(host, &cmd, NULL); if (err) return err; cmd.cmd_code = SD_CMD_APP_SEND_OP_COND; cmd.resp_type = MMC_RSP_R3; /* * Most cards do not answer if some reserved bits * in the ocr are set. However, Some controller * can set bit 7 (reserved for low voltages), but * how to manage low voltages SD card is not yet * specified. */ cmd.arg = (host->dev->voltages & 0xff8000); if (host->dev->version == SD_VERSION_2) cmd.arg |= OCR_HCS; err = mmc_send_cmd(host, &cmd, NULL); if (err) return err; aicos_mdelay(1); } while ((!(cmd.resp[0] & OCR_BUSY)) && timeout--); if (timeout <= 0) return -1; if (host->dev->version != SD_VERSION_2) host->dev->version = SD_VERSION_1_0; host->dev->valid_ocr = cmd.resp[0]; host->dev->high_capacity = ((host->dev->valid_ocr & OCR_HCS) == OCR_HCS); host->dev->rca = 0; return 0; } static int mmc_send_op_cond(struct aic_sdmc *host) { struct aic_sdmc_cmd cmd = {0}; int err, timeout = 1000; /* Some cards seem to need this */ mmc_go_idle(host); /* CMD1: Asking to the card its capabilities */ cmd.cmd_code = MMC_CMD_SEND_OP_COND; cmd.resp_type = MMC_RSP_R3; cmd.arg = 0; cmd.flags = 0; err = mmc_send_cmd(host, &cmd, NULL); if (err) return err; aicos_mdelay(1); do { cmd.cmd_code = MMC_CMD_SEND_OP_COND; cmd.resp_type = MMC_RSP_R3; cmd.arg = ((host->dev->voltages & (cmd.resp[0] & OCR_VOLTAGE_MASK)) | (cmd.resp[0] & OCR_ACCESS_MODE)); if (host->dev->host_caps & MMC_MODE_HC) cmd.arg |= OCR_HCS; cmd.flags = 0; err = mmc_send_cmd(host, &cmd, NULL); if (err) return err; aicos_mdelay(1); } while ((!(cmd.resp[0] & OCR_BUSY)) && timeout--); if (timeout <= 0) return -1; host->dev->version = MMC_VERSION_UNKNOWN; host->dev->valid_ocr = cmd.resp[0]; host->dev->high_capacity = ((host->dev->valid_ocr & OCR_HCS) == OCR_HCS); host->dev->rca = 1; return 0; } static int mmc_send_ext_csd(struct aic_sdmc *host, u8 *ext_csd) { struct aic_sdmc_cmd cmd = {0}; struct aic_sdmc_data data = {0}; int err; cmd.cmd_code = MMC_CMD_SEND_EXT_CSD; cmd.resp_type = MMC_RSP_R1; cmd.arg = 0; cmd.flags = 0; data.buf = ext_csd; data.blks = 1; data.blksize = 512; data.flags = MMC_DATA_READ; err = mmc_send_cmd(host, &cmd, &data); return err; } static int mmc_get_capabilities(struct aic_sdmc *host, u8 *ext_csd) { host->dev->card_caps = 0; /* Only version 4 supports high-speed */ if (host->dev->version < MMC_VERSION_4) return 0; /* Default is 4-line mode */ host->dev->card_caps |= MMC_MODE_4BIT; host->dev->card_caps |= MMC_MODE_HS; return 0; } static int sd_switch(struct aic_sdmc *host, int mode, int group, u8 value, u8 *resp) { struct aic_sdmc_cmd cmd = {0}; struct aic_sdmc_data data = {0}; /* Switch the frequency */ cmd.cmd_code = SD_CMD_SWITCH_FUNC; cmd.resp_type = MMC_RSP_R1; cmd.arg = (mode << 31) | 0xffffff; cmd.arg &= ~(0xf << (group * 4)); cmd.arg |= value << (group * 4); data.buf = resp; data.blksize = 64; data.blks = 1; data.flags = MMC_DATA_READ; return mmc_send_cmd(host, &cmd, &data); } static int sd_get_capabilities(struct aic_sdmc *host) { struct aic_sdmc_cmd cmd = {0}; struct aic_sdmc_data data = {0}; ALLOC_CACHE_ALIGN_BUFFER(u32, scr, 16); ALLOC_CACHE_ALIGN_BUFFER(u32, switch_status, 16); int err, timeout; host->dev->card_caps = 0; /* Read the SCR to find out if this card supports higher speeds */ cmd.cmd_code = MMC_CMD_APP_CMD; cmd.resp_type = MMC_RSP_R1; cmd.arg = host->dev->rca << 16; cmd.flags = 0; err = mmc_send_cmd(host, &cmd, NULL); if (err) return err; cmd.cmd_code = SD_CMD_APP_SEND_SCR; cmd.resp_type = MMC_RSP_R1; cmd.arg = 0; cmd.flags = 0; timeout = 3; retry_scr: data.buf = (u8 *)scr; data.blksize = 8; data.blks = 1; data.flags = MMC_DATA_READ; err = mmc_send_cmd(host, &cmd, &data); if (err) { if (timeout--) goto retry_scr; return err; } host->dev->scr[0] = be32_to_cpu(scr[0]); host->dev->scr[1] = be32_to_cpu(scr[1]); switch ((host->dev->scr[0] >> 24) & 0xf) { case 0: host->dev->version = SD_VERSION_1_0; pr_debug("SD Ver 1.0\n"); break; case 1: host->dev->version = SD_VERSION_1_10; pr_debug("SD Ver 1.1\n"); break; case 2: host->dev->version = SD_VERSION_2; pr_debug("SD Ver 2.0\n"); break; default: host->dev->version = SD_VERSION_1_0; pr_debug("SD Ver 1.0\n"); break; } if (host->dev->version < MMC_VERSION_4) return 0; /* Default is 4-line mode */ if (host->dev->scr[0] & SD_DATA_4BIT) { host->dev->card_caps |= MMC_MODE_4BIT; pr_debug("Card caps 4 bit\n"); } /* Version 1.0 doesn't support switching */ if (host->dev->version == SD_VERSION_1_0) return 0; timeout = 4; while (timeout--) { err = sd_switch(host, SD_SWITCH_CHECK, 0, 1, (u8 *)switch_status); if (err) return err; /* The high-speed function is busy. Try again */ if (!(be32_to_cpu(switch_status[7]) & SD_HIGHSPEED_BUSY)) break; } /* If high-speed isn't supported, we return */ if (be32_to_cpu(switch_status[3]) & SD_HIGHSPEED_SUPPORTED) host->dev->card_caps |= MMC_MODE_HS; return 0; } static int sd_set_card_speed(struct aic_sdmc *host, u32 hs) { int err; ALLOC_CACHE_ALIGN_BUFFER(uint, switch_status, 16); /* SD version 1.00 and 1.01 does not support CMD 6 */ if (host->dev->version == SD_VERSION_1_0) return 0; err = sd_switch(host, SD_SWITCH_SWITCH, 0, hs, (u8 *)switch_status); if (err) return err; if (((be32_to_cpu(switch_status[4]) >> 24) & 0xF) != hs) return -1; return 0; } static int sd_select_bus_width(struct aic_sdmc *host, int w) { int err; struct aic_sdmc_cmd cmd = {0}; if ((w != 4) && (w != 1)) return -EINVAL; cmd.cmd_code = MMC_CMD_APP_CMD; cmd.resp_type = MMC_RSP_R1; cmd.arg = host->dev->rca << 16; err = mmc_send_cmd(host, &cmd, NULL); if (err) return err; cmd.cmd_code = SD_CMD_APP_SET_BUS_WIDTH; cmd.resp_type = MMC_RSP_R1; if (w == 4) cmd.arg = 2; else if (w == 1) cmd.arg = 0; err = mmc_send_cmd(host, &cmd, NULL); if (err) return err; return 0; } static void mmc_update_version(struct aic_sdmc *host, int version) { switch (version) { case 0: host->dev->version = MMC_VERSION_1_2; break; case 1: host->dev->version = MMC_VERSION_1_4; break; case 2: host->dev->version = MMC_VERSION_2_2; break; case 3: host->dev->version = MMC_VERSION_3; break; case 4: host->dev->version = MMC_VERSION_4; break; default: host->dev->version = MMC_VERSION_1_2; break; } } static int mmc_get_csd(struct aic_sdmc *host) { struct aic_sdmc_cmd cmd = {0}; int err = 0; u32 csd_ver = 0; /* CMD9 - Get the Card-Specific Data */ cmd.cmd_code = MMC_CMD_SEND_CSD; cmd.resp_type = MMC_RSP_R2; cmd.arg = host->dev->rca << 16; cmd.flags = 0; err = mmc_send_cmd(host, &cmd, NULL); if (err) return err; if (host->dev->version == MMC_VERSION_UNKNOWN) mmc_update_version(host, (cmd.resp[0] >> 26) & 0xf); host->dev->read_bl_len = 512; if (host->index) { csd_ver = GET_BITS(cmd.resp, 126, 2); switch (csd_ver) { case 0: host->dev->card_capacity = (GET_BITS(cmd.resp, 62, 12) + 1) << (GET_BITS(cmd.resp, 47, 3) + 2); host->dev->card_capacity *= GET_BITS(cmd.resp, 80, 4); host->dev->card_capacity >>= 10; /* unit:KB */ break; case 1: host->dev->card_capacity = (GET_BITS(cmd.resp, 48, 22) + 1) * 512; /* unit:KB */ break; default: pr_err("unrecognised CSD structure version %d!", csd_ver); break; } printf("SD card capacity %d KB.\n", host->dev->card_capacity); } return 0; } static int mmc_go_transfer_mode(struct aic_sdmc *host) { struct aic_sdmc_cmd cmd = {0}; int err = 0; /* CMD7 - Select the card, and put it into Transfer Mode */ cmd.cmd_code = MMC_CMD_SELECT_CARD; cmd.resp_type = MMC_RSP_R1b; cmd.arg = host->dev->rca << 16; err = mmc_send_cmd(host, &cmd, NULL); return err; } static int sd_startup(struct aic_sdmc *host) { s32 err; err = sd_get_capabilities(host); if (err != 0) return err; if (host->dev->card_caps & MMC_MODE_4BIT) { host->dev->bus_width = 4; sd_select_bus_width(host, 4); aic_sdmc_set_cfg(host); } if (host->dev->card_caps & MMC_MODE_HS) { sd_set_card_speed(host, 1); host->dev->clock = 50000000; } else { sd_set_card_speed(host, 0); host->dev->clock = 25000000; } aic_sdmc_set_cfg(host); return 0; } static int emmc_startup(struct aic_sdmc *host) { s32 err; u8 ext_csd[512] = {0}; if (host->dev->version >= MMC_VERSION_4) { /* check ext_csd version and capacity */ err = mmc_send_ext_csd(host, ext_csd); /* update mmcdev version */ switch (ext_csd[192]) { case 0: host->dev->version = MMC_VERSION_4; break; case 1: host->dev->version = MMC_VERSION_4_1; break; case 2: host->dev->version = MMC_VERSION_4_2; break; case 3: host->dev->version = MMC_VERSION_4_3; break; case 5: host->dev->version = MMC_VERSION_4_41; break; case 6: host->dev->version = MMC_VERSION_4_5; break; case 7: host->dev->version = MMC_VERSION_5_0; break; case 8: host->dev->version = MMC_VERSION_5_1; break; } /* Check Read only ext_csd[160] whether support partition. */ if (ext_csd[160] & PART_SUPPORT) host->dev->part_config = ext_csd[179]; } err = mmc_get_capabilities(host, ext_csd); if (err != 0) return err; /* Restrict card's capabilities by what the host can do */ host->dev->card_caps &= host->dev->host_caps; if (host->dev->card_caps & MMC_MODE_4BIT) { /* Set the card to use 4 bit*/ host->dev->bus_width = 4; aic_sdmc_set_cfg(host); } else if (host->dev->card_caps & MMC_MODE_8BIT) { /* Set the card to use 8 bit*/ host->dev->bus_width = 8; aic_sdmc_set_cfg(host); } if (host->dev->card_caps & MMC_MODE_HS) { if (host->dev->card_caps & MMC_MODE_HS_52MHz) host->dev->clock = 52000000; else host->dev->clock = 26000000; } else { /* MMC Legacy */ host->dev->clock = 25000000; } aic_sdmc_set_cfg(host); return 0; } static int mmc_go_identify_mode(struct aic_sdmc *host) { struct aic_sdmc_cmd cmd = {0}; int err = 0; /* CMD2 - Put the Card in Identify Mode */ cmd.cmd_code = MMC_CMD_ALL_SEND_CID; /* cmd not supported in spi */ cmd.resp_type = MMC_RSP_R2; cmd.arg = 0; cmd.flags = 0; err = mmc_send_cmd(host, &cmd, NULL); return err; } static s32 mmc_relative_addr(struct aic_sdmc *host) { struct aic_sdmc_cmd cmd = {0}; int err = 0; /* * CMD3 - For MMC cards, set the Relative Address. * For SD cards, get the Relative Address. * This also puts the cards into Standby State */ cmd.cmd_code = SD_CMD_SEND_RELATIVE_ADDR; /* cmd not supported in spi */ cmd.resp_type = MMC_RSP_R6; cmd.arg = host->dev->rca << 16; cmd.flags = 0; err = mmc_send_cmd(host, &cmd, NULL); if (IS_SD(host)) host->dev->rca = (cmd.resp[0] >> 16) & 0xffff; return err; } static int mmc_startup(struct aic_sdmc *host) { int err = 0; /* Get Card-Specific-Data and update parameters */ err = mmc_get_csd(host); if (err) return err; err = mmc_go_transfer_mode(host); if (err) return err; host->dev->part_config = MMCPART_NOAVAILABLE; host->dev->boot_bus_cond = MMCPART_NOAVAILABLE; if (IS_SD(host)) err = sd_startup(host); else err = emmc_startup(host); if (err) return err; return 0; } static int mmc_send_if_cond(struct aic_sdmc *host) { struct aic_sdmc_cmd cmd = {0}; int err; cmd.cmd_code = SD_CMD_SEND_IF_COND; /* We set the bit if the host supports voltages between 2.7 and 3.6 V */ cmd.arg = ((host->dev->voltages & 0xff8000) != 0) << 8 | 0xaa; cmd.resp_type = MMC_RSP_R7; cmd.flags = 0; err = mmc_send_cmd(host, &cmd, NULL); if (err) { pr_err("snd cmd failed.\n"); return err; } /* * 0xaa is 8bit "check pattern", if the card is SD v2.0 or later, it will * echo the check pattern value. */ if ((cmd.resp[0] & 0xff) != 0xaa) { pr_err("resp failed(%d).\n", cmd.resp[0]); return -1; } host->dev->version = SD_VERSION_2; return 0; } u32 mmc_read_blocks(struct aic_sdmc *host, void *dst, u32 start, u32 blkcnt) { struct aic_sdmc_cmd cmd = {0}; struct aic_sdmc_data data = {0}; int err; memset(&cmd, 0, sizeof(struct aic_sdmc_cmd)); memset(&data, 0, sizeof(struct aic_sdmc_data)); /* Change for send stop cmd manually */ if (blkcnt > 1) { cmd.cmd_code = MMC_CMD_READ_MULTIPLE_BLOCK; cmd.auto_stop_flag = 0; } else { cmd.cmd_code = MMC_CMD_READ_SINGLE_BLOCK; cmd.auto_stop_flag = 0; } if (host->dev->high_capacity) cmd.arg = start; else cmd.arg = start * host->dev->read_bl_len; cmd.resp_type = MMC_RSP_R1; cmd.flags = 0; data.buf = dst; data.blks = blkcnt; data.blksize = host->dev->read_bl_len; data.flags = MMC_DATA_READ; /* * Change for send stop cmd manually conditions * Cmd 18 should be couple used with cmd 12 * 1.Response error(CRC error;timeout); * 2.Data timeout; * 3.Data error; * 4.Transfer complete normally */ err = mmc_send_cmd(host, &cmd, &data); if (err) { pr_err("Send cmd %d error = %d\n", cmd.cmd_code, err); return 0; } if ((cmd.cmd_code == MMC_CMD_READ_MULTIPLE_BLOCK) && !(cmd.auto_stop_flag)) { cmd.cmd_code = MMC_CMD_STOP_TRANSMISSION; cmd.resp_type = MMC_RSP_R1b; cmd.arg = 0; cmd.flags = 0; if (mmc_send_cmd(host, &cmd, NULL)) { pr_err("Failed to stop multi-block read. err -%d\n", cmd.err); return 0; } } if (cmd.err || data.err) { printf("read blocks failed, %d, %d, 0x%08x, 0x%08x\n", cmd.err, data.err, data.flags, data.blksize); return 0; } return blkcnt; } u32 mmc_bread(void *priv, u32 start, u32 blkcnt, u8 *dst) { struct aic_sdmc *host = (struct aic_sdmc *)priv; u32 cur, blk_todo = blkcnt; if (blkcnt == 0) return 0; do { if (blk_todo > host->dev->blk_max) cur = host->dev->blk_max; else cur = blk_todo; if (mmc_read_blocks(host, dst, start, cur) != cur) return 0; blk_todo -= cur; start += cur; dst += cur * host->dev->read_bl_len; } while (blk_todo > 0); return blkcnt; } u32 mmc_write_blocks(struct aic_sdmc *host, const u8 *src, u32 start, u32 blkcnt) { struct aic_sdmc_cmd cmd = {0}; struct aic_sdmc_data data = {0}; if (blkcnt > 1) cmd.cmd_code = MMC_CMD_WRITE_MULTIPLE_BLOCK; else cmd.cmd_code = MMC_CMD_WRITE_SINGLE_BLOCK; if (host->dev->high_capacity) cmd.arg = start; else cmd.arg = start * host->dev->read_bl_len; cmd.resp_type = MMC_RSP_R1; cmd.flags = 0; data.buf = (u8 *)src; data.blks = blkcnt; data.blksize = host->dev->read_bl_len; data.flags = MMC_DATA_WRITE; if (mmc_send_cmd(host, &cmd, &data)) { pr_err("write blocks failed, error = -%d\n", -cmd.err); return 0; } if (cmd.cmd_code == MMC_CMD_WRITE_MULTIPLE_BLOCK) { cmd.cmd_code = MMC_CMD_STOP_TRANSMISSION; cmd.resp_type = MMC_RSP_R1b; cmd.arg = 0; cmd.flags = 0; if (mmc_send_cmd(host, &cmd, NULL)) { pr_err("Failed to stop mulit-block write. err -%d\n", -cmd.err); return 0; } } return blkcnt; } u32 mmc_bwrite(struct aic_sdmc *host, u32 start, u32 blkcnt, const u8 *src) { u32 cur, blocks_todo = blkcnt; if (blkcnt == 0) return 0; do { if (blocks_todo > host->dev->blk_max) cur = host->dev->blk_max; else cur = blocks_todo; if (mmc_write_blocks(host, src, start, cur) != cur) return 0; blocks_todo -= cur; start += cur; src += cur * host->dev->read_bl_len; } while (blocks_todo > 0); return blkcnt; } void mmc_setup_cfg(struct aic_sdmc *host) { host->dev->freq_min = SDMC_CLOCK_MIN; host->dev->freq_max = SDMC_CLOCK_MAX; host->dev->host_caps = MMC_MODE_HC; host->dev->valid_ocr = MMC_VDD_32_33 | MMC_VDD_33_34; host->dev->voltages = MMC_VDD_29_30 | MMC_VDD_30_31 | MMC_VDD_31_32 | MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_34_35 | MMC_VDD_35_36; host->dev->flags = EXT_CSD_BUS_WIDTH_4 | EXT_CSD_SUP_SDIO_IRQ | EXT_CSD_SUP_HIGHSPEED | EXT_CSD_MUTBLKWRITE; if (host->pdata->buswidth8) host->dev->flags |= EXT_CSD_BUS_WIDTH_8; host->dev->max_seg_size = 4096; host->dev->max_dma_segs = 256; host->dev->max_blk_size = 512; host->dev->max_blk_count = 65535; host->dev->blk_max = CONFIG_SYS_MMC_MAX_BLK_COUNT; } static int mmc_identification(struct aic_sdmc *host) { int err = 0; /* CMD0 - Reset the Card */ err = mmc_go_idle(host); if (err) { pr_err("CMD0 failed, no card.\n"); return err; } /* Trying SDMC for eMMC: First try eMMC, if it is failed, then try SD Card */ if (host->index == 0) { // Try eMMC err = mmc_send_op_cond(host); if (err) { /* * CMD8 - SD_CMD_SEND_IF_COND * Test for SD version 2 or later */ mmc_send_if_cond(host); /* * ACMD41 - SD_CMD_APP_SEND_OP_COND * Now try to get the SD card's operating condition */ err = sd_send_op_cond(host); // Spend about 0.3 ms } if (err) { pr_err("Unknown card type.\n"); return err; } /* Trying SDMC for SD: First try SD Card, if it is failed, then try eMMC */ } else { // Try SD Card /* CMD8 - SD_CMD_SEND_IF_COND, Test for SD version 2 or later */ mmc_send_if_cond(host); /* * ACMD41 - SD_CMD_APP_SEND_OP_COND, Now try to get the SD card's operating * condition */ err = sd_send_op_cond(host); // Spend about 0.3 ms if (err) { /* The card is not SD,then check if it is eMMC */ err = mmc_send_op_cond(host); if (err) { pr_err("Card did not respond to voltage select!\n"); return -1; } } } /* CMD2 - Put the Card in Identify Mode */ err = mmc_go_identify_mode(host); if (err) { pr_err("CMD2 failed.\n"); return err; } err = mmc_relative_addr(host); return err; } struct aic_sdmc *find_mmc_dev_by_index(int id) { int i; for (i = 0; i < MAX_MMC_DEV_NUM; i++) { if (mmc_dev[i] && ((struct aic_sdmc *)mmc_dev[i])->index == id) return mmc_dev[i]; } return NULL; } s32 mmc_init(int id) { struct aic_sdmc *host = NULL; struct aic_sdmc_pdata *pdata = NULL; struct aic_sdmc_dev *dev = NULL; int i, ret; if (id < 0 || id > MAX_MMC_DEV_NUM - 1) { pr_err("Invalid SDMC ID %d\n", id); return -1; } if (mmc_dev[id]) { pr_info("SDMC%d was already inited\n", id); return 0; } host = malloc(sizeof(struct aic_sdmc)); if (!host) { pr_err("Failed to malloc(%d)\n", (u32)sizeof(struct aic_sdmc)); return -1; } memset(host, 0, sizeof(struct aic_sdmc)); dev = malloc(sizeof(struct aic_sdmc_dev)); if (dev == NULL) { pr_err("malloc dev failed.\n"); goto out; } memset(dev, 0, sizeof(struct aic_sdmc_dev)); for (i = 0; i < ARRAY_SIZE(sdmc_pdata); i++) { if (sdmc_pdata[i].id == id) { pdata = &sdmc_pdata[i]; break; } } if (pdata == NULL) goto out; host->index = pdata->id; host->irq = pdata->irq; host->clk = pdata->clk; host->host.base = (volatile void *)pdata->base; host->pdata = pdata; host->dev = dev; mmc_dev[id] = host; ret = aic_sdmc_clk_init(host); if (ret) goto out; aicos_request_irq(host->irq, aic_sdmc_irq, 0, NULL, host); host->host.fifoth_val = MSIZE(2) | RX_WMARK(7) | TX_WMARK(8); host->host.is_sdio = pdata->is_sdio; mmc_setup_cfg(host); aic_sdmc_init(host); pr_info("SDMC%d driver loaded\n", pdata->id); ret = mmc_identification(host); if (ret) goto out; ret = mmc_startup(host); if (ret) goto out; return 0; out: if (host) { free(host); mmc_dev[id] = NULL; } if (dev) free(dev); return -1; } s32 mmc_deinit(int id) { struct aic_sdmc *p = (struct aic_sdmc *)mmc_dev[id]; if (id < 0 || id > MAX_MMC_DEV_NUM - 1) { pr_err("Invalid SDMC ID %d\n", id); return -1; } if (p == NULL) { pr_info("SDMC%d was already deinited\n", id); return 0; } if (p->dev) free(p->dev); if (p) { free(p); mmc_dev[id] = NULL; } return 0; }