Commit 0f8d8ea6 authored by Adrian Hunter's avatar Adrian Hunter Committed by Chris Ball
Browse files

mmc: Fixes for Dual Data Rate (DDR) support



The DDR support patch needs the following fixes:

- The block driver does not need to know about DDR, any more
  than it needs to know about bus width.
- Not only the card must be switched to DDR mode.  The host
  controller must also be configured, which is done through
  the 'set_ios()' function.
- Do not set the DDR mode state until after the switch command
  is successful.
- Setting block length is not supported in DDR mode.  Make that
  a core function and change the other place it is used (mmc_test)
  also.

Signed-off-by: default avatarAdrian Hunter <adrian.hunter@nokia.com>
Signed-off-by: default avatarChris Ball <cjb@laptop.org>
parent dfc13e84
Loading
Loading
Loading
Loading
+3 −16
Original line number Diff line number Diff line
@@ -373,8 +373,6 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req)
			readcmd = MMC_READ_SINGLE_BLOCK;
			writecmd = MMC_WRITE_BLOCK;
		}
		if (mmc_card_ddr_mode(card))
			brq.data.flags |= MMC_DDR_MODE;
		if (rq_data_dir(req) == READ) {
			brq.cmd.opcode = readcmd;
			brq.data.flags |= MMC_DATA_READ;
@@ -653,26 +651,15 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
static int
mmc_blk_set_blksize(struct mmc_blk_data *md, struct mmc_card *card)
{
	struct mmc_command cmd;
	int err;

	/*
	 * Block-addressed and ddr mode supported cards
	 * ignore MMC_SET_BLOCKLEN.
	 */
	if (mmc_card_blockaddr(card) || mmc_card_ddr_mode(card))
		return 0;

	mmc_claim_host(card->host);
	cmd.opcode = MMC_SET_BLOCKLEN;
	cmd.arg = 512;
	cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
	err = mmc_wait_for_cmd(card->host, &cmd, 5);
	err = mmc_set_blocklen(card, 512);
	mmc_release_host(card->host);

	if (err) {
		printk(KERN_ERR "%s: unable to set block size to %d: %d\n",
			md->disk->disk_name, cmd.arg, err);
		printk(KERN_ERR "%s: unable to set block size to 512: %d\n",
			md->disk->disk_name, err);
		return -EINVAL;
	}

+1 −11
Original line number Diff line number Diff line
@@ -155,17 +155,7 @@ struct mmc_test_card {
 */
static int mmc_test_set_blksize(struct mmc_test_card *test, unsigned size)
{
	struct mmc_command cmd;
	int ret;

	cmd.opcode = MMC_SET_BLOCKLEN;
	cmd.arg = size;
	cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
	ret = mmc_wait_for_cmd(test->card->host, &cmd, 0);
	if (ret)
		return ret;

	return 0;
	return mmc_set_blocklen(test->card, size);
}

/*
+4 −2
Original line number Diff line number Diff line
@@ -253,14 +253,16 @@ int mmc_add_card(struct mmc_card *card)
	}

	if (mmc_host_is_spi(card->host)) {
		printk(KERN_INFO "%s: new %s%s card on SPI\n",
		printk(KERN_INFO "%s: new %s%s%s card on SPI\n",
			mmc_hostname(card->host),
			mmc_card_highspeed(card) ? "high speed " : "",
			mmc_card_ddr_mode(card) ? "DDR " : "",
			type);
	} else {
		printk(KERN_INFO "%s: new %s%s card at address %04x\n",
		printk(KERN_INFO "%s: new %s%s%s card at address %04x\n",
			mmc_hostname(card->host),
			mmc_card_highspeed(card) ? "high speed " : "",
			mmc_card_ddr_mode(card) ? "DDR " : "",
			type, card->rca);
	}

+26 −2
Original line number Diff line number Diff line
@@ -651,14 +651,23 @@ void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode)
}

/*
 * Change data bus width of a host.
 * Change data bus width and DDR mode of a host.
 */
void mmc_set_bus_width(struct mmc_host *host, unsigned int width)
void mmc_set_bus_width_ddr(struct mmc_host *host, unsigned int width, int ddr)
{
	host->ios.bus_width = width;
	host->ios.ddr = ddr ? MMC_DDR_MODE : MMC_SDR_MODE;
	mmc_set_ios(host);
}

/*
 * Change data bus width of a host.
 */
void mmc_set_bus_width(struct mmc_host *host, unsigned int width)
{
	mmc_set_bus_width_ddr(host, width, 0);
}

/**
 * mmc_vdd_to_ocrbitnum - Convert a voltage to the OCR bit number
 * @vdd:	voltage (mV)
@@ -1399,6 +1408,21 @@ int mmc_erase_group_aligned(struct mmc_card *card, unsigned int from,
}
EXPORT_SYMBOL(mmc_erase_group_aligned);

int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen)
{
	struct mmc_command cmd;

	if (mmc_card_blockaddr(card) || mmc_card_ddr_mode(card))
		return 0;

	memset(&cmd, 0, sizeof(struct mmc_command));
	cmd.opcode = MMC_SET_BLOCKLEN;
	cmd.arg = blocklen;
	cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
	return mmc_wait_for_cmd(card->host, &cmd, 5);
}
EXPORT_SYMBOL(mmc_set_blocklen);

void mmc_rescan(struct work_struct *work)
{
	struct mmc_host *host =
+1 −0
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@ void mmc_set_chip_select(struct mmc_host *host, int mode);
void mmc_set_clock(struct mmc_host *host, unsigned int hz);
void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode);
void mmc_set_bus_width(struct mmc_host *host, unsigned int width);
void mmc_set_bus_width_ddr(struct mmc_host *host, unsigned int width, int ddr);
u32 mmc_select_voltage(struct mmc_host *host, u32 ocr);
void mmc_set_timing(struct mmc_host *host, unsigned int timing);

Loading