static int omap_hsmmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) { struct hsmmc *mmc_base; unsigned int flags, mmc_stat; ulong start; mmc_base = ((struct omap_hsmmc_data *)mmc->priv)->base_addr; start = get_timer(0); while ((readl(&mmc_base->pstate) & (DATI_MASK | CMDI_MASK)) != 0) { if (get_timer(0) - start > MAX_RETRY_MS) { printf("%s: timedout waiting on cmd inhibit to clear\n", __func__); return -ETIMEDOUT; } } writel(0xFFFFFFFF, &mmc_base->stat); start = get_timer(0); while (readl(&mmc_base->stat)) { if (get_timer(0) - start > MAX_RETRY_MS) { printf("%s: timedout waiting for STAT (%x) to clear\n", __func__, readl(&mmc_base->stat)); return -ETIMEDOUT; } } /* * CMDREG * CMDIDX[13:8] : Command index * DATAPRNT[5] : Data Present Select * ENCMDIDX[4] : Command Index Check Enable * ENCMDCRC[3] : Command CRC Check Enable * RSPTYP[1:0] * 00 = No Response * 01 = Length 136 * 10 = Length 48 * 11 = Length 48 Check busy after response */ /* Delay added before checking the status of frq change * retry not supported by mmc.c(core file) */ if (cmd->cmdidx == SD_CMD_APP_SEND_SCR) udelay(50000); /* wait 50 ms */ if (!(cmd->resp_type & MMC_RSP_PRESENT)) flags = 0; else if (cmd->resp_type & MMC_RSP_136) flags = RSP_TYPE_LGHT136 | CICE_NOCHECK; else if (cmd->resp_type & MMC_RSP_BUSY) flags = RSP_TYPE_LGHT48B; else flags = RSP_TYPE_LGHT48; /* enable default flags */ flags = flags | (CMD_TYPE_NORMAL | CICE_NOCHECK | CCCE_NOCHECK | MSBS_SGLEBLK | ACEN_DISABLE | BCE_DISABLE | DE_DISABLE); if (cmd->resp_type & MMC_RSP_CRC) flags |= CCCE_CHECK; if (cmd->resp_type & MMC_RSP_OPCODE) flags |= CICE_CHECK; if (data) { if ((cmd->cmdidx == MMC_CMD_READ_MULTIPLE_BLOCK) || (cmd->cmdidx == MMC_CMD_WRITE_MULTIPLE_BLOCK)) { flags |= (MSBS_MULTIBLK | BCE_ENABLE); data->blocksize = 512; writel(data->blocksize | (data->blocks << 16), &mmc_base->blk); } else writel(data->blocksize | NBLK_STPCNT, &mmc_base->blk); if (data->flags & MMC_DATA_READ) flags |= (DP_DATA | DDIR_READ); else flags |= (DP_DATA | DDIR_WRITE); } writel(cmd->cmdarg, &mmc_base->arg); udelay(20); /* To fix "No status update" error on eMMC */ writel((cmd->cmdidx << 24) | flags, &mmc_base->cmd); start = get_timer(0); do { mmc_stat = readl(&mmc_base->stat); if (get_timer(0) - start > MAX_RETRY_MS) { printf("%s : timeout: No status update\n", __func__); return -ETIMEDOUT; } } while (!mmc_stat); if ((mmc_stat & IE_CTO) != 0) { mmc_reset_controller_fsm(mmc_base, SYSCTL_SRC); return -ETIMEDOUT; } else if ((mmc_stat & ERRI_MASK) != 0) return -1; if (mmc_stat & CC_MASK) { writel(CC_MASK, &mmc_base->stat); if (cmd->resp_type & MMC_RSP_PRESENT) { if (cmd->resp_type & MMC_RSP_136) { /* response type 2 */ cmd->response[3] = readl(&mmc_base->rsp10); cmd->response[2] = readl(&mmc_base->rsp32); cmd->response[1] = readl(&mmc_base->rsp54); cmd->response[0] = readl(&mmc_base->rsp76); } else /* response types 1, 1b, 3, 4, 5, 6 */ cmd->response[0] = readl(&mmc_base->rsp10); } } if (data && (data->flags & MMC_DATA_READ)) { mmc_read_data(mmc_base, data->dest, data->blocksize * data->blocks); } else if (data && (data->flags & MMC_DATA_WRITE)) { mmc_write_data(mmc_base, data->src, data->blocksize * data->blocks); } return 0; }
unsigned char omap_mmc_write_sect(unsigned int *input_buf, unsigned int num_bytes, mmc_controller_data *mmc_cont_cur, mmc_card_data *mmc_c, unsigned long start_sec) { unsigned char err; unsigned int argument; unsigned int resp[4]; unsigned int num_sec_val = (num_bytes + (MMCSD_SECTOR_SIZE - 1)) / MMCSD_SECTOR_SIZE; unsigned int sec_inc_val; unsigned int blk_cnt_current_tns; int r; if (num_sec_val == 0) { printf("mmc write: Invalid size\n"); return 1; } if (mmc_c->mode == SECTOR_MODE) { argument = start_sec; sec_inc_val = 1; } else { argument = start_sec * MMCSD_SECTOR_SIZE; sec_inc_val = MMCSD_SECTOR_SIZE; } while (num_sec_val) { if (num_sec_val > 0xFFFF) /* Max number of blocks per cmd */ blk_cnt_current_tns = 0xFFFF; else blk_cnt_current_tns = num_sec_val; /* check for Multi Block */ if (blk_cnt_current_tns > 1) { #if !defined(CONFIG_4430PANDA) err = mmc_send_cmd(mmc_cont_cur->base, MMC_CMD23, blk_cnt_current_tns, resp); if (err != 1) return err; #endif OMAP_HSMMC_BLK(mmc_cont_cur->base) = BLEN_512BYTESLEN | (blk_cnt_current_tns << 16); err = mmc_send_cmd(mmc_cont_cur->base, MMC_CMD25, argument, resp); if (err != 1) return err; } else { err = mmc_send_cmd(mmc_cont_cur->base, MMC_CMD24, argument, resp); if (err != 1) return err; } r = mmc_write_data(mmc_cont_cur->base, input_buf); if (r < 0) return 1; blk_cnt_current_tns = r; #if defined(CONFIG_4430PANDA) if (blk_cnt_current_tns > 1) { err = mmc_send_cmd(mmc_cont_cur->base, MMC_CMD12, 0, resp); if (err != 1) { printf("MMC_CMD12 failed 0x%x\n", err); return err; } } #endif input_buf += (MMCSD_SECTOR_SIZE / 4) * blk_cnt_current_tns; argument += sec_inc_val * blk_cnt_current_tns; num_sec_val -= blk_cnt_current_tns; } return 1; }