Re: mmc errors (was Re: [PATCH] arm: Fix DEBUG_LL for omap zoom2/3)

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hello all

I've juste finished a modification about a multi eMMC on own platform.
we used 4 eMMC of 32Gib (micron MTFC32GHKD) on same host (MMC1) and we used it like de big device (128Gib)

I had a similar problem (It was the pbias 1 configuration)

I can't test the effect on SD card
any comments...



diff --git a/drivers/mmc/card/Kconfig b/drivers/mmc/card/Kconfig
index 3f2a912..6054441 100644
--- a/drivers/mmc/card/Kconfig
+++ b/drivers/mmc/card/Kconfig
@@ -32,6 +32,19 @@ config MMC_BLOCK_BOUNCE

 	  If unsure, say Y here.

+config MULTI_MMC_AS_ONE
+	bool "Simulate multi mmc card as one big"
+	depends on MMC_BLOCK && MULTI_MMC_ON_HOST
+	default y
+	help
+	  A multiple SD/MMC card can be connected on a single host controller.
+	  with this you can see a large device.
+
+	  Say N here if you want to see as multiple storage devices
+
+	  If unsure, say N here.
+
+
 config SDIO_UART
 	tristate "SDIO UART/GPS class support"
 	help
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 1f552c6..a368ecb 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -16,6 +16,12 @@
  *
  * Author:  Andrew Christian
  *          28 May 2002
+ *
+ * 20100315	
+ *          Laurent Epinat <laurent.epinat@xxxxxxxxxxxxxxx>
+ * Add multi "card" on one controller
+ * seen as multi card or as one big card
+ *
  */
 #include <linux/moduleparam.h>
 #include <linux/module.h>
@@ -41,6 +47,10 @@

 #include "queue.h"

+#ifdef CONFIG_MULTI_MMC_ON_HOST
+#include "../core/mmc_ops.h"
+#endif
+
 MODULE_ALIAS("mmc:block");

 /*
@@ -248,6 +258,13 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
 	struct mmc_blk_request brq;
 	int ret = 1, disable_multi = 0;

+#ifdef CONFIG_MULTI_MMC_ON_HOST
+static struct mmc_card *card_cur=NULL;
+int card_size;
+#ifdef CONFIG_MULTI_MMC_AS_ONE
+	int idx;
+#endif
+#endif
 	mmc_claim_host(card->host);

 	do {
@@ -261,6 +278,17 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
 		brq.cmd.arg = blk_rq_pos(req);
 		if (!mmc_card_blockaddr(card))
 			brq.cmd.arg <<= 9;
+#ifdef CONFIG_MULTI_MMC_ON_HOST
+		else {
+			/* All cards as a seem size */
+			/* TODO: check for card <2Gb (ext_csd is 0 );and
+			 * calculation for a size different
+			 **/
+			BUG_ON(!card->ext_csd.sectors);
+			card_size = card->ext_csd.sectors;
+		}
+#endif
+			
 		brq.cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
 		brq.data.blksz = 512;
 		brq.stop.opcode = MMC_STOP_TRANSMISSION;
@@ -273,9 +301,39 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
 		 * restrictions, so we need to be prepared for too big
 		 * requests.
 		 */
-		if (brq.data.blocks > card->host->max_blk_count)
+		if (brq.data.blocks > card->host->max_blk_count)
 			brq.data.blocks = card->host->max_blk_count;

+#ifdef CONFIG_MULTI_MMC_ON_HOST
+#ifdef CONFIG_MULTI_MMC_AS_ONE
+		idx = (brq.cmd.arg/card_size);
+		/* Force to select a new card if necessary */
+		if (card != card->host->cards[idx]) {
+			card = card->host->cards[idx];
+			card_size = card->ext_csd.sectors;
+			brq.cmd.arg -= idx * card_size;
+		}
+		/*
+		 * Check if the block can go the selected card
+		 * if not truc it
+		 */
+		if (brq.cmd.arg + brq.data.blocks >  card_size) {
+			brq.data.blocks = card_size - brq.cmd.arg;
+		}
+#endif /* CONFIG_MULTI_MMC_AS_ONE */
+
+		/* Change the current mmc on bus if needed */
+		if (card != card_cur){
+			if (!mmc_select_card(card)) {
+				card_cur=card;
+			}
+			else {
+				printk(KERN_ERR "%s: error: Can't select Card %d\n",
+								req->rq_disk->disk_name, card->rca);
+			}
+		}
+#endif /* CONFIG_MULTI_MMC_ON_HOST */
+
 		/*
 		 * After a read error, we redo the request one sector at a time
 		 * in order to accurately determine which sectors can be read
@@ -481,6 +539,12 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
 	struct mmc_blk_data *md;
 	int devidx, ret;

+#ifdef CONFIG_MULTI_MMC_AS_ONE
+	struct mmc_host *host = card->host;
+	int i;
+	int sec_num;
+#endif
+
 	devidx = find_first_zero_bit(dev_use, MMC_NUM_MINORS);
 	if (devidx >= MMC_NUM_MINORS)
 		return ERR_PTR(-ENOSPC);
@@ -492,7 +556,6 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
 		goto out;
 	}

-
 	/*
 	 * Set the read-only status based on the supported commands
 	 * and the write protect switch.
@@ -543,15 +606,47 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
 		 * The EXT_CSD sector count is in number or 512 byte
 		 * sectors.
 		 */
+#ifdef CONFIG_MULTI_MMC_AS_ONE
+		for (i=0;i<host->card_detected;++i){
+			sec_num+=host->cards[i]->ext_csd.sectors;
+		}
+		set_capacity(md->disk, sec_num);
+#else
 		set_capacity(md->disk, card->ext_csd.sectors);
+#endif
 	} else {
 		/*
 		 * The CSD capacity field is in units of read_blkbits.
 		 * set_capacity takes units of 512 bytes.
 		 */
-		set_capacity(md->disk,
-			card->csd.capacity << (card->csd.read_blkbits - 9));
+#ifdef MMC_MULTI_CARD_AS_ONE
+		for (i=0; i<host->card_detected; ++i){
+			sec_num += host->cards[i]->csd.capacity <<
+									(host->cards[i]->csd.read_blkbits - 9)
+		}
+		set_capacity(md->disk, sec_num);
+#else
+		set_capacity(md->disk,
+						card->csd.capacity << (card->csd.read_blkbits - 9));
+#endif
 	}
+
+#if defined(CONFIG_MULTI_MMC_ON_HOST)
+{
+	/* deselect cards without waiting for completion */
+	struct mmc_request mrq={0};
+	struct mmc_command cmd={0};
+
+	cmd.opcode = MMC_SELECT_CARD;
+	cmd.arg = 0; /* deselect cards */
+	cmd.flags = MMC_RSP_NONE | MMC_CMD_AC;
+	mrq.cmd = &cmd;
+	mrq.cmd->mrq = &mrq;
+	
+	card->host->ops->request(card->host, &mrq);
+}
+#endif
+
 	return md;

  err_putdisk:
diff --git a/drivers/mmc/core/Kconfig b/drivers/mmc/core/Kconfig
index bb22ffd..b3c854e 100644
--- a/drivers/mmc/core/Kconfig
+++ b/drivers/mmc/core/Kconfig
@@ -16,3 +16,8 @@ config MMC_UNSAFE_RESUME

 	  This option sets a default which can be overridden by the
 	  module parameter "removable=0" or "removable=1".
+
+config MULTI_MMC_ON_HOST
+	bool "Detect multiple MMC/SD cards one same host controller"
+	help
+	  If you say Y here, the MMC layer scan the bus to discover MMC cards
diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
index bdb165f..badec96 100644
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -221,7 +222,9 @@ struct mmc_card *mmc_alloc_card(struct mmc_host *host, struct device_type *type)
  */
 int mmc_add_card(struct mmc_card *card)
 {
+#ifndef CONFIG_MULTI_MMC_AS_ONE
 	int ret;
+#endif
 	const char *type;

 	dev_set_name(&card->dev, "%s:%04x", mmc_hostname(card->host), card->rca);
@@ -255,9 +258,11 @@ int mmc_add_card(struct mmc_card *card)
 			type, card->rca);
 	}

+#ifndef CONFIG_MULTI_MMC_AS_ONE
 	ret = device_add(&card->dev);
 	if (ret)
 		return ret;
+#endif

 #ifdef CONFIG_DEBUG_FS
 	mmc_add_card_debugfs(card);
@@ -286,7 +291,9 @@ void mmc_remove_card(struct mmc_card *card)
 			printk(KERN_INFO "%s: card %04x removed\n",
 				mmc_hostname(card->host), card->rca);
 		}
+#ifndef CONFIG_MULTI_MMC_AS_ONE
 		device_del(&card->dev);
+#endif
 	}

 	put_device(&card->dev);
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 30acd52..b186933 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -910,9 +910,9 @@ static void mmc_power_up(struct mmc_host *host)
 	if (host->f_min > 400000) {
 		pr_warning("%s: Minimum clock frequency too high for "
 				"identification mode\n", mmc_hostname(host));
-		host->ios.clock = host->f_min;
-	} else
 		host->ios.clock = 400000;
+	} else
+		host->ios.clock = host->f_min;

 	host->ios.power_mode = MMC_POWER_ON;
 	mmc_set_ios(host);
@@ -1164,8 +1164,6 @@ void mmc_stop_host(struct mmc_host *host)
 	}
 	mmc_bus_put(host);

-	BUG_ON(host->card);
-
 	mmc_power_off(host);
 }

@@ -1235,10 +1233,21 @@ EXPORT_SYMBOL(mmc_card_sleep);

 int mmc_card_can_sleep(struct mmc_host *host)
 {
+
+#ifdef CONFIG_MULTI_MMC_ON_HOST
+	struct mmc_card *card;
+	int i;
+	for (i=0; i<host->card_detected;++i){
+		card = host->cards[i];
+		if (card && mmc_card_mmc(card) && card->ext_csd.rev >= 3)
+			return 1;
+	}
+#else
 	struct mmc_card *card = host->card;

 	if (card && mmc_card_mmc(card) && card->ext_csd.rev >= 3)
 		return 1;
+#endif
 	return 0;
 }
 EXPORT_SYMBOL(mmc_card_can_sleep);
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 0eac6c8..e29d1bd 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -5,6 +5,11 @@
  *  Copyright (C) 2005-2007 Pierre Ossman, All Rights Reserved.
  *  MMCv4 support Copyright (C) 2006 Philip Langdale, All Rights Reserved.
  *
+ * 20100315
+ *          Laurent Epinat <laurent.epinat@xxxxxxxxxxxxxxx>
+ * Add multi "card" detection on one controller
+ * they can be seen as multi card or as one big card
+ *
  * 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
  * published by the Free Software Foundation.
@@ -224,6 +229,11 @@ static int mmc_read_ext_csd(struct mmc_card *card)
 		if (card->ext_csd.sectors)
 			mmc_card_set_blockaddr(card);
 	}
+	else {
+		/* TODO: In MULTI CARD we need the size to select the crad on the bus */
+		WARN_ON(!card->ext_csd.sectors);
+
+	}

 	switch (ext_csd[EXT_CSD_CARD_TYPE]) {
 	case EXT_CSD_CARD_TYPE_52 | EXT_CSD_CARD_TYPE_26:
@@ -293,6 +303,261 @@ static struct device_type mmc_type = {
 	.groups = mmc_attr_groups,
 };

+#ifdef CONFIG_MULTI_MMC_ON_HOST
+/*
+ * Handle the detection and initialisation of a cards.
+ *
+ * In the case of a resume, "rescan" will contain a flag and
+ * we're trying to reinitialise all cards.
+ */
+static int mmc_init_cards(struct mmc_host *host, u32 ocr, int rescan)
+{
+	int i;
+	int high_speed = 1;
+	unsigned int ext_csd_bit=0, bus_width = MMC_BUS_WIDTH_8;
+	struct mmc_card *card=NULL;
+	int err;
+	u32 cid[4];
+	unsigned int max_dtr = (unsigned int)-1;
+
+	BUG_ON(!host);
+	WARN_ON(!host->claimed);
+
+	BUG_ON(host->card_detected);
+
+	/*
+	 * Since we're changing the OCR value, we seem to
+	 * need to tell some cards to go back to the idle
+	 * state.  We wait 1ms to give cards time to
+	 * respond.
+	 */
+	mmc_go_idle(host);
+
+	/* The extra bit indicates that we support high capacity */
+	err = mmc_send_op_cond(host, ocr | (1 << 30), NULL);
+	if (err)
+		goto err;
+
+	/*
+	 * For SPI, enable CRC as appropriate.
+	 */
+	if (mmc_host_is_spi(host)) {
+		err = mmc_spi_set_crc(host, use_spi_crc);
+		if (err)
+			goto err;
+	}
+
+	while(host->card_detected < MMC_MAX_CARD) {
+		/*
+		 * Fetch CID from card.
+		 */
+		if (mmc_host_is_spi(host))
+			err = mmc_send_cid(host, 0, cid);
+		else
+			err = mmc_all_send_cid(host, cid);
+		
+		if (err) {
+			if (!host->card_detected)
+				goto err;
+			else
+				break;
+		}
+		if (rescan) {
+			card = host->cards[host->card_detected];
+			if (memcmp(cid, card->raw_cid, sizeof(cid)) != 0) {
+				err = -ENOENT;
+				goto err;
+			}
+		} else {
+			/*
+			 * Allocate card structure.
+			 */
+			card = mmc_alloc_card(host, &mmc_type);
+			if (IS_ERR(card)) {
+				err = PTR_ERR(card);
+				goto err;
+			}
+
+			card->type = MMC_TYPE_MMC;
+			card->rca = host->card_detected+1;
+			memcpy(card->raw_cid, cid, sizeof(card->raw_cid));
+			
+			host->cards[host->card_detected] = card;
+		}
+
+		/*
+		 * For native busses:  set card RCA and quit open drain mode.
+		 */
+		if (!mmc_host_is_spi(host)) {
+			err = mmc_set_relative_addr(card);
+			if (err)
+				goto free_card;
+		}
+		host->card_detected++;
+	}
+
+	if (host->card_detected >= MMC_MAX_CARD) {
+			printk(KERN_ERR "%s: Problem card number detected\n",
+								mmc_hostname(host));
+		goto free_card;
+	}
+		
+	printk(KERN_INFO "%s: %d cards detected on this controller\n",
+			       mmc_hostname(host), host->card_detected);
+	
+	/* Set to push pull mode */
+	if (!mmc_host_is_spi(host)) {
+		mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL);
+	}
+
+	for (i=0;  !rescan && i < host->card_detected; ++i) {
+		card = host->cards[i];
+			/*
+			 * Fetch CSD from card.
+			 */
+			err = mmc_send_csd(card, card->raw_csd);
+			if (err)
+				goto free_card;
+
+			err = mmc_decode_csd(card);
+			if (err)
+				goto free_card;
+			err = mmc_decode_cid(card);
+			if (err)
+				goto free_card;
+	}
+
+	/* Get the EXT CSD for each card */
+	for (i=0; i < host->card_detected; ++i) {
+		card = host->cards[i];
+
+		/*
+		 * Select card, as all following commands rely on that.
+		 */
+		if (!mmc_host_is_spi(host)) {
+			err = mmc_select_card(card);
+			if (err)
+				goto free_card;
+		}
+
+		/*
+		 * Fetch and process extended CSD.
+		 */
+		if (!rescan) {
+			err = mmc_read_ext_csd(card);
+			if (err)
+				goto free_card;
+		}
+
+		/* Check if all cards can be switched to high speed mode */
+		if ((card->ext_csd.hs_max_dtr == 0) ||
+			!(host->caps & MMC_CAP_MMC_HIGHSPEED))
+		{
+			high_speed = 0;
+		}
+
+		/* Check if all cards can be switch to wide bus */
+		if (card->csd.mmca_vsn < CSD_SPEC_VER_4) {
+			bus_width = 0;
+		}
+	}
+
+	if (bus_width && (host->caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA))) {
+		if (host->caps & MMC_CAP_8_BIT_DATA) {
+			ext_csd_bit = EXT_CSD_BUS_WIDTH_8;
+			bus_width = MMC_BUS_WIDTH_8;
+		} else {
+			ext_csd_bit = EXT_CSD_BUS_WIDTH_4;
+			bus_width = MMC_BUS_WIDTH_4;
+		}
+	}
+	else {
+		bus_width = 0;
+	}
+
+	/* Set the speed en bus width to all cards */
+	for (i=0; i < host->card_detected; ++i) {
+		card = host->cards[i];
+
+		/*
+		 * Select card, as all following commands rely on that.
+		 */
+		if (!mmc_host_is_spi(host)) {
+			err = mmc_select_card(card);
+			if (err)
+				goto free_card;
+		}
+
+		if (high_speed)  {
+			/*
+			 * Activate high speed for all cards
+			 */
+			err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+				EXT_CSD_HS_TIMING, 1);
+			if (err && err != -EBADMSG)
+				goto free_card;
+
+			if (err) {
+				high_speed = 0;
+				printk(KERN_WARNING "%s: switch to highspeed failed\n",
+					   mmc_hostname(card->host));
+			}
+			else {
+				mmc_card_set_highspeed(card);
+			}
+		}
+
+		/*
+		 * Activate wide bus (if supported).
+		 */
+		if (bus_width) {
+			err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+				 EXT_CSD_BUS_WIDTH, ext_csd_bit);
+
+			if (err) {
+				printk(KERN_WARNING "%s: switch to highspeed failed\n",
+					   mmc_hostname(card->host));
+				bus_width = 0;
+			}
+		}
+
+		/*
+		 * Compute bus speed.
+		 * and chose the fastest of slowest cards
+		 */
+		if (mmc_card_highspeed(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) {
+			if (max_dtr > card->csd.max_dtr)
+				max_dtr = card->csd.max_dtr;
+		}
+	}
+
+	if (high_speed) {
+		mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
+	}
+	if (bus_width)
+		mmc_set_bus_width(card->host, bus_width);
+
+	if (max_dtr != (unsigned int)-1)
+		mmc_set_clock(host, max_dtr);
+
+	mmc_deselect_cards(host);
+	return 0;
+
+free_card:
+	while(!rescan && host->card_detected) {
+		if (host->cards[host->card_detected])
+			mmc_remove_card(host->cards[host->card_detected]);
+		--host->card_detected;
+	}
+err:
+	return err;
+}
+
+#else /* CONFIG_MULTI_MMC_ON_HOST */
+
 /*
  * Handle the detection and initialisation of a card.
  *
@@ -336,7 +601,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 	 * Fetch CID from card.
 	 */
 	if (mmc_host_is_spi(host))
-		err = mmc_send_cid(host, cid);
+		err = mmc_send_cid(host, 0, cid);
 	else
 		err = mmc_all_send_cid(host, cid);
 	if (err)
@@ -486,17 +751,27 @@ err:

 	return err;
 }
-
+#endif
 /*
  * Host is being removed. Free up the current card.
  */
 static void mmc_remove(struct mmc_host *host)
 {
 	BUG_ON(!host);
+#ifdef CONFIG_MULTI_MMC_ON_HOST
+	while (host->card_detected--) {
+		BUG_ON(!host->cards[host->card_detected]);
+		mmc_remove_card(host->cards[host->card_detected]);
+		host->cards[host->card_detected] = NULL;
+	}
+
+	
+#else	
 	BUG_ON(!host->card);

 	mmc_remove_card(host->card);
 	host->card = NULL;
+#endif
 }

 /*
@@ -504,6 +779,8 @@ static void mmc_remove(struct mmc_host *host)
  */
 static void mmc_detect(struct mmc_host *host)
 {
+#ifdef CONFIG_MULTI_MMC_ON_HOST
+#else
 	int err;

 	BUG_ON(!host);
@@ -525,6 +802,7 @@ static void mmc_detect(struct mmc_host *host)
 		mmc_detach_bus(host);
 		mmc_release_host(host);
 	}
+#endif
 }

 /*
@@ -532,7 +810,20 @@ static void mmc_detect(struct mmc_host *host)
  */
 static int mmc_suspend(struct mmc_host *host)
 {
+#ifdef CONFIG_MULTI_MMC_ON_HOST
+	int i;
 	BUG_ON(!host);
+	mmc_claim_host(host);
+	if (!mmc_host_is_spi(host))
+		mmc_deselect_cards(host);
+	for (i=0; i<host->card_detected;++i){
+		host->cards[i]->state &= ~MMC_STATE_HIGHSPEED;
+	}
+	host->card_detected = 0;
+	mmc_release_host(host);
+#else
+	BUG_ON(!host);
+
 	BUG_ON(!host->card);

 	mmc_claim_host(host);
@@ -540,7 +831,7 @@ static int mmc_suspend(struct mmc_host *host)
 		mmc_deselect_cards(host);
 	host->card->state &= ~MMC_STATE_HIGHSPEED;
 	mmc_release_host(host);
-
+#endif
 	return 0;
 }

@@ -554,26 +845,58 @@ static int mmc_resume(struct mmc_host *host)
 {
 	int err;

+#ifdef CONFIG_MULTI_MMC_ON_HOST
+	BUG_ON(!host);
+	mmc_claim_host(host);
+	err = mmc_init_cards(host, host->ocr, 1);
+	mmc_release_host(host);
+#else
 	BUG_ON(!host);
 	BUG_ON(!host->card);

 	mmc_claim_host(host);
 	err = mmc_init_card(host, host->ocr, host->card);
 	mmc_release_host(host);
+#endif

 	return err;
 }

 static void mmc_power_restore(struct mmc_host *host)
 {
+#ifdef CONFIG_MULTI_MMC_ON_HOST
+	int i;
+	mmc_claim_host(host);
+	for (i=0; i<host->card_detected; ++i){
+		host->cards[i]->state &= ~MMC_STATE_HIGHSPEED;
+	}
+	host->card_detected = 0;
+	mmc_init_cards(host, host->ocr, 1);
+	mmc_release_host(host);
+#else
 	host->card->state &= ~MMC_STATE_HIGHSPEED;
 	mmc_claim_host(host);
 	mmc_init_card(host, host->ocr, host->card);
 	mmc_release_host(host);
+#endif
 }

 static int mmc_sleep(struct mmc_host *host)
 {
+#ifdef CONFIG_MULTI_MMC_ON_HOST
+	int i;
+	struct mmc_card *card;
+	int err = -ENOSYS;
+	for (i=0; i<host->card_detected;++i){
+		card = host->cards[i];
+		if (card && card->ext_csd.rev >= 3) {
+			err = mmc_card_sleepawake(card, 1);
+			if (err < 0)
+				pr_debug("%s: Error %d while putting card into sleep",
+					 mmc_hostname(host), err);
+		}
+	}
+#else
 	struct mmc_card *card = host->card;
 	int err = -ENOSYS;

@@ -583,12 +906,28 @@ static int mmc_sleep(struct mmc_host *host)
 			pr_debug("%s: Error %d while putting card into sleep",
 				 mmc_hostname(host), err);
 	}
+#endif

 	return err;
 }

 static int mmc_awake(struct mmc_host *host)
 {
+#ifdef CONFIG_MULTI_MMC_ON_HOST
+	struct mmc_card *card;
+	int err = -ENOSYS;
+	int i;
+	for (i=0; i<host->card_detected;++i){
+		card = host->cards[i];
+
+		if (card && card->ext_csd.rev >= 3) {
+			err = mmc_card_sleepawake(card, 0);
+			if (err < 0)
+				pr_debug("%s: Error %d while awaking sleeping card",
+					 mmc_hostname(host), err);
+		}
+	}
+#else
 	struct mmc_card *card = host->card;
 	int err = -ENOSYS;

@@ -598,6 +937,7 @@ static int mmc_awake(struct mmc_host *host)
 			pr_debug("%s: Error %d while awaking sleeping card",
 				 mmc_hostname(host), err);
 	}
+#endif

 	return err;
 }
@@ -639,7 +979,9 @@ static void mmc_attach_bus_ops(struct mmc_host *host)
 int mmc_attach_mmc(struct mmc_host *host, u32 ocr)
 {
 	int err;
-
+#if defined(CONFIG_MULTI_MMC_ON_HOST)
+	int i;
+#endif
 	BUG_ON(!host);
 	WARN_ON(!host->claimed);

@@ -671,10 +1013,31 @@ int mmc_attach_mmc(struct mmc_host *host, u32 ocr)
 	 * Can we support the voltage of the card?
 	 */
 	if (!host->ocr) {
+		printk(KERN_ERR "%s: card claims to unsupported voltages\n",
+		       mmc_hostname(host));
 		err = -EINVAL;
 		goto err;
 	}

+#ifdef CONFIG_MULTI_MMC_ON_HOST
+	err = mmc_init_cards(host, host->ocr, 0);
+	if (err)  {
+		goto remove_card;
+	}
+	mmc_release_host(host);
+
+	for (i=0; i < host->card_detected; ++i) {
+		err = mmc_add_card(host->cards[i]);
+		if (err)
+			goto remove_card;
+	}
+#ifdef CONFIG_MULTI_MMC_AS_ONE
+	err = device_add(&host->cards[0]->dev);
+	if (err)
+		goto remove_device;
+#endif
+
+#else  /* CONFIG_MULTI_MMC_ON_HOST */
 	/*
 	 * Detect and init the card.
 	 */
@@ -687,12 +1050,29 @@ int mmc_attach_mmc(struct mmc_host *host, u32 ocr)
 	err = mmc_add_card(host->card);
 	if (err)
 		goto remove_card;
+#endif  /* CONFIG_MULTI_MMC_ON_HOST */

 	return 0;
+	
+#if defined(CONFIG_MULTI_MMC_AS_ONE)
+remove_device:
+	device_del(&host->cards[0]->dev);
+#endif

+#ifdef CONFIG_MULTI_MMC_ON_HOST
+remove_card:
+	while (host->card_detected) {
+		if (host->cards[host->card_detected])
+			mmc_remove_card(host->cards[host->card_detected]);
+		host->cards[host->card_detected] = NULL;
+		--host->card_detected;
+	}
+	host->card_detected = 0;
+#else
 remove_card:
 	mmc_remove_card(host->card);
 	host->card = NULL;
+#endif
 	mmc_claim_host(host);
 err:
 	mmc_detach_bus(host);
diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
index d2cb5c6..b894481 100644
--- a/drivers/mmc/core/mmc_ops.c
+++ b/drivers/mmc/core/mmc_ops.c
@@ -29,7 +29,6 @@ static int _mmc_select_card(struct mmc_host *host, struct mmc_card *card)
 	memset(&cmd, 0, sizeof(struct mmc_command));

 	cmd.opcode = MMC_SELECT_CARD;
-
 	if (card) {
 		cmd.arg = card->rca << 16;
 		cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
@@ -51,20 +50,21 @@ int mmc_select_card(struct mmc_card *card)

 	return _mmc_select_card(card->host, card);
 }
+EXPORT_SYMBOL(mmc_select_card);

 int mmc_deselect_cards(struct mmc_host *host)
 {
 	return _mmc_select_card(host, NULL);
 }
+EXPORT_SYMBOL(mmc_deselect_cards);

-int mmc_card_sleepawake(struct mmc_host *host, int sleep)
+int mmc_card_sleepawake(struct mmc_card *card, int sleep)
 {
 	struct mmc_command cmd;
-	struct mmc_card *card = host->card;
 	int err;

 	if (sleep)
-		mmc_deselect_cards(host);
+		mmc_deselect_cards(card->host);

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

@@ -74,7 +74,7 @@ int mmc_card_sleepawake(struct mmc_host *host, int sleep)
 		cmd.arg |= 1 << 15;

 	cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
-	err = mmc_wait_for_cmd(host, &cmd, 0);
+	err = mmc_wait_for_cmd(card->host, &cmd, 0);
 	if (err)
 		return err;

@@ -84,7 +84,7 @@ int mmc_card_sleepawake(struct mmc_host *host, int sleep)
 	 * SEND_STATUS command to poll the status because that command (and most
 	 * others) is invalid while the card sleeps.
 	 */
-	if (!(host->caps & MMC_CAP_WAIT_WHILE_BUSY))
+	if (!(card->host->caps & MMC_CAP_WAIT_WHILE_BUSY))
 		mmc_delay(DIV_ROUND_UP(card->ext_csd.sa_timeout, 10000));

 	if (!sleep)
@@ -325,14 +325,15 @@ int mmc_send_csd(struct mmc_card *card, u32 *csd)
 	return 0;
 }

-int mmc_send_cid(struct mmc_host *host, u32 *cid)
+int mmc_send_cid(struct mmc_host *host, unsigned int rca, u32 *cid)
 {
 	int ret, i;

+	if (!host)
+		return -EINVAL;
+
 	if (!mmc_host_is_spi(host)) {
-		if (!host->card)
-			return -EINVAL;
-		return mmc_send_cxd_native(host, host->card->rca << 16,
+		return mmc_send_cxd_native(host, rca << 16,
 				cid, MMC_SEND_CID);
 	}

diff --git a/drivers/mmc/core/mmc_ops.h b/drivers/mmc/core/mmc_ops.h
index 653eb8e..d0aee59 100644
--- a/drivers/mmc/core/mmc_ops.h
+++ b/drivers/mmc/core/mmc_ops.h
@@ -22,10 +22,10 @@ int mmc_send_csd(struct mmc_card *card, u32 *csd);
 int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd);
 int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value);
 int mmc_send_status(struct mmc_card *card, u32 *status);
-int mmc_send_cid(struct mmc_host *host, u32 *cid);
+int mmc_send_cid(struct mmc_host *host, unsigned int rca, u32 *cid);
 int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp);
 int mmc_spi_set_crc(struct mmc_host *host, int use_crc);
-int mmc_card_sleepawake(struct mmc_host *host, int sleep);
+int mmc_card_sleepawake(struct mmc_card *card, int sleep);

 #endif

diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index fdd414e..0889de2 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -366,7 +366,7 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
 	 * Fetch CID from card.
 	 */
 	if (mmc_host_is_spi(host))
-		err = mmc_send_cid(host, cid);
+		err = mmc_send_cid(host, 0, cid);
 	else
 		err = mmc_all_send_cid(host, cid);
 	if (err)
diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index 83f0aff..e3ad4cf 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -38,6 +38,12 @@
 #include <plat/mmc.h>
 #include <plat/cpu.h>

+#ifdef CONFIG_MMC_DEBUG
+#define mmc_dbg(fmt, arg...)	printk(KERN_DEBUG fmt, ##arg)
+#else
+#define mmc_dbg(fmt, arg...)
+#endif
+
 /* OMAP HSMMC Host Controller Registers */
 #define OMAP_HSMMC_SYSCONFIG	0x0010
 #define OMAP_HSMMC_SYSSTATUS	0x0014
@@ -56,6 +62,7 @@
 #define OMAP_HSMMC_IE		0x0134
 #define OMAP_HSMMC_ISE		0x0138
 #define OMAP_HSMMC_CAPA		0x0140
+#define OMAP_HSMMC_CUR_CAPA	0x0148

 #define VS18			(1 << 26)
 #define VS30			(1 << 25)
@@ -625,13 +632,13 @@ static int omap_hsmmc_context_restore(struct omap_hsmmc_host *host)
 		if (OMAP_MMC_MASTER_CLOCK / dsor > ios->clock)
 			dsor++;

-		if (dsor > 250)
-			dsor = 250;
+		if (dsor > 1023) /* Maximum of ratio 0x3FF */
+			dsor = 1023;
 	}

 	OMAP_HSMMC_WRITE(host->base, SYSCTL,
 		OMAP_HSMMC_READ(host->base, SYSCTL) & ~CEN);
-	OMAP_HSMMC_WRITE(host->base, SYSCTL, (dsor << 6) | (DTO << 16));
+	OMAP_HSMMC_WRITE(host->base, SYSCTL, (dsor << 6) | (DTO << DTO_SHIFT));
 	OMAP_HSMMC_WRITE(host->base, SYSCTL,
 		OMAP_HSMMC_READ(host->base, SYSCTL) | ICE);

@@ -816,6 +823,7 @@ omap_hsmmc_start_command(struct omap_hsmmc_host *host, struct mmc_command *cmd,

 	OMAP_HSMMC_WRITE(host->base, ARG, cmd->arg);
 	OMAP_HSMMC_WRITE(host->base, CMD, cmdreg);
+
 }

 static int
@@ -867,6 +875,52 @@ omap_hsmmc_xfer_done(struct omap_hsmmc_host *host, struct mmc_data *data)
 	omap_hsmmc_start_command(host, data->stop, NULL);
 }

+#ifdef CONFIG_MMC_DEBUG
+static const char *mmc_report_card_status(u32 status)
+{
+	/* It's the status come from the omap mmc controler */
+	/* --- means reserved bit without definition at documentation */
+	static const char *mmc_status_bits[] = {
+		"---", "---", "---", "---", "---", "APP_CMD", "---", "SW_ERROR",
+		"READY_4_DATA",
+		"---", "---", "---", "---", /* mmc_report_card_state */
+		
+		"ERASE_RST",  "---", "WP_ERASE_SKIP", "CID/CSD_OVR", "---","---",
+		"ERR", "CC_ERR", "CARD_ECC_FAILED", "ILLEGAL_CMD", "COM_CRC_ERR",
+		"(UN)LOCK_FAILED", "CARD_LOCKED", "WP_VIOLATION",
+		"ERASE_PARAM", "ERASE_SEQ_ERR", "BLK_LEN_ERR", "ADDR_MISCALIGN",
+		"ADDR_OUT_OF_RANGE",
+	};
+	static const char *mmc_state_bits[] = {
+			"S_IDLE", "S_READY","S_IDENT","S_STBY",
+			"S_TRAN","S_DATA","S_RCV","S_PRG","S_DIS",
+			"S_BTST","S_SLP","---", "---", "---", "---","---"
+	};
+
+	static char res[256];
+	char *buf = res;
+	int len, i;
+
+	len = sprintf(buf, "CARD status 0x%x :", status);
+	buf += len;
+
+	for (i = 0; i < ARRAY_SIZE(mmc_status_bits); i++) {
+		if (i>=9 && i<=12){
+			if (i==9){
+				len = sprintf(buf, " %s |", mmc_state_bits[status&0x0F]);
+				buf += len;
+			}
+		}
+		else {
+			if (status & (1 << i)) {
+				len = sprintf(buf, " %s |", mmc_status_bits[i]);
+				buf += len;
+			}
+		}
+	}
+	return res;
+}
+#endif /* CONFIG_MMC_DEBUG */
 /*
  * Notify the core about command completion
  */
@@ -882,9 +936,18 @@ omap_hsmmc_cmd_done(struct omap_hsmmc_host *host, struct mmc_command *cmd)
 			cmd->resp[2] = OMAP_HSMMC_READ(host->base, RSP32);
 			cmd->resp[1] = OMAP_HSMMC_READ(host->base, RSP54);
 			cmd->resp[0] = OMAP_HSMMC_READ(host->base, RSP76);
+			mmc_dbg("%s: "
+					"RSP10=0x%08x RSP32=0x%08x RSP54=0x%08x RSP76=0x%08x\n",
+					mmc_hostname(host->mmc),
+					cmd->resp[3],cmd->resp[2],cmd->resp[1],cmd->resp[0]);
+		
 		} else {
 			/* response types 1, 1b, 3, 4, 5, 6 */
 			cmd->resp[0] = OMAP_HSMMC_READ(host->base, RSP10);
+			mmc_dbg("%s: RSP10=0x%08x %s\n",
+					mmc_hostname(host->mmc),
+					cmd->resp[0],
+					mmc_report_card_status(cmd->resp[0]));
 		}
 	}
 	if ((host->data == NULL && !host->response_busy) || cmd->error) {
@@ -914,6 +977,7 @@ static void omap_hsmmc_dma_cleanup(struct omap_hsmmc_host *host, int errno)
  * Readable error output
  */
 #ifdef CONFIG_MMC_DEBUG
+
 static void omap_hsmmc_report_irq(struct omap_hsmmc_host *host, u32 status)
 {
 	/* --- means reserved bit without definition at documentation */
@@ -938,6 +1002,7 @@ static void omap_hsmmc_report_irq(struct omap_hsmmc_host *host, u32 status)

 	dev_dbg(mmc_dev(host->mmc), "%s\n", res);
 }
+
 #endif  /* CONFIG_MMC_DEBUG */

 /*
@@ -1539,13 +1604,13 @@ static void omap_hsmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 		if (OMAP_MMC_MASTER_CLOCK / dsor > ios->clock)
 			dsor++;

-		if (dsor > 250)
-			dsor = 250;
+		if (dsor > 1023) /* Maximum of ratio 0x3FF */
+			dsor = 1023;
 	}
 	omap_hsmmc_stop_clock(host);
 	regval = OMAP_HSMMC_READ(host->base, SYSCTL);
 	regval = regval & ~(CLKD_MASK);
-	regval = regval | (dsor << 6) | (DTO << 16);
+	regval = regval | (dsor << 6) | (DTO << DTO_SHIFT);
 	OMAP_HSMMC_WRITE(host->base, SYSCTL, regval);
 	OMAP_HSMMC_WRITE(host->base, SYSCTL,
 		OMAP_HSMMC_READ(host->base, SYSCTL) | ICE);
@@ -1921,7 +1986,8 @@ static int omap_hsmmc_regs_show(struct seq_file *s, void *data)
 			OMAP_HSMMC_READ(host->base, ISE));
 	seq_printf(s, "CAPA:\t\t0x%08x\n",
 			OMAP_HSMMC_READ(host->base, CAPA));
-
+	seq_printf(s, "CUR_CAPA:\t\t0x%08x\n",
+			OMAP_HSMMC_READ(host->base, CUR_CAPA));
 	clk_disable(host->fclk);

 	return 0;
@@ -2132,13 +2198,13 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev)
 	ret = request_irq(host->irq, omap_hsmmc_irq, IRQF_DISABLED,
 			mmc_hostname(mmc), host);
 	if (ret) {
-		dev_dbg(mmc_dev(host->mmc), "Unable to grab HSMMC IRQ\n");
+		dev_err(mmc_dev(host->mmc), "Unable to grab HSMMC IRQ\n");
 		goto err_irq;
 	}

 	if (pdata->init != NULL) {
 		if (pdata->init(&pdev->dev) != 0) {
-			dev_dbg(mmc_dev(host->mmc),
+			dev_err(mmc_dev(host->mmc),
 				"Unable to configure MMC IRQs\n");
 			goto err_irq_cd_init;
 		}
@@ -2161,7 +2227,7 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev)
 					  | IRQF_DISABLED,
 				  mmc_hostname(mmc), host);
 		if (ret) {
-			dev_dbg(mmc_dev(host->mmc),
+			dev_err(mmc_dev(host->mmc),
 				"Unable to grab MMC CD IRQ\n");
 			goto err_irq_cd;
 		}
diff --git a/arch/arm/mach-omap2/hsmmc.c b/arch/arm/mach-omap2/hsmmc.c
index 9ad2295..7996bcc 100644
--- a/arch/arm/mach-omap2/hsmmc.c
+++ b/arch/arm/mach-omap2/hsmmc.c
@@ -5,6 +5,11 @@
  * Copyright (C) 2008 Nokia Corporation
  * Author: Texas Instruments
  *
+ *
+ * 20100315
+ *          Laurent Epinat <laurent.epinat@xxxxxxxxxxxxxxx>
+ * Add 	cpu_is_omap34xx() for pbias1  (VMMCa1)
+ *
  * 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
  * published by the Free Software Foundation.
@@ -83,14 +88,23 @@ static void hsmmc1_before_set_reg(struct device *dev, int slot,
 			prog_io = omap_ctrl_readl(OMAP343X_CONTROL_PROG_IO1);
 			prog_io |= OMAP3630_PRG_SDMMC1_SPEEDCTRL;
 			omap_ctrl_writel(prog_io, OMAP343X_CONTROL_PROG_IO1);
-		} else {
+		}
+		else if (cpu_is_omap34xx()) {
+			reg &= 	~(OMAP343X_PBIASSPEEDCTRL1|OMAP2_PBIASSPEEDCTRL0);
+		}
+		else {
 			reg |= OMAP2_PBIASSPEEDCTRL0;
 		}
 		reg &= ~OMAP2_PBIASLITEPWRDNZ0;
+		if (cpu_is_omap34xx())
+			reg &= ~OMAP343X_PBIASLITEPWRDNZ1;
 		omap_ctrl_writel(reg, control_pbias_offset);
 	} else {
 		reg = omap_ctrl_readl(control_pbias_offset);
 		reg &= ~OMAP2_PBIASLITEPWRDNZ0;
+		if (cpu_is_omap34xx())
+			reg &= ~OMAP343X_PBIASLITEPWRDNZ1;
+
 		omap_ctrl_writel(reg, control_pbias_offset);
 	}
 }
@@ -106,15 +120,29 @@ static void hsmmc1_after_set_reg(struct device *dev, int slot,
 	if (power_on) {
 		reg = omap_ctrl_readl(control_pbias_offset);
 		reg |= (OMAP2_PBIASLITEPWRDNZ0 | OMAP2_PBIASSPEEDCTRL0);
-		if ((1 << vdd) <= MMC_VDD_165_195)
+		if (cpu_is_omap34xx()) {
+			reg |= 	(OMAP343X_PBIASLITEPWRDNZ1 | OMAP343X_PBIASSPEEDCTRL1);
+		}
+		if ((1 << vdd) <= MMC_VDD_165_195) {
 			reg &= ~OMAP2_PBIASLITEVMODE0;
-		else
+			if (cpu_is_omap34xx()) {
+				reg &= ~OMAP343X_PBIASLITEVMODE1;
+			}
+		}
+		else {
 			reg |= OMAP2_PBIASLITEVMODE0;
+			if (cpu_is_omap34xx()) {
+				reg |= OMAP343X_PBIASLITEVMODE1;
+			}
+		}
 		omap_ctrl_writel(reg, control_pbias_offset);
 	} else {
 		reg = omap_ctrl_readl(control_pbias_offset);
 		reg |= (OMAP2_PBIASSPEEDCTRL0 | OMAP2_PBIASLITEPWRDNZ0 |
 			OMAP2_PBIASLITEVMODE0);
+		if (cpu_is_omap34xx())
+			reg |= 	(OMAP343X_PBIASSPEEDCTRL1 | OMAP343X_PBIASLITEPWRDNZ1 |
+						OMAP343X_PBIASLITEVMODE1);
 		omap_ctrl_writel(reg, control_pbias_offset);
 	}
 }
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index eaf3636..b925265 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -182,7 +182,12 @@ struct mmc_host {
 	unsigned int		disable_delay;	/* disable delay in msecs */
 	struct delayed_work	disable;	/* disabling work */

-	struct mmc_card		*card;		/* device attached to this host */
+#ifdef CONFIG_MULTI_MMC_ON_HOST
+#define MMC_MAX_CARD	64		/* spec ~40 in same host ? */
+	struct mmc_card *cards[MMC_MAX_CARD];/* devices attached to this host */
+	int  card_detected;
+#endif
+	struct mmc_card *card;			/* Keep for compatibility SD, SDIO, ...*/

 	wait_queue_head_t	wq;
 	struct task_struct	*claimer;	/* task that has host claimed */
---



Le 24.03.2010 16:35, Madhusudhan a écrit :


-----Original Message-----
From: Nishanth Menon [mailto:nm@xxxxxx]
Sent: Tuesday, March 23, 2010 5:49 PM
To: Tony Lindgren
Cc: Pais, Allen; linux-arm-kernel@xxxxxxxxxxxxxxxxxxx; linux-
omap@xxxxxxxxxxxxxxx; Pandita, Vikram; Madhusudhan Chikkature Rajashekar
Subject: mmc errors (was Re: [PATCH] arm: Fix DEBUG_LL for omap zoom2/3)

Tony Lindgren had written, on 03/23/2010 10:27 AM, the following:
[...]
Then at least one issue remains for zoom3 to be usable..
I'm getting tons of MMC errors trying to mount root on it:

mmcblk1: error -110 transferring data, sector 2097024, nr 8, card status
0x900
end_request: I/O error, dev mmcblk1, sector 2097024
...

I have seen this on few platforms and seem to be related to eMMC usage.

Any ideas if that's fixed somewhere also?
Madhu, any comments?

Sorry about multiple replies to this mail. Just wanted to avoid top posting.

The eMMC on Zoom2 has an issue with respect to detection as a high
capacity card. This was discussed on the list with Pierre sometime back. I
don't have an acceptable solution to make this device work. Rather I
prefer to submit a patch which disables MMC2 on these boards.

You can still use MMC1 to mount your file system. This is the card you can
plug in to the cage.

Regards,
Madhu

--
Regards,
Nishanth Menon

--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




--

Salutations
Laurent Epinat -> mailto:laurent.epinat@xxxxxxxxxxxxxxx

CIO Informatique
Le millenium
1, rue de Presse - BP 710
42950 Saint-Etienne Cedex 9

Tel    33 (0) 477 93 34 32
Tcopie 33 (0) 477 79 75 55
WWW : http://www.cioinfoindus.fr/
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Arm (vger)]     [ARM Kernel]     [ARM MSM]     [Linux Tegra]     [Linux WPAN Networking]     [Linux Wireless Networking]     [Maemo Users]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite Trails]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux