linux-spi.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: David Brownell <david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>
To: Pierre Ossman <drzeus-mmc-p3sGCRWkH8CeZLLa646FqQ@public.gmane.org>
Cc: Hans-Peter Nilsson
	<hans-peter.nilsson-VrBV9hrLPhE@public.gmane.org>,
	Mikael Starvik <mikael.starvik-VrBV9hrLPhE@public.gmane.org>,
	Mike Lavender
	<mike-UTnDXsALFwNjMdQLN6DIHgC/G2K4zDHf@public.gmane.org>,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org
Subject: Re: [patch 2.6.22-git5 3/4] MMC core learns about SPI
Date: Thu, 26 Jul 2007 14:58:54 -0700	[thread overview]
Message-ID: <200707261458.55558.david-b@pacbell.net> (raw)
In-Reply-To: <20070726191824.569542fd-mgABNEgzgxm+PRNnhPf8W5YgPPQkE1Si@public.gmane.org>

On Thursday 26 July 2007, Pierre Ossman wrote:
> On Sat, 14 Jul 2007 15:07:16 -0700
> David Brownell <david-b@pacbell.net> wrote:
> 
> > @@ -541,7 +548,9 @@ void mmc_rescan(struct work_struct *work
> >  
> >  		err = mmc_send_app_op_cond(host, 0, &ocr);
> >  		if (err == MMC_ERR_NONE) {
> > -			if (mmc_attach_sd(host, ocr))
> > +			if (mmc_host_is_spi(host))
> > +				err = mmc_spi_read_ocr(host, &ocr);
> > +			if (err != MMC_ERR_NONE || mmc_attach_sd(host, ocr))
> >  				mmc_power_off(host);
> >  		} else {
> >  			/*
> 
> Getting the OCR is not vital to determine if it's SD or MMC, so
> we can move that into mmc.c and sd.c, reducing the code in here.

Yes we could ... but this way is IMO simpler, since it retains
a simple invariant:  that the OCR parameter to attach() methods
is always valid.  As one would expect!  Which gives another
advantage:  no surprises.

 
> > @@ -550,7 +559,10 @@ void mmc_rescan(struct work_struct *work
> >  			 */
> >  			err = mmc_send_op_cond(host, 0, &ocr);
> >  			if (err == MMC_ERR_NONE) {
> > -				if (mmc_attach_mmc(host, ocr))
> > +				if (mmc_host_is_spi(host))
> > +					err = mmc_spi_read_ocr(host, &ocr);
> > +				if (err != MMC_ERR_NONE
> > +						|| mmc_attach_mmc(host, ocr))
> >  					mmc_power_off(host);
> >  			} else {
> >  				mmc_power_off(host);
> 
> This will fail to initialise a high capacity MMC card. From the MMC spec:
> 
> "Without the CMD58 with bits [30:29] set as "10b" in prior to the CMD1 a
> higher than 2GB of density of memory will remain in Idle state forever." 

The first thing mmc_attach_mmc() does is reset the card...

Are you sure that "forever" means that reset will fail?
That would be a very foolish thing to specify.  And while
I've seen strange things in specs, that would be one of
the worst that's not a vendor-specific part of a papering
over errata ...

I'd be inclined to leave this alone unless someone gets
such a card and notices that it doesn't work.  After all,
lack of testing on those new (and-I-still-can't-find-one)
cards is a general disclaimer.


> > @@ -95,14 +106,18 @@ int mmc_send_op_cond(struct mmc_host *ho
> >  
> >  	cmd.opcode = MMC_SEND_OP_COND;
> >  	cmd.arg = ocr;
> 
> Argument is "None", not "Ignored", so this should be 0 for SPI.

Indeed.  The specs would make more sense if they said "zero"
in such cases, so the language isn't in conflict with the
day-to-day/commonsense uses of those words!


> > -	mmc_set_data_timeout(&data, card, 0);
> > +	/* Note that for MMC_SEND_EXT_CSD we could set the timeout; but
> > +	 * not for the other requests. But host->card isn't set yet!
> > +	 */
> >  
> 
> This will break on native hosts as a timeout of 0 means exactly that.

Urgh.  OK; I just grew the parameter list by one more member,
which is NULL before there's a card.  (You might consider
setting host->card earlier...)


> > +
> > +int mmc_spi_send_cid(struct mmc_host *host, u32 *cid)
> > +{
> > +	if (!mmc_host_is_spi(host))
> > +		return mmc_send_cxd_native(host, 0, cid, MMC_SEND_CID);
> > +
> > +	return mmc_send_cxd_data(host, MMC_SEND_CID, cid, 16);
> > +}
> > +
> 
> As this is not SPI specific (except for its current use), why not mmc_send_cid() ?
> 
> And the argument for it is the RCA (in native mode).

OK ... renamed, and passed "rca << 16".  At least, if host->card
has been set, which only happens *after* the enumeration sequence
needs to fetch the CID ... which is done before it knows whether
to create a card struct or not.  (The SEND_ALL_CID request is used
for non-SPI hosts.)


> > +
> > +/* Enabling software CRCs can be a significant (30%) performance cost,
> > + * and for other reasons isn't always desired; so it can be disabled.
> > + */
> > +static int use_spi_crc = 1;
> > +module_param(use_spi_crc, bool, 0);
> > +
> 
> The *_ops.c only contain function wrappers of protocol commands, not
> policy. So I think this is better placed where mmc_spi_set_crc() is called. 

You mean, have separate module params for SD and for MMC?
It seems cleaner this way...


> > --- g26.orig/drivers/mmc/core/mmc.c	2007-07-14 14:47:12.000000000 -0700
> > +++ g26/drivers/mmc/core/mmc.c	2007-07-14 14:47:54.000000000 -0700
> > @@ -264,7 +264,13 @@ static int mmc_init_card(struct mmc_host
> >  	/*
> >  	 * Fetch CID from card.
> >  	 */
> > -	err = mmc_all_send_cid(host, cid);
> > +	if (mmc_host_is_spi(host)) {
> > +		err = mmc_spi_set_crc(host);
> > +		if (err != MMC_ERR_NONE)
> > +			goto err;
> > +		err = mmc_spi_send_cid(host, cid);
> > +	} else
> > +		err = mmc_all_send_cid(host, cid);
> >  	if (err != MMC_ERR_NONE)
> >  		goto err;
> >  
> 
> A matter of taste, but wouldn't it be clearer if you separated out
> the crc bit and did that earlier, before the above comment?
>	[ ditto for SD ]

OK.  The comment probably should have been updated, but I'd expect
GCC will merge the two adjacent "if (it's spi)" blocks which will
be the result.


> > --- g26.orig/drivers/mmc/core/sd_ops.c	2007-07-14 14:47:12.000000000 -0700
> > +++ g26/drivers/mmc/core/sd_ops.c	2007-07-14 14:47:54.000000000 -0700
> > @@ -70,6 +70,12 @@ int mmc_wait_for_app_cmd(struct mmc_host
> >  		err = cmd->error;
> >  		if (cmd->error == MMC_ERR_NONE)
> >  			break;
> > +
> > +		/* no point in retrying illegal commands! */
> > +		if (mmc_host_is_spi(host)) {
> > +			if (cmd->resp[0] & R1_SPI_ILLEGAL_COMMAND)
> > +				break;
> > +		}
> >  	}
> >  
> >  	return err;
> 
> "Illegal command" refers to the previous command sent (and failed).
> So this can give false negatives. 

The immediately preceding command would be MMC_APP_CMD ... ?
I didn't see any language in the specs which could let me
interpret this as anything other than APP_CMD failure:

   When an error bit is detected in “R” mode the card will
   report the error in the response to the command that raised
   the exception. The command will not be executed and the
   associated state transition will not take place. 

What this does is to quickly abort retries of SD card ops
that were sent to MMC cards, and which always fail with
ILLEGAL_COMMAND.

- Dave


========	CUT HERE
Teach the MMC/SD/SDIO core about using SPI mode.

 - Use mmc_host_is_spi() so enumeration works through SPI signaling
   and protocols, not just the native versions.

 - Provide the SPI response type flags with each request issued,
   including requests from the new lock/unlock code.

 - Understand that some commands act a bit differently ... notably:
     * OP_COND command reports busy status differently
     * OP_COND command doesn't return the OCR
     * APP_CMD status doesn't have an R1_APP_CMD analogue

 - Understand that cmd->resp[0] and mmc_get_status() results for SPI
   return different values than for "native" MMC/SD protocol; this
   affects checking card lock status, and some others.

Those changes required some new and updated primitives:

 - Provide utilities to access two SPI-only requests, and one
   request that wasn't previously needed:
     * mmc_spi_read_ocr() ... SPI only
     * mmc_spi_set_crc() ... SPI only (override by module parm)
     * mmc_spi_send_cid() ... works without broadcast mode

 - Updated internal routines:
     * Previous mmc_send_csd() modified into mmc_send_cxd_native();
       it uses native "R2" responses, which include 16 bytes of data.
     * Previous mmc_send_ext_csd() becomes new mmc_send_cxd_data()
       helper for command-and-data access
     * Bugfix to that mmc_send_cxd_data() code:  dma-to-stack is
       unsafe/nonportable, so kmalloc a bounce buffer instead.

 - Modified mmc_send_ext_csd() now uses mmc_send_cxd_data() helper

 - Modified mmc_send_csd(), and new mmc_spi_send_cid(), routines use
   those helper routines based on whether they're native or SPI

The SPI support hasn't been tested on the new MMC4 cards (they're not
widely available); likewise SD cards with 4GB and up may have surprises
lurking.

Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
---
 drivers/mmc/core/core.c    |   24 ++++--
 drivers/mmc/core/mmc.c     |   39 +++++++---
 drivers/mmc/core/mmc_ops.c |  165 ++++++++++++++++++++++++++++++++++++---------
 drivers/mmc/core/mmc_ops.h |    3 
 drivers/mmc/core/sd.c      |   37 +++++++---
 drivers/mmc/core/sd_ops.c  |   32 ++++++--
 6 files changed, 232 insertions(+), 68 deletions(-)

--- g26.orig/drivers/mmc/core/mmc_ops.h	2007-07-26 13:13:23.000000000 -0700
+++ g26/drivers/mmc/core/mmc_ops.h	2007-07-26 14:54:35.000000000 -0700
@@ -22,6 +22,9 @@ int mmc_send_csd(struct mmc_card *card, 
 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_spi_read_ocr(struct mmc_host *host, u32 *ocrp);
+int mmc_spi_set_crc(struct mmc_host *host);
 
 #endif
 
--- g26.orig/drivers/mmc/core/core.c	2007-07-26 13:13:24.000000000 -0700
+++ g26/drivers/mmc/core/core.c	2007-07-26 14:54:35.000000000 -0700
@@ -404,8 +404,13 @@ static void mmc_power_up(struct mmc_host
 	int bit = fls(host->ocr_avail) - 1;
 
 	host->ios.vdd = bit;
-	host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
-	host->ios.chip_select = MMC_CS_DONTCARE;
+	if (mmc_host_is_spi(host)) {
+		host->ios.chip_select = MMC_CS_HIGH;
+		host->ios.bus_mode = MMC_BUSMODE_PUSHPULL;
+	} else {
+		host->ios.chip_select = MMC_CS_DONTCARE;
+		host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
+	}
 	host->ios.power_mode = MMC_POWER_UP;
 	host->ios.bus_width = MMC_BUS_WIDTH_1;
 	host->ios.timing = MMC_TIMING_LEGACY;
@@ -424,8 +429,10 @@ static void mmc_power_off(struct mmc_hos
 {
 	host->ios.clock = 0;
 	host->ios.vdd = 0;
-	host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
-	host->ios.chip_select = MMC_CS_DONTCARE;
+	if (!mmc_host_is_spi(host)) {
+		host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
+		host->ios.chip_select = MMC_CS_DONTCARE;
+	}
 	host->ios.power_mode = MMC_POWER_OFF;
 	host->ios.bus_width = MMC_BUS_WIDTH_1;
 	host->ios.timing = MMC_TIMING_LEGACY;
@@ -541,7 +548,9 @@ void mmc_rescan(struct work_struct *work
 
 		err = mmc_send_app_op_cond(host, 0, &ocr);
 		if (err == MMC_ERR_NONE) {
-			if (mmc_attach_sd(host, ocr))
+			if (mmc_host_is_spi(host))
+				err = mmc_spi_read_ocr(host, &ocr);
+			if (err != MMC_ERR_NONE || mmc_attach_sd(host, ocr))
 				mmc_power_off(host);
 		} else {
 			/*
@@ -550,7 +559,10 @@ void mmc_rescan(struct work_struct *work
 			 */
 			err = mmc_send_op_cond(host, 0, &ocr);
 			if (err == MMC_ERR_NONE) {
-				if (mmc_attach_mmc(host, ocr))
+				if (mmc_host_is_spi(host))
+					err = mmc_spi_read_ocr(host, &ocr);
+				if (err != MMC_ERR_NONE
+						|| mmc_attach_mmc(host, ocr))
 					mmc_power_off(host);
 			} else {
 				mmc_power_off(host);
--- g26.orig/drivers/mmc/core/mmc_ops.c	2007-07-26 13:13:23.000000000 -0700
+++ g26/drivers/mmc/core/mmc_ops.c	2007-07-26 14:54:35.000000000 -0700
@@ -63,23 +63,34 @@ int mmc_go_idle(struct mmc_host *host)
 	int err;
 	struct mmc_command cmd;
 
-	mmc_set_chip_select(host, MMC_CS_HIGH);
-
-	mmc_delay(1);
+	/*
+	 * Non-SPI hosts need to prevent chipselect going active during
+	 * GO_IDLE; that would put chips into SPI mode.  Remind them of
+	 * that in case of hardware that won't pull up DAT3/nCS otherwise.
+	 *
+	 * SPI hosts ignore ios.chip_select; it's managed according to
+	 * rules that must accomodate non-MMC slaves which this layer
+	 * won't even know about.
+	 */
+	if (!mmc_host_is_spi(host)) {
+		mmc_set_chip_select(host, MMC_CS_HIGH);
+		mmc_delay(1);
+	}
 
 	memset(&cmd, 0, sizeof(struct mmc_command));
 
 	cmd.opcode = MMC_GO_IDLE_STATE;
 	cmd.arg = 0;
-	cmd.flags = MMC_RSP_NONE | MMC_CMD_BC;
+	cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_NONE | MMC_CMD_BC;
 
 	err = mmc_wait_for_cmd(host, &cmd, 0);
 
 	mmc_delay(1);
 
-	mmc_set_chip_select(host, MMC_CS_DONTCARE);
-
-	mmc_delay(1);
+	if (!mmc_host_is_spi(host)) {
+		mmc_set_chip_select(host, MMC_CS_DONTCARE);
+		mmc_delay(1);
+	}
 
 	return err;
 }
@@ -94,15 +105,19 @@ int mmc_send_op_cond(struct mmc_host *ho
 	memset(&cmd, 0, sizeof(struct mmc_command));
 
 	cmd.opcode = MMC_SEND_OP_COND;
-	cmd.arg = ocr;
-	cmd.flags = MMC_RSP_R3 | MMC_CMD_BCR;
+	cmd.arg = mmc_host_is_spi(host) ? 0 : ocr;
+	cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R3 | MMC_CMD_BCR;
 
 	for (i = 100; i; i--) {
 		err = mmc_wait_for_cmd(host, &cmd, 0);
 		if (err != MMC_ERR_NONE)
 			break;
 
-		if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0)
+		if (mmc_host_is_spi(host)) {
+			/* wait until reset completes */
+			if (!(cmd.resp[0] & R1_SPI_IDLE))
+				break;
+		} else if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0)
 			break;
 
 		err = MMC_ERR_TIMEOUT;
@@ -110,7 +125,7 @@ int mmc_send_op_cond(struct mmc_host *ho
 		mmc_delay(10);
 	}
 
-	if (rocr)
+	if (rocr && !mmc_host_is_spi(host))
 		*rocr = cmd.resp[0];
 
 	return err;
@@ -160,40 +175,46 @@ int mmc_set_relative_addr(struct mmc_car
 	return MMC_ERR_NONE;
 }
 
-int mmc_send_csd(struct mmc_card *card, u32 *csd)
+static int
+mmc_send_cxd_native(struct mmc_host *host, u32 arg, u32 *cxd, int opcode)
 {
 	int err;
 	struct mmc_command cmd;
 
-	BUG_ON(!card);
-	BUG_ON(!card->host);
-	BUG_ON(!csd);
+	BUG_ON(!host);
+	BUG_ON(!cxd);
 
 	memset(&cmd, 0, sizeof(struct mmc_command));
 
-	cmd.opcode = MMC_SEND_CSD;
-	cmd.arg = card->rca << 16;
+	cmd.opcode = opcode;
+	cmd.arg = arg;
 	cmd.flags = MMC_RSP_R2 | MMC_CMD_AC;
 
-	err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES);
+	err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES);
 	if (err != MMC_ERR_NONE)
 		return err;
 
-	memcpy(csd, cmd.resp, sizeof(u32) * 4);
+	memcpy(cxd, cmd.resp, sizeof(u32) * 4);
 
 	return MMC_ERR_NONE;
 }
 
-int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd)
+static int
+mmc_send_cxd_data(struct mmc_card *card, struct mmc_host *host,
+		u32 opcode, void *buf, unsigned len)
 {
 	struct mmc_request mrq;
 	struct mmc_command cmd;
 	struct mmc_data data;
 	struct scatterlist sg;
+	void *data_buf;
 
-	BUG_ON(!card);
-	BUG_ON(!card->host);
-	BUG_ON(!ext_csd);
+	/* dma onto stack is unsafe/nonportable, but callers here
+	 * normally provide temporary on-stack buffers.
+	 */
+	data_buf = kmalloc(len, GFP_KERNEL);
+	if (data_buf == NULL)
+		return -ENOMEM;
 
 	memset(&mrq, 0, sizeof(struct mmc_request));
 	memset(&cmd, 0, sizeof(struct mmc_command));
@@ -202,21 +223,31 @@ int mmc_send_ext_csd(struct mmc_card *ca
 	mrq.cmd = &cmd;
 	mrq.data = &data;
 
-	cmd.opcode = MMC_SEND_EXT_CSD;
+	cmd.opcode = opcode;
 	cmd.arg = 0;
-	cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
 
-	data.blksz = 512;
+	/* NOTE HACK:  the MMC_RSP_SPI_R1 is always correct here, but we
+	 * rely on callers to never use this with "native" calls for reading
+	 * CSD or CID.  Native versions of those commands use the R2 type,
+	 * not R1 plus a data block.
+	 */
+	cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
+
+	data.blksz = len;
 	data.blocks = 1;
 	data.flags = MMC_DATA_READ;
 	data.sg = &sg;
 	data.sg_len = 1;
 
-	sg_init_one(&sg, ext_csd, 512);
+	sg_init_one(&sg, data_buf, len);
 
-	mmc_set_data_timeout(&data, card, 0);
+	if (card)
+		mmc_set_data_timeout(&data, card, 0);
 
-	mmc_wait_for_req(card->host, &mrq);
+	mmc_wait_for_req(host, &mrq);
+
+	memcpy(buf, data_buf, len);
+	kfree(data_buf);
 
 	if (cmd.error != MMC_ERR_NONE)
 		return cmd.error;
@@ -226,6 +257,72 @@ int mmc_send_ext_csd(struct mmc_card *ca
 	return MMC_ERR_NONE;
 }
 
+int mmc_send_csd(struct mmc_card *card, u32 *csd)
+{
+	if (!mmc_host_is_spi(card->host))
+		return mmc_send_cxd_native(card->host, card->rca << 16,
+				csd, MMC_SEND_CSD);
+
+	return mmc_send_cxd_data(card, card->host, MMC_SEND_CSD, csd, 16);
+}
+
+int mmc_send_cid(struct mmc_host *host, u32 *cid)
+{
+	if (!mmc_host_is_spi(host)) {
+		if (!host->card)
+			return MMC_ERR_INVALID;
+		return mmc_send_cxd_native(host->card, host->card->rca << 16,
+				cid, MMC_SEND_CID);
+	}
+
+	return mmc_send_cxd_data(NULL, host, MMC_SEND_CID, cid, 16);
+}
+
+int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd)
+{
+	return mmc_send_cxd_data(card, card->host, MMC_SEND_EXT_CSD,
+			ext_csd, 512);
+}
+
+int mmc_spi_read_ocr(struct mmc_host *host, u32 *ocrp)
+{
+	struct mmc_command cmd;
+	int err;
+
+	memset(&cmd, 0, sizeof(struct mmc_command));
+
+	cmd.opcode = MMC_SPI_READ_OCR;
+	cmd.flags = MMC_RSP_SPI_R3;
+
+	err = mmc_wait_for_cmd(host, &cmd, 0);
+
+	*ocrp = cmd.resp[1];
+	return err;
+}
+
+/* Enabling software CRCs can be a significant (30%) performance cost,
+ * and for other reasons isn't always desired; so it can be disabled.
+ */
+static int use_spi_crc = 1;
+module_param(use_spi_crc, bool, 0);
+
+int mmc_spi_set_crc(struct mmc_host *host)
+{
+	struct mmc_command cmd;
+	int err;
+
+	memset(&cmd, 0, sizeof(struct mmc_command));
+
+	cmd.opcode = MMC_SPI_CRC_ON_OFF;
+	cmd.flags = MMC_RSP_SPI_R1;
+	cmd.arg = use_spi_crc;
+
+	err = mmc_wait_for_cmd(host, &cmd, 0);
+	if (err == MMC_ERR_NONE)
+		host->use_spi_crc = use_spi_crc;
+	return err;
+}
+
 int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value)
 {
 	int err;
@@ -241,7 +338,7 @@ int mmc_switch(struct mmc_card *card, u8
 		  (index << 16) |
 		  (value << 8) |
 		  set;
-	cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
+	cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
 
 	err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES);
 	if (err != MMC_ERR_NONE)
@@ -261,13 +358,17 @@ int mmc_send_status(struct mmc_card *car
 	memset(&cmd, 0, sizeof(struct mmc_command));
 
 	cmd.opcode = MMC_SEND_STATUS;
-	cmd.arg = card->rca << 16;
-	cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
+	if (!mmc_host_is_spi(card->host))
+		cmd.arg = card->rca << 16;
+	cmd.flags = MMC_RSP_SPI_R2 | MMC_RSP_R1 | MMC_CMD_AC;
 
 	err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES);
 	if (err != MMC_ERR_NONE)
 		return err;
 
+	/* NOTE: callers are required to understand the difference
+	 * between "native" and SPI format status words!
+	 */
 	if (status)
 		*status = cmd.resp[0];
 
--- g26.orig/drivers/mmc/core/mmc.c	2007-07-26 13:13:24.000000000 -0700
+++ g26/drivers/mmc/core/mmc.c	2007-07-26 14:54:35.000000000 -0700
@@ -262,9 +262,21 @@ static int mmc_init_card(struct mmc_host
 		goto err;
 
 	/*
+	 * For SPI, enable CRC as appropriate.
+	 */
+	if (mmc_host_is_spi(host)) {
+		err = mmc_spi_set_crc(host);
+		if (err != MMC_ERR_NONE)
+			goto err;
+	}
+
+	/*
 	 * Fetch CID from card.
 	 */
-	err = mmc_all_send_cid(host, cid);
+	if (mmc_host_is_spi(host))
+		err = mmc_send_cid(host, cid);
+	else
+		err = mmc_all_send_cid(host, cid);
 	if (err != MMC_ERR_NONE)
 		goto err;
 
@@ -287,13 +299,15 @@ static int mmc_init_card(struct mmc_host
 	}
 
 	/*
-	 * Set card RCA.
+	 * For native busses:  set card RCA and leave open drain mode.
 	 */
-	err = mmc_set_relative_addr(card);
-	if (err != MMC_ERR_NONE)
-		goto free_card;
+	if (!mmc_host_is_spi(host)) {
+		err = mmc_set_relative_addr(card);
+		if (err != MMC_ERR_NONE)
+			goto free_card;
 
-	mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL);
+		mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL);
+	}
 
 	if (!oldcard) {
 		/*
@@ -314,13 +328,15 @@ static int mmc_init_card(struct mmc_host
 	/*
 	 * Select card, as all following commands rely on that.
 	 */
-	err = mmc_select_card(card);
-	if (err != MMC_ERR_NONE)
-		goto free_card;
+	if (!mmc_host_is_spi(host)) {
+		err = mmc_select_card(card);
+		if (err != MMC_ERR_NONE)
+			goto free_card;
+	}
 
 	if (!oldcard) {
 		/*
-		 * Fetch and process extened CSD.
+		 * Fetch and process extended CSD.
 		 */
 		err = mmc_read_ext_csd(card);
 		if (err != MMC_ERR_NONE)
@@ -480,7 +496,8 @@ static void mmc_suspend(struct mmc_host 
 	BUG_ON(!host->card);
 
 	mmc_claim_host(host);
-	mmc_deselect_cards(host);
+	if (!mmc_host_is_spi(host))
+		mmc_deselect_cards(host);
 	host->card->state &= ~MMC_STATE_HIGHSPEED;
 	mmc_release_host(host);
 }
--- g26.orig/drivers/mmc/core/sd.c	2007-07-26 13:13:23.000000000 -0700
+++ g26/drivers/mmc/core/sd.c	2007-07-26 14:54:35.000000000 -0700
@@ -319,9 +319,21 @@ static int mmc_sd_init_card(struct mmc_h
 		goto err;
 
 	/*
+	 * For SPI, enable CRC as appropriate.
+	 */
+	if (mmc_host_is_spi(host)) {
+		err = mmc_spi_set_crc(host);
+		if (err != MMC_ERR_NONE)
+			goto err;
+	}
+
+	/*
 	 * Fetch CID from card.
 	 */
-	err = mmc_all_send_cid(host, cid);
+	if (mmc_host_is_spi(host))
+		err = mmc_send_cid(host, cid);
+	else
+		err = mmc_all_send_cid(host, cid);
 	if (err != MMC_ERR_NONE)
 		goto err;
 
@@ -343,13 +355,15 @@ static int mmc_sd_init_card(struct mmc_h
 	}
 
 	/*
-	 * Set card RCA.
+	 * For native busses:  get card RCA and leave open drain mode.
 	 */
-	err = mmc_send_relative_addr(host, &card->rca);
-	if (err != MMC_ERR_NONE)
-		goto free_card;
+	if (!mmc_host_is_spi(host)) {
+		err = mmc_send_relative_addr(host, &card->rca);
+		if (err != MMC_ERR_NONE)
+			goto free_card;
 
-	mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL);
+		mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL);
+	}
 
 	if (!oldcard) {
 		/*
@@ -369,9 +383,11 @@ static int mmc_sd_init_card(struct mmc_h
 	/*
 	 * Select card, as all following commands rely on that.
 	 */
-	err = mmc_select_card(card);
-	if (err != MMC_ERR_NONE)
-		goto free_card;
+	if (!mmc_host_is_spi(host)) {
+		err = mmc_select_card(card);
+		if (err != MMC_ERR_NONE)
+			goto free_card;
+	}
 
 	if (!oldcard) {
 		/*
@@ -554,7 +570,8 @@ static void mmc_sd_suspend(struct mmc_ho
 	BUG_ON(!host->card);
 
 	mmc_claim_host(host);
-	mmc_deselect_cards(host);
+	if (!mmc_host_is_spi(host))
+		mmc_deselect_cards(host);
 	host->card->state &= ~MMC_STATE_HIGHSPEED;
 	mmc_release_host(host);
 }
--- g26.orig/drivers/mmc/core/sd_ops.c	2007-07-26 13:13:24.000000000 -0700
+++ g26/drivers/mmc/core/sd_ops.c	2007-07-26 14:54:35.000000000 -0700
@@ -70,6 +70,12 @@ int mmc_wait_for_app_cmd(struct mmc_host
 		err = cmd->error;
 		if (cmd->error == MMC_ERR_NONE)
 			break;
+
+		/* no point in retrying illegal commands! */
+		if (mmc_host_is_spi(host)) {
+			if (cmd->resp[0] & R1_SPI_ILLEGAL_COMMAND)
+				break;
+		}
 	}
 
 	return err;
@@ -89,10 +95,10 @@ int mmc_app_cmd(struct mmc_host *host, s
 
 	if (card) {
 		cmd.arg = card->rca << 16;
-		cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
+		cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
 	} else {
 		cmd.arg = 0;
-		cmd.flags = MMC_RSP_R1 | MMC_CMD_BCR;
+		cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_BCR;
 	}
 
 	err = mmc_wait_for_cmd(host, &cmd, 0);
@@ -100,8 +106,8 @@ int mmc_app_cmd(struct mmc_host *host, s
 		return err;
 
 	/* Check that card supported application commands */
-	if (!(cmd.resp[0] & R1_APP_CMD))
-		return MMC_ERR_FAILED;
+	if (!mmc_host_is_spi(host) && !(cmd.resp[0] & R1_APP_CMD))
+		return (u32)-1;
 
 	return MMC_ERR_NONE;
 }
@@ -148,14 +154,18 @@ int mmc_send_app_op_cond(struct mmc_host
 
 	cmd.opcode = SD_APP_OP_COND;
 	cmd.arg = ocr;
-	cmd.flags = MMC_RSP_R3 | MMC_CMD_BCR;
+	cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R3 | MMC_CMD_BCR;
 
 	for (i = 100; i; i--) {
 		err = mmc_wait_for_app_cmd(host, NULL, &cmd, MMC_CMD_RETRIES);
 		if (err != MMC_ERR_NONE)
 			break;
 
-		if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0)
+		if (mmc_host_is_spi(host)) {
+			/* wait until reset completes */
+			if (!(cmd.resp[0] & R1_SPI_IDLE))
+				break;
+		} else if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0)
 			break;
 
 		err = MMC_ERR_TIMEOUT;
@@ -182,7 +192,7 @@ int mmc_send_if_cond(struct mmc_host *ho
 	 */
 	cmd.opcode = SD_SEND_IF_COND;
 	cmd.arg = ((ocr & 0xFF8000) != 0) << 8 | test_pattern;
-	cmd.flags = MMC_RSP_R7 | MMC_CMD_BCR;
+	cmd.flags = MMC_RSP_SPI_R7 | MMC_RSP_R7 | MMC_CMD_BCR;
 
 	err = mmc_wait_for_cmd(host, &cmd, 0);
 	if (err != MMC_ERR_NONE)
@@ -229,6 +239,8 @@ int mmc_app_send_scr(struct mmc_card *ca
 	BUG_ON(!card->host);
 	BUG_ON(!scr);
 
+	/* NOTE: caller guarantees scr is heap-allocated */
+
 	err = mmc_app_cmd(card->host, card);
 	if (err != MMC_ERR_NONE)
 		return err;
@@ -242,7 +254,7 @@ int mmc_app_send_scr(struct mmc_card *ca
 
 	cmd.opcode = SD_APP_SEND_SCR;
 	cmd.arg = 0;
-	cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
+	cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
 
 	data.blksz = 8;
 	data.blocks = 1;
@@ -278,6 +290,8 @@ int mmc_sd_switch(struct mmc_card *card,
 	BUG_ON(!card);
 	BUG_ON(!card->host);
 
+	/* NOTE: caller guarantees resp is heap-allocated */
+
 	mode = !!mode;
 	value &= 0xF;
 
@@ -292,7 +306,7 @@ int mmc_sd_switch(struct mmc_card *card,
 	cmd.arg = mode << 31 | 0x00FFFFFF;
 	cmd.arg &= ~(0xF << (group * 4));
 	cmd.arg |= value << (group * 4);
-	cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
+	cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
 
 	data.blksz = 64;
 	data.blocks = 1;

-------------------------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc.
Still grepping through log files to find problems?  Stop.
Now Search log events and configuration files using AJAX and a browser.
Download your FREE copy of Splunk now >>  http://get.splunk.com/
_______________________________________________
spi-devel-general mailing list
spi-devel-general@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/spi-devel-general

  parent reply	other threads:[~2007-07-26 21:58 UTC|newest]

Thread overview: 47+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2007-07-14 22:04 [patch 2.6.22-git5 0/4] MMC-over-SPI David Brownell
     [not found] ` <200707141504.51950.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>
2007-07-14 22:05   ` [patch 2.6.22-git5 1/4] MMC headers learn about SPI David Brownell
     [not found]     ` <200707141506.00262.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>
2007-07-26 16:31       ` Pierre Ossman
     [not found]         ` <20070726183150.024930aa-mgABNEgzgxm+PRNnhPf8W5YgPPQkE1Si@public.gmane.org>
2007-07-26 16:55           ` David Brownell
     [not found]             ` <200707260955.22967.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>
2007-07-26 18:05               ` Pierre Ossman
     [not found]                 ` <20070726200525.6a5b7d72-mgABNEgzgxm+PRNnhPf8W5YgPPQkE1Si@public.gmane.org>
2007-07-26 20:08                   ` David Brownell
2007-07-14 22:06   ` [patch 2.6.22-git5 2/4] MMC block learns " David Brownell
     [not found]     ` <200707141506.42880.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>
2007-07-26 16:33       ` Pierre Ossman
     [not found]         ` <20070726183339.6631243f-mgABNEgzgxm+PRNnhPf8W5YgPPQkE1Si@public.gmane.org>
2007-07-26 17:00           ` David Brownell
     [not found]             ` <200707261000.17339.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>
2007-07-26 18:06               ` Pierre Ossman
     [not found]                 ` <20070726200639.06242858-mgABNEgzgxm+PRNnhPf8W5YgPPQkE1Si@public.gmane.org>
2007-07-26 20:15                   ` David Brownell
2007-07-14 22:07   ` [patch 2.6.22-git5 3/4] MMC core " David Brownell
     [not found]     ` <200707141507.17484.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>
2007-07-26 17:18       ` Pierre Ossman
     [not found]         ` <20070726191824.569542fd-mgABNEgzgxm+PRNnhPf8W5YgPPQkE1Si@public.gmane.org>
2007-07-26 21:58           ` David Brownell [this message]
     [not found]             ` <200707261458.55558.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>
2007-07-26 22:22               ` David Brownell
2007-08-01 15:02               ` Pierre Ossman
     [not found]                 ` <20070801170220.3c5ccff6-mgABNEgzgxm+PRNnhPf8W5YgPPQkE1Si@public.gmane.org>
2007-08-01 17:02                   ` David Brownell
     [not found]                     ` <200708011002.28801.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>
2007-08-02 12:54                       ` Pierre Ossman
     [not found]                         ` <20070802145445.1118d1e7-mgABNEgzgxm+PRNnhPf8W5YgPPQkE1Si@public.gmane.org>
2007-08-02 19:23                           ` David Brownell
2007-07-14 22:08   ` [patch 2.6.22-git5 4/4] mmc_spi host driver David Brownell
     [not found]     ` <200707141508.07555.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>
2007-07-26 18:02       ` Pierre Ossman
     [not found]         ` <20070726200202.5e5dcf62-mgABNEgzgxm+PRNnhPf8W5YgPPQkE1Si@public.gmane.org>
2007-07-26 23:32           ` David Brownell
     [not found]             ` <200707261632.37011.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>
2007-08-01 15:12               ` Pierre Ossman
     [not found]                 ` <20070801171217.1478267b-mgABNEgzgxm+PRNnhPf8W5YgPPQkE1Si@public.gmane.org>
2007-08-01 18:17                   ` David Brownell
     [not found]                     ` <200708011117.24664.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>
2007-08-02 13:06                       ` Pierre Ossman
     [not found]                         ` <20070802150615.36e073c6-mgABNEgzgxm+PRNnhPf8W5YgPPQkE1Si@public.gmane.org>
2007-08-02 20:34                           ` David Brownell
     [not found]                             ` <200708021334.50670.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>
2007-08-04 13:14                               ` Pierre Ossman
     [not found]                                 ` <20070804151452.0efaa5a9-mgABNEgzgxm+PRNnhPf8W5YgPPQkE1Si@public.gmane.org>
2007-08-04 17:32                                   ` David Brownell
     [not found]                                     ` <200708041032.10001.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>
2007-08-04 21:32                                       ` Pierre Ossman
2007-08-07 12:35                               ` Pierre Ossman
2007-08-01 18:40                   ` David Brownell
2007-07-16 16:48   ` [patch 2.6.22-git5 0/4] MMC-over-SPI Anton Vorontsov
     [not found]     ` <20070716164837.GA18707-bi+AKbBUZKY6gyzm1THtWbp2dZbC/Bob@public.gmane.org>
2007-07-16 18:54       ` David Brownell
     [not found]         ` <200707161154.54728.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>
2007-07-17 15:13           ` Anton Vorontsov
     [not found]             ` <20070717151350.GA3752-bi+AKbBUZKY6gyzm1THtWbp2dZbC/Bob@public.gmane.org>
2007-07-17 16:11               ` David Brownell
     [not found]                 ` <200707170911.16715.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>
2007-07-18  7:35                   ` Jan Nikitenko
     [not found]                     ` <469DC2BC.5070305-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2007-07-18 17:06                       ` David Brownell
2007-07-18 10:00                   ` Anton Vorontsov
     [not found]                     ` <20070718100047.GA9544-bi+AKbBUZKY6gyzm1THtWbp2dZbC/Bob@public.gmane.org>
2007-07-18 14:05                       ` Anton Vorontsov
2007-07-18 14:44                   ` Pierre Ossman
     [not found]                     ` <20070718164409.56ca0019-mgABNEgzgxm+PRNnhPf8W5YgPPQkE1Si@public.gmane.org>
2007-07-18 17:27                       ` David Brownell
     [not found]                         ` <200707181027.17819.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>
2007-07-19 16:15                           ` Anton Vorontsov
     [not found]                             ` <20070719161553.GA15756-bi+AKbBUZKY6gyzm1THtWbp2dZbC/Bob@public.gmane.org>
2007-07-19 20:28                               ` David Brownell
     [not found]                                 ` <200707191328.18846.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>
2007-07-23 14:29                                   ` Anton Vorontsov
     [not found]                                     ` <20070723142923.GA28979-bi+AKbBUZKY6gyzm1THtWbp2dZbC/Bob@public.gmane.org>
2007-07-23 17:33                                       ` David Brownell
     [not found]                                         ` <200707231033.31717.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>
2007-07-24 10:23                                           ` Anton Vorontsov
2007-08-07  3:21                                           ` David Brownell

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=200707261458.55558.david-b@pacbell.net \
    --to=david-b-ybekhbn/0ldr7s880joybq@public.gmane.org \
    --cc=drzeus-mmc-p3sGCRWkH8CeZLLa646FqQ@public.gmane.org \
    --cc=hans-peter.nilsson-VrBV9hrLPhE@public.gmane.org \
    --cc=mikael.starvik-VrBV9hrLPhE@public.gmane.org \
    --cc=mike-UTnDXsALFwNjMdQLN6DIHgC/G2K4zDHf@public.gmane.org \
    --cc=spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).