コード例 #1
0
ファイル: omap_hsmmc.c プロジェクト: Philippe12/u-boot-sunxi
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;
}
コード例 #2
0
ファイル: mmc.c プロジェクト: CMNookTablet/acclaim_cyanoboot
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;
}