int mmc_send_status(struct mmc *mmc, int timeout)
{
	struct mmc_cmd cmd;
	int err;

	cmd.cmdidx = MMC_CMD_SEND_STATUS;
	cmd.resp_type = MMC_RSP_R1;
	cmd.cmdarg = mmc->rca << 16;
	cmd.flags = 0;

	do {
		err = mmc_send_cmd(mmc, &cmd, NULL);
		if (err)
			return err;
		else if (cmd.response[0] & MMC_STATUS_RDY_FOR_DATA)
			break;

		udelay(1000);

		if (cmd.response[0] & MMC_STATUS_MASK) {
			mmcdbg("Status Error: 0x%08X\n", cmd.response[0]);
			return COMM_ERR;
		}
	} while (timeout--);

	if (!timeout) {
		mmcdbg("Timeout waiting card ready\n");
		return TIMEOUT;
	}

	return 0;
}
static unsigned long
mmc_write_blocks(struct mmc *mmc, unsigned long start, unsigned blkcnt, const void*src)
{
	struct mmc_cmd cmd;
	struct mmc_data data;
	int timeout = 1000;

	if ((start + blkcnt) > mmc->lba) {
		mmcdbg("MMC: block number 0x%lx exceeds max(0x%lx)\n",
			start + blkcnt, mmc->lba);
		return 0;
	}

	if (blkcnt > 1)
		cmd.cmdidx = MMC_CMD_WRITE_MULTIPLE_BLOCK;
	else
		cmd.cmdidx = MMC_CMD_WRITE_SINGLE_BLOCK;

	if (mmc->high_capacity)
		cmd.cmdarg = start;
	else
		cmd.cmdarg = start * mmc->write_bl_len;

	cmd.resp_type = MMC_RSP_R1;
	cmd.flags = 0;

	data.b.src = src;
	data.blocks = blkcnt;
	data.blocksize = mmc->write_bl_len;
	data.flags = MMC_DATA_WRITE;

	if (mmc_send_cmd(mmc, &cmd, &data)) {
		mmcdbg("mmc write failed\n");
		return 0;
	}

	/* SPI multiblock writes terminate using a special
	 * token, not a STOP_TRANSMISSION request.
	 */
	if (!mmc_host_is_spi(mmc) && blkcnt > 1) {
		cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION;
		cmd.cmdarg = 0;
		cmd.resp_type = MMC_RSP_R1b;
		cmd.flags = 0;
		if (mmc_send_cmd(mmc, &cmd, NULL)) {
			mmcdbg("mmc fail to send stop cmd\n");
			return 0;
		}


	}

	/* Waiting for the ready status */
	mmc_send_status(mmc, timeout);
	return blkcnt;
}
Example #3
0
static int mmc_config_clock(struct mmc *mmc, unsigned clk)
{
	struct sunxi_mmc_host* mmchost = (struct sunxi_mmc_host *)mmc->priv;
	unsigned rval = readl(&mmchost->reg->clkcr);
//	unsigned int clkdiv = 0;

	/* Disable Clock */
	rval &= ~(1 << 16);
	writel(rval, &mmchost->reg->clkcr);
	if(mmc_update_clk(mmc)){
		mmcinfo("mmc %d disable clock failed\n",mmchost ->mmc_no);
		return -1;
	}

//	clkdiv = mmchost->mclk/clk/2;
	//disable mclk first
	writel(0,mmchost->mclkbase);
	mmcdbg("mmc %d mclkbase %x\n",mmchost ->mmc_no,readl(mmchost->mclkbase));
	if (clk <=400000) {
	    mmchost->mclk = 400000;
	    writel(0x0002000f, mmchost->mclkbase);
	    mmcdbg("mmc %d mclkbase%x\n",mmchost ->mmc_no,readl(mmchost->mclkbase));
	} else {
	    mmchost->mclk = 12000000;
	    writel(0x00000001, mmchost->mclkbase);
	    mmcdbg("mmc %d mclkbase%x\n",mmchost ->mmc_no,readl(mmchost->mclkbase));
	}
	//re-enable mclk
	writel(readl(mmchost->mclkbase)|(1<<31),mmchost->mclkbase);
	mmcdbg("mmc %d mclkbase%x\n",mmchost ->mmc_no,readl(mmchost->mclkbase));
	/*
	 * CLKCREG[7:0]: divider
	 * CLKCREG[16]:  on/off
	 * CLKCREG[17]:  power save
	 */
	/* Change Divider Factor */
	rval &= ~(0xFF);
	writel(rval, &mmchost->reg->clkcr);
	if(mmc_update_clk(mmc)){
		mmcinfo("mmc %d Change Divider Factor failed\n",mmchost ->mmc_no);
		return -1;
    }
	/* Re-enable Clock */
	rval |= (3 << 16);
	writel(rval, &mmchost->reg->clkcr);
	if(mmc_update_clk(mmc)){
		mmcinfo("mmc %d re-enable clock failed\n",mmchost ->mmc_no);
		return -1;
	}
	return 0;
}
Example #4
0
static int mmc_resource_init(int sdc_no)
{
	struct sunxi_mmc_host* mmchost = &mmc_host[sdc_no];

	mmcdbg("init mmc %d resource\n", sdc_no);
	mmchost->reg = (struct sunxi_mmc *)(MMC_REG_BASE + sdc_no * 0x1000);
	mmchost->database = (u32)mmchost->reg + MMC_REG_FIFO_OS;

#ifdef CONFIG_ARCH_SUN9IW1P1
	mmchost->commreg = MMC_REG_COMM_BASE+sdc_no*4;
	mmchost->hclkbase = 0x06000400+0x180;
	mmchost->hclkrst  = 0x06000400+0x1a0;
#else
	mmchost->hclkbase = CCMU_HCLKGATE0_BASE;
#if !defined(CONFIG_ARCH_SUN5I) && !defined(CONFIG_ARCH_SUN7I)
	mmchost->hclkrst  = CCMU_HCLKRST0_BASE;
#endif
#endif
	if (sdc_no == 0)
		mmchost->mclkbase = CCMU_MMC0_CLK_BASE;
	else if (sdc_no == 2)
		mmchost->mclkbase = CCMU_MMC2_CLK_BASE;
	else {
		mmcinfo("Wrong mmc NO.: %d\n", sdc_no);
		return -1;
	}
	mmchost->mmc_no = sdc_no;

	return 0;
}
unsigned long
mmc_bread(int dev_num, unsigned long start, unsigned blkcnt, void *dst)
{
	unsigned cur, blocks_todo = blkcnt;
	struct mmc *mmc = find_mmc_device(dev_num);

	if (blkcnt == 0)
		return 0;
	if (!mmc)
		return 0;

	if ((start + blkcnt) > mmc->lba) {
		mmcdbg("MMC: block number 0x%x exceeds max(0x%x)\n",
			start + blkcnt, mmc->lba);
		return 0;
	}

	if (mmc_set_blocklen(mmc, mmc->read_bl_len))
		return 0;

	do {
		cur = (blocks_todo > mmc->b_max) ?  mmc->b_max : blocks_todo;
		if(mmc_read_blocks(mmc, dst, start, cur) != cur)
			return 0;
		blocks_todo -= cur;
		start += cur;
//		dst += cur * mmc->read_bl_len;
		dst = (char*)dst + cur * mmc->read_bl_len;
	} while (blocks_todo > 0);

	return blkcnt;
}
struct mmc *find_mmc_device(int dev_num)
{
	if (mmc_devices[dev_num] != NULL)
		return mmc_devices[dev_num];

	mmcdbg("MMC Device %d not found\n", dev_num);

	return NULL;
}
Example #7
0
static unsigned long mmc_erase_t(struct mmc *mmc, unsigned long start, unsigned blkcnt)
{
	struct mmc_cmd cmd;
	unsigned long end;
	int err, start_cmd, end_cmd;

	if (mmc->high_capacity)
		end = start + blkcnt - 1;
	else {
		end = (start + blkcnt - 1) * mmc->write_bl_len;
		start *= mmc->write_bl_len;
	}

	if (IS_SD(mmc)) {
		start_cmd = SD_CMD_ERASE_WR_BLK_START;
		end_cmd = SD_CMD_ERASE_WR_BLK_END;
	} else {
		start_cmd = MMC_CMD_ERASE_GROUP_START;
		end_cmd = MMC_CMD_ERASE_GROUP_END;
	}

	cmd.cmdidx = start_cmd;
	cmd.cmdarg = start;
	cmd.resp_type = MMC_RSP_R1;
	cmd.flags = 0;

	err = mmc_send_cmd(mmc, &cmd, NULL);
	if (err)
		goto err_out;

	cmd.cmdidx = end_cmd;
	cmd.cmdarg = end;

	err = mmc_send_cmd(mmc, &cmd, NULL);
	if (err)
		goto err_out;

	cmd.cmdidx = MMC_CMD_ERASE;
	cmd.cmdarg = SECURE_ERASE;
	cmd.resp_type = MMC_RSP_R1b;

	err = mmc_send_cmd(mmc, &cmd, NULL);
	if (err)
		goto err_out;

	return 0;

err_out:
	mmcdbg("mmc erase failed\n");
	return err;
}
int mmc_read_blocks(struct mmc *mmc, void *dst, unsigned long start, unsigned blkcnt)
{
	struct mmc_cmd cmd;
	struct mmc_data data;
	int timeout = 1000;

	if (blkcnt > 1)
		cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK;
	else
		cmd.cmdidx = MMC_CMD_READ_SINGLE_BLOCK;

	if (mmc->high_capacity)
		cmd.cmdarg = start;
	else
		cmd.cmdarg = start * mmc->read_bl_len;

	cmd.resp_type = MMC_RSP_R1;
	cmd.flags = 0;

	data.b.dest = dst;
	data.blocks = blkcnt;
	data.blocksize = mmc->read_bl_len;
	data.flags = MMC_DATA_READ;

	if (mmc_send_cmd(mmc, &cmd, &data))
		return 0;

	if (blkcnt > 1) {
		cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION;
		cmd.cmdarg = 0;
		cmd.resp_type = MMC_RSP_R1b;
		cmd.flags = 0;
		if (mmc_send_cmd(mmc, &cmd, NULL)) {
			mmcdbg("mmc fail to send stop cmd\n");
			return 0;
		}

		/* Waiting for the ready status */
		mmc_send_status(mmc, timeout);
	}

	return blkcnt;
}
Example #9
0
static void mmc_set_ios(struct mmc *mmc)
{
	struct sunxi_mmc_host* mmchost = (struct sunxi_mmc_host *)mmc->priv;


	mmcdbg("mmc %d ios: bus: %d, clock: %d\n",mmchost ->mmc_no, mmc->bus_width, mmc->clock);

	if (mmc->clock && mmc_config_clock(mmc, mmc->clock)) {
	    mmcinfo("[mmc]: " "*** update clock failed\n");
		mmchost->fatal_err = 1;
		return;
	}
	/* Change bus width */
	if (mmc->bus_width == 8)
		writel(2, &mmchost->reg->width);
	else if (mmc->bus_width == 4)
		writel(1, &mmchost->reg->width);
	else
		writel(0, &mmchost->reg->width);
}
Example #10
0
static int mmc_resource_init(int sdc_no)
{
	struct sunxi_mmc_host* mmchost = &mmc_host[sdc_no];

	mmcdbg("init mmc %d resource\n", sdc_no);
	mmchost->reg = (struct sunxi_mmc *)(MMC_REG_BASE + sdc_no * 0x1000);
	mmchost->database = (u32)mmchost->reg + MMC_REG_FIFO_OS;

	mmchost->hclkbase = CCMU_HCLKGATE0_BASE;
	mmchost->hclkrst  = CCMU_BUS_SOFT_RST_REG0;
	if (sdc_no == 0)
		mmchost->mclkbase = CCMU_MMC0_CLK_BASE;
	else if (sdc_no == 2)
		mmchost->mclkbase = CCMU_MMC2_CLK_BASE;
	else {
		mmcinfo("Wrong mmc NO.: %d\n", sdc_no);
		return -1;
	}
	mmchost->mmc_no = sdc_no;

	return 0;
}
Example #11
0
int mmc_change_freq(struct mmc *mmc)
{
	char ext_csd[512];
	char cardtype;
	int err;
	int retry = 5;

	mmc->card_caps = 0;

	if (mmc_host_is_spi(mmc))
		return 0;

	/* Only version 4 supports high-speed */
	if (mmc->version < MMC_VERSION_4)
		return 0;

	mmc->card_caps |= MMC_MODE_4BIT|MMC_MODE_8BIT;
	err = mmc_send_ext_csd(mmc, ext_csd);

	if (err){
		mmcinfo("mmc %d get ext csd failed\n",mmc->control_num);
		return err;
	}

	cardtype = ext_csd[196] & 0xff;

	//retry for Toshiba emmc,for the first time Toshiba emmc change to HS
	//it will return response crc err,so retry
	do{
		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 1);
		if(!err){
			break;
		}
		mmcinfo("retry mmc switch(cmd6)\n");
	}while(retry--);

	if (err){
		mmcinfo("mmc %d change to hs failed\n",mmc->control_num);
		return err;
	}

	/* Now check to see that it worked */
	err = mmc_send_ext_csd(mmc, ext_csd);

	if (err){
		mmcinfo("mmc %d send ext csd faild\n",mmc->control_num);
		return err;
	}

	/* No high-speed support */
	if (!ext_csd[185])
		return 0;

	/* High Speed is set, there are two types: 52MHz and 26MHz */
	if (cardtype & EXT_CSD_CARD_TYPE_HS) { //EXT_CSD_CARD_TYPE_52
		if (cardtype & EXT_CSD_CARD_TYPE_DDR_52) {
			mmcdbg("%s: get ddr OK!\n", __FUNCTION__);
			mmc->card_caps |= MMC_MODE_DDR_52MHz;
			mmc->speed_mode = HSDDR52_DDR50;
		} else
			mmc->speed_mode = HSSDR52_SDR25;
		mmc->card_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS;
	} else {
		mmc->card_caps |= MMC_MODE_HS;
		mmc->speed_mode = DS26_SDR12;
	}

	return 0;
}