Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit cdb54fac authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge branch 'for-linus' of master.kernel.org:/pub/scm/linux/kernel/git/drzeus/mmc

* 'for-linus' of master.kernel.org:/pub/scm/linux/kernel/git/drzeus/mmc:
  mmc: correct request error handling
  mmc: Flush block queue when removing card
  mmc: sdhci high speed support
  mmc: Support for high speed SD cards
  mmc: Fix mmc_delay() function
  mmc: Add support for mmc v4 wide-bus modes
  [PATCH] mmc: Add support for mmc v4 high speed mode
  trivial change for mmc/Kconfig: MMC_PXA does not mean only PXA255
  Make general code cleanups
  Add MMC_CAP_{MULTIWRITE,BYTEBLOCK} flags
  Platform device error handling cleanup
  Move register definitions away from the header file
  Change OMAP_MMC_{READ,WRITE} macros to use the host pointer
  Replace base with virt_base and phys_base
  mmc: constify mmc_host_ops vectors
  mmc: remove kernel_thread()
parents 37043318 8b7feff8
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -40,7 +40,7 @@ config MMC_ARMMMCI
	  If unsure, say N.

config MMC_PXA
	tristate "Intel PXA255 Multimedia Card Interface support"
	tristate "Intel PXA25x/26x/27x Multimedia Card Interface support"
	depends on ARCH_PXA && MMC
	help
	  This selects the Intel(R) PXA(R) Multimedia card Interface.
+1 −1
Original line number Diff line number Diff line
@@ -793,7 +793,7 @@ int at91_mci_get_ro(struct mmc_host *mmc)
	return read_only;
}

static struct mmc_host_ops at91_mci_ops = {
static const struct mmc_host_ops at91_mci_ops = {
	.request	= at91_mci_request,
	.set_ios	= at91_mci_set_ios,
	.get_ro		= at91_mci_get_ro,
+1 −1
Original line number Diff line number Diff line
@@ -875,7 +875,7 @@ static void au1xmmc_init_dma(struct au1xmmc_host *host)
	host->rx_chan = rxchan;
}

struct mmc_host_ops au1xmmc_ops = {
struct const mmc_host_ops au1xmmc_ops = {
	.request	= au1xmmc_request,
	.set_ios	= au1xmmc_set_ios,
};
+1 −1
Original line number Diff line number Diff line
@@ -877,7 +877,7 @@ static void imxmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
	}
}

static struct mmc_host_ops imxmci_ops = {
static const struct mmc_host_ops imxmci_ops = {
	.request	= imxmci_request,
	.set_ios	= imxmci_set_ios,
};
+274 −20
Original line number Diff line number Diff line
@@ -4,6 +4,7 @@
 *  Copyright (C) 2003-2004 Russell King, All Rights Reserved.
 *  SD support Copyright (C) 2004 Ian Molton, All Rights Reserved.
 *  SD support Copyright (C) 2005 Pierre Ossman, All Rights Reserved.
 *  MMCv4 support Copyright (C) 2006 Philip Langdale, All Rights Reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
@@ -396,23 +397,23 @@ static int mmc_select_card(struct mmc_host *host, struct mmc_card *card)
		return err;

	/*
	 * Default bus width is 1 bit.
	 */
	host->ios.bus_width = MMC_BUS_WIDTH_1;

	/*
	 * We can only change the bus width of the selected
	 * card so therefore we have to put the handling
	 * We can only change the bus width of SD cards when
	 * they are selected so we have to put the handling
	 * here.
	 */
	if (host->caps & MMC_CAP_4_BIT_DATA) {
		/*
	 *
	 * The card is in 1 bit mode by default so
	 * we only need to change if it supports the
	 * wider version.
	 */
	if (mmc_card_sd(card) &&
		(card->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) {

		/*
		* Default bus width is 1 bit.
		*/
		host->ios.bus_width = MMC_BUS_WIDTH_1;

		if (host->caps & MMC_CAP_4_BIT_DATA) {
			struct mmc_command cmd;
			cmd.opcode = SD_APP_SET_BUS_WIDTH;
			cmd.arg = SD_BUS_WIDTH_4;
@@ -453,11 +454,11 @@ static void mmc_deselect_cards(struct mmc_host *host)

static inline void mmc_delay(unsigned int ms)
{
	if (ms < HZ / 1000) {
		yield();
	if (ms < 1000 / HZ) {
		cond_resched();
		mdelay(ms);
	} else {
		msleep_interruptible (ms);
		msleep(ms);
	}
}

@@ -953,6 +954,137 @@ static void mmc_read_csds(struct mmc_host *host)
	}
}

static void mmc_process_ext_csds(struct mmc_host *host)
{
	int err;
	struct mmc_card *card;

	struct mmc_request mrq;
	struct mmc_command cmd;
	struct mmc_data data;

	struct scatterlist sg;

	/*
	 * As the ext_csd is so large and mostly unused, we don't store the
	 * raw block in mmc_card.
	 */
	u8 *ext_csd;
	ext_csd = kmalloc(512, GFP_KERNEL);
	if (!ext_csd) {
		printk("%s: could not allocate a buffer to receive the ext_csd."
		       "mmc v4 cards will be treated as v3.\n",
			mmc_hostname(host));
		return;
	}

	list_for_each_entry(card, &host->cards, node) {
		if (card->state & (MMC_STATE_DEAD|MMC_STATE_PRESENT))
			continue;
		if (mmc_card_sd(card))
			continue;
		if (card->csd.mmca_vsn < CSD_SPEC_VER_4)
			continue;

		err = mmc_select_card(host, card);
		if (err != MMC_ERR_NONE) {
			mmc_card_set_dead(card);
			continue;
		}

		memset(&cmd, 0, sizeof(struct mmc_command));

		cmd.opcode = MMC_SEND_EXT_CSD;
		cmd.arg = 0;
		cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;

		memset(&data, 0, sizeof(struct mmc_data));

		mmc_set_data_timeout(&data, card, 0);

		data.blksz = 512;
		data.blocks = 1;
		data.flags = MMC_DATA_READ;
		data.sg = &sg;
		data.sg_len = 1;

		memset(&mrq, 0, sizeof(struct mmc_request));

		mrq.cmd = &cmd;
		mrq.data = &data;

		sg_init_one(&sg, ext_csd, 512);

		mmc_wait_for_req(host, &mrq);

		if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE) {
			mmc_card_set_dead(card);
			continue;
		}

		switch (ext_csd[EXT_CSD_CARD_TYPE]) {
		case EXT_CSD_CARD_TYPE_52 | EXT_CSD_CARD_TYPE_26:
			card->ext_csd.hs_max_dtr = 52000000;
			break;
		case EXT_CSD_CARD_TYPE_26:
			card->ext_csd.hs_max_dtr = 26000000;
			break;
		default:
			/* MMC v4 spec says this cannot happen */
			printk("%s: card is mmc v4 but doesn't support "
			       "any high-speed modes.\n",
				mmc_hostname(card->host));
			mmc_card_set_bad(card);
			continue;
		}

		/* Activate highspeed support. */
		cmd.opcode = MMC_SWITCH;
		cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
			  (EXT_CSD_HS_TIMING << 16) |
			  (1 << 8) |
			  EXT_CSD_CMD_SET_NORMAL;
		cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;

		err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
		if (err != MMC_ERR_NONE) {
			printk("%s: failed to switch card to mmc v4 "
			       "high-speed mode.\n",
			       mmc_hostname(card->host));
			continue;
		}

		mmc_card_set_highspeed(card);

		/* Check for host support for wide-bus modes. */
		if (!(host->caps & MMC_CAP_4_BIT_DATA)) {
			continue;
		}

		/* Activate 4-bit support. */
		cmd.opcode = MMC_SWITCH;
		cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
			  (EXT_CSD_BUS_WIDTH << 16) |
			  (EXT_CSD_BUS_WIDTH_4 << 8) |
			  EXT_CSD_CMD_SET_NORMAL;
		cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;

		err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
		if (err != MMC_ERR_NONE) {
			printk("%s: failed to switch card to "
			       "mmc v4 4-bit bus mode.\n",
			       mmc_hostname(card->host));
			continue;
		}

		host->ios.bus_width = MMC_BUS_WIDTH_4;
	}

	kfree(ext_csd);

	mmc_deselect_cards(host);
}

static void mmc_read_scrs(struct mmc_host *host)
{
	int err;
@@ -1025,14 +1157,133 @@ static void mmc_read_scrs(struct mmc_host *host)
	mmc_deselect_cards(host);
}

static void mmc_read_switch_caps(struct mmc_host *host)
{
	int err;
	struct mmc_card *card;
	struct mmc_request mrq;
	struct mmc_command cmd;
	struct mmc_data data;
	unsigned char *status;
	struct scatterlist sg;

	status = kmalloc(64, GFP_KERNEL);
	if (!status) {
		printk(KERN_WARNING "%s: Unable to allocate buffer for "
			"reading switch capabilities.\n",
			mmc_hostname(host));
		return;
	}

	list_for_each_entry(card, &host->cards, node) {
		if (card->state & (MMC_STATE_DEAD|MMC_STATE_PRESENT))
			continue;
		if (!mmc_card_sd(card))
			continue;
		if (card->scr.sda_vsn < SCR_SPEC_VER_1)
			continue;

		err = mmc_select_card(host, card);
		if (err != MMC_ERR_NONE) {
			mmc_card_set_dead(card);
			continue;
		}

		memset(&cmd, 0, sizeof(struct mmc_command));

		cmd.opcode = SD_SWITCH;
		cmd.arg = 0x00FFFFF1;
		cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;

		memset(&data, 0, sizeof(struct mmc_data));

		mmc_set_data_timeout(&data, card, 0);

		data.blksz = 64;
		data.blocks = 1;
		data.flags = MMC_DATA_READ;
		data.sg = &sg;
		data.sg_len = 1;

		memset(&mrq, 0, sizeof(struct mmc_request));

		mrq.cmd = &cmd;
		mrq.data = &data;

		sg_init_one(&sg, status, 64);

		mmc_wait_for_req(host, &mrq);

		if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE) {
			mmc_card_set_dead(card);
			continue;
		}

		if (status[13] & 0x02)
			card->sw_caps.hs_max_dtr = 50000000;

		memset(&cmd, 0, sizeof(struct mmc_command));

		cmd.opcode = SD_SWITCH;
		cmd.arg = 0x80FFFFF1;
		cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;

		memset(&data, 0, sizeof(struct mmc_data));

		mmc_set_data_timeout(&data, card, 0);

		data.blksz = 64;
		data.blocks = 1;
		data.flags = MMC_DATA_READ;
		data.sg = &sg;
		data.sg_len = 1;

		memset(&mrq, 0, sizeof(struct mmc_request));

		mrq.cmd = &cmd;
		mrq.data = &data;

		sg_init_one(&sg, status, 64);

		mmc_wait_for_req(host, &mrq);

		if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE) {
			mmc_card_set_dead(card);
			continue;
		}

		if ((status[16] & 0xF) != 1) {
			printk(KERN_WARNING "%s: Problem switching card "
				"into high-speed mode!\n",
				mmc_hostname(host));
			continue;
		}

		mmc_card_set_highspeed(card);
	}

	kfree(status);

	mmc_deselect_cards(host);
}

static unsigned int mmc_calculate_clock(struct mmc_host *host)
{
	struct mmc_card *card;
	unsigned int max_dtr = host->f_max;

	list_for_each_entry(card, &host->cards, node)
		if (!mmc_card_dead(card) && max_dtr > card->csd.max_dtr)
		if (!mmc_card_dead(card)) {
			if (mmc_card_highspeed(card) && mmc_card_sd(card)) {
				if (max_dtr > card->sw_caps.hs_max_dtr)
					max_dtr = card->sw_caps.hs_max_dtr;
			} else if (mmc_card_highspeed(card) && !mmc_card_sd(card)) {
				if (max_dtr > card->ext_csd.hs_max_dtr)
					max_dtr = card->ext_csd.hs_max_dtr;
			} else if (max_dtr > card->csd.max_dtr) {
				max_dtr = card->csd.max_dtr;
			}
		}

	pr_debug("%s: selected %d.%03dMHz transfer rate\n",
		 mmc_hostname(host),
@@ -1150,8 +1401,11 @@ static void mmc_setup(struct mmc_host *host)

	mmc_read_csds(host);

	if (host->mode == MMC_MODE_SD)
	if (host->mode == MMC_MODE_SD) {
		mmc_read_scrs(host);
		mmc_read_switch_caps(host);
	} else
		mmc_process_ext_csds(host);
}


Loading