linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH][MMC] Secure Digital (SD) support
@ 2005-03-03 12:22 Pierre Ossman
  2005-03-04 13:22 ` Pavel Machek
                   ` (2 more replies)
  0 siblings, 3 replies; 21+ messages in thread
From: Pierre Ossman @ 2005-03-03 12:22 UTC (permalink / raw)
  To: LKML; +Cc: Russell King, Ian Molton, Richard Purdie

[-- Attachment #1: Type: text/plain, Size: 1577 bytes --]

Here are the patches for Secure Digital support that I've been sitting 
on for a while. I tried to get some feedback on inclusion of this 
previously but since I didn't get any I'll just submit the thing.
It was originally diffed against 2.6.10 but it applies to 2.6.11 just 
fine (only minor fuzz).

Change summary:

* Detects if connected card is SD or MMC. Marks host as in SD mode if SD 
is detected (since SD isn't a bus system).
* Reads extra registers from SD cards (SCR) and parses CSD differently 
depending on SD/MMC mode.
* Support for 4-bit mode. This has been design to be fairly isolated 
from the SD bit so that it can (hopefully) be reused with MMC.
* New callback added for reading the read-only switch on SD cards.

Changed files:

mmc.c : SD detection and register parsing.
mmc_block.c : Checks read-only flag for cards (not SD-specific).
mmc_sysfs.c : Exposes SCR register.
card.h : Added flags to determine card type, RO and new register.
host.h : Added flags for bus width, RO test and mode (SD/MMC).
mmc.h : Added R6 define and new defines.
protocol.h : Added needed SD commands.

This patch is backwards compatible and only needs updated drivers to 
take advantage of 4-bit bus and reading the RO switch (unmodified 
drivers will default to 1-bit bus and write enable).

There might be new bugs that surface with this though. With my own 
drivers I discovered that very small transfers (< 16 bytes) always 
failed. Testing is needed but I do not have access to do it myself. MMC 
should not break with this since MMC is detected before SD.

Rgds
Pierre

[-- Attachment #2: mmc-sd-2.6.10.patch --]
[-- Type: text/x-patch, Size: 25045 bytes --]

diff -uNp linux/include/linux/mmc/card.h linux-wbsd/include/linux/mmc/card.h
--- linux/include/linux/mmc/card.h	2004-10-18 23:54:55.000000000 +0200
+++ linux-wbsd/include/linux/mmc/card.h	2004-12-25 23:42:13.974522806 +0100
@@ -33,6 +33,13 @@ struct mmc_csd {
 	unsigned int		capacity;
 };
 
+struct sd_scr {
+	unsigned char		sda_vsn;
+	unsigned char		bus_widths;
+#define SD_SCR_BUS_WIDTH_1	(1<<0)
+#define SD_SCR_BUS_WIDTH_4	(1<<2)
+};
+
 struct mmc_host;
 
 /*
@@ -47,19 +54,27 @@ struct mmc_card {
 #define MMC_STATE_PRESENT	(1<<0)		/* present in sysfs */
 #define MMC_STATE_DEAD		(1<<1)		/* device no longer in stack */
 #define MMC_STATE_BAD		(1<<2)		/* unrecognised device */
+#define MMC_STATE_SDCARD	(1<<3)		/* is an SD card */
+#define MMC_STATE_READONLY	(1<<4)		/* card is read-only */
 	u32			raw_cid[4];	/* raw card CID */
 	u32			raw_csd[4];	/* raw card CSD */
+	u32			raw_scr[2];	/* raw card SCR */
 	struct mmc_cid		cid;		/* card identification */
 	struct mmc_csd		csd;		/* card specific */
+	struct sd_scr		scr;		/* extra SD information */
 };
 
 #define mmc_card_present(c)	((c)->state & MMC_STATE_PRESENT)
 #define mmc_card_dead(c)	((c)->state & MMC_STATE_DEAD)
 #define mmc_card_bad(c)		((c)->state & MMC_STATE_BAD)
+#define mmc_card_sd(c)		((c)->state & MMC_STATE_SDCARD)
+#define mmc_card_readonly(c)	((c)->state & MMC_STATE_READONLY)
 
 #define mmc_card_set_present(c)	((c)->state |= MMC_STATE_PRESENT)
 #define mmc_card_set_dead(c)	((c)->state |= MMC_STATE_DEAD)
 #define mmc_card_set_bad(c)	((c)->state |= MMC_STATE_BAD)
+#define mmc_card_set_sd(c)	((c)->state |= MMC_STATE_SDCARD)
+#define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY)
 
 #define mmc_card_name(c)	((c)->cid.prod_name)
 #define mmc_card_id(c)		((c)->dev.bus_id)
diff -uNp linux/include/linux/mmc/host.h linux-wbsd/include/linux/mmc/host.h
--- linux/include/linux/mmc/host.h	2004-10-18 23:54:32.000000000 +0200
+++ linux-wbsd/include/linux/mmc/host.h	2004-12-25 22:36:16.260639695 +0100
@@ -51,11 +51,17 @@ struct mmc_ios {
 #define MMC_POWER_OFF		0
 #define MMC_POWER_UP		1
 #define MMC_POWER_ON		2
+
+	unsigned char	bus_width;		/* data bus width */
+
+#define MMC_BUS_WIDTH_1		0
+#define MMC_BUS_WIDTH_4		2
 };
 
 struct mmc_host_ops {
 	void	(*request)(struct mmc_host *host, struct mmc_request *req);
 	void	(*set_ios)(struct mmc_host *host, struct mmc_ios *ios);
+	int	(*get_ro)(struct mmc_host *host);
 };
 
 struct mmc_card;
@@ -68,6 +74,10 @@ struct mmc_host {
 	unsigned int		f_max;
 	u32			ocr_avail;
 	char			host_name[8];
+	
+	unsigned long		caps;		/* Host capabilities */
+	
+#define MMC_CAP_4_BIT_DATA	(1 << 0)	/* Can the host do 4 bit transfers */
 
 	/* host specific block data */
 	unsigned int		max_seg_size;	/* see blk_queue_max_segment_size */
@@ -79,6 +89,10 @@ struct mmc_host {
 	/* private data */
 	struct mmc_ios		ios;		/* current io bus settings */
 	u32			ocr;		/* the current OCR setting */
+	
+	unsigned int		mode;		/* current card mode of host */
+#define MMC_MODE_MMC		0
+#define MMC_MODE_SD		1
 
 	struct list_head	cards;		/* devices attached to this host */
 
diff -uNp linux/include/linux/mmc/mmc.h linux-wbsd/include/linux/mmc/mmc.h
--- linux/include/linux/mmc/mmc.h	2004-12-26 00:17:12.338128877 +0100
+++ linux-wbsd/include/linux/mmc/mmc.h	2005-01-01 23:11:51.478637901 +0100
@@ -37,6 +37,7 @@ struct mmc_command {
 #define MMC_RSP_R1B	(MMC_RSP_SHORT|MMC_RSP_CRC|MMC_RSP_BUSY)
 #define MMC_RSP_R2	(MMC_RSP_LONG|MMC_RSP_CRC)
 #define MMC_RSP_R3	(MMC_RSP_SHORT)
+#define MMC_RSP_R6	(MMC_RSP_SHORT|MMC_RSP_CRC)
 
 	unsigned int		retries;	/* max number of retries */
 	unsigned int		error;		/* command error */
@@ -88,6 +89,8 @@ struct mmc_card;
 
 extern int mmc_wait_for_req(struct mmc_host *, struct mmc_request *);
 extern int mmc_wait_for_cmd(struct mmc_host *, struct mmc_command *, int);
+extern int mmc_wait_for_app_cmd(struct mmc_host *, unsigned int,
+	struct mmc_command *, int);
 
 extern int __mmc_claim_host(struct mmc_host *host, struct mmc_card *card);
 
diff -uNp linux/include/linux/mmc/protocol.h linux-wbsd/include/linux/mmc/protocol.h
--- linux/include/linux/mmc/protocol.h	2004-10-18 23:55:36.000000000 +0200
+++ linux-wbsd/include/linux/mmc/protocol.h	2004-12-24 02:43:55.880637702 +0100
@@ -76,6 +76,16 @@
 #define MMC_APP_CMD              55   /* ac   [31:16] RCA        R1  */
 #define MMC_GEN_CMD              56   /* adtc [0] RD/WR          R1b */
 
+/* SD commands                           type  argument     response */
+  /* class 8 */
+/* This is basically the same command as for MMC with some quirks. */
+#define SD_SEND_RELATIVE_ADDR     3   /* ac                      R6  */
+
+  /* Application commands */
+#define SD_APP_SET_BUS_WIDTH      6   /* ac   [1:0] bus width    R1  */
+#define SD_APP_OP_COND           41   /* bcr  [31:0] OCR         R3  */
+#define SD_APP_SEND_SCR          51   /* adtc                    R1  */
+
 /*
   MMC status in R1
   Type
@@ -113,7 +123,7 @@
 #define R1_STATUS(x)            (x & 0xFFFFE000)
 #define R1_CURRENT_STATE(x)    	((x & 0x00001E00) >> 9)	/* sx, b (4 bits) */
 #define R1_READY_FOR_DATA	(1 << 8)	/* sx, a */
-#define R1_APP_CMD		(1 << 7)	/* sr, c */
+#define R1_APP_CMD		(1 << 5)	/* sr, c */
 
 /* These are unpacked versions of the actual responses */
 
@@ -199,5 +209,12 @@ struct _mmc_csd {
 #define CSD_SPEC_VER_2      2           /* Implements system specification 2.0 - 2.2 */
 #define CSD_SPEC_VER_3      3           /* Implements system specification 3.1 */
 
+
+/*
+ * SD bus widths
+ */
+#define SD_BUS_WIDTH_1      0
+#define SD_BUS_WIDTH_4      2
+
 #endif  /* MMC_MMC_PROTOCOL_H */
 
Common subdirectories: linux/include/linux/mmc/.svn and linux-wbsd/include/linux/mmc/.svn
--- linux/drivers/mmc/mmc.c	2005-01-02 01:05:32.976696144 +0100
+++ linux-wbsd/drivers/mmc/mmc.c	2005-01-02 23:50:27.982629278 +0100
@@ -16,6 +16,8 @@
 #include <linux/delay.h>
 #include <linux/pagemap.h>
 #include <linux/err.h>
+#include <asm/scatterlist.h>
+#include <linux/scatterlist.h>
 
 #include <linux/mmc/card.h>
 #include <linux/mmc/host.h>
@@ -172,7 +174,81 @@ int mmc_wait_for_cmd(struct mmc_host *ho
 
 EXPORT_SYMBOL(mmc_wait_for_cmd);
 
+/**
+ *	mmc_wait_for_app_cmd - start an application command and wait for
+ 			       completion
+ *	@host: MMC host to start command
+ *	@rca: RCA to send MMC_APP_CMD to
+ *	@cmd: MMC command to start
+ *	@retries: maximum number of retries
+ *
+ *	Sends a MMC_APP_CMD, checks the card response, sends the command
+ *	in the parameter and waits for it to complete. Return any error
+ *	that occurred while the command was executing.  Do not attempt to
+ *	parse the response.
+ */
+int mmc_wait_for_app_cmd(struct mmc_host *host, unsigned int rca,
+	struct mmc_command *cmd, int retries)
+{
+	struct mmc_request mrq;
+	struct mmc_command appcmd;
+	
+	int i, err;
+
+	BUG_ON(host->card_busy == NULL);
+	BUG_ON(retries < 0);
+	
+	err = MMC_ERR_INVALID;
+	
+	/*
+	 * We have to resend MMC_APP_CMD for each attempt so
+	 * we cannot use the retries field in mmc_command.
+	 */
+	for (i = 0;i <= retries;i++) {
+		memset(&mrq, 0, sizeof(struct mmc_request));
+
+		appcmd.opcode = MMC_APP_CMD;
+		appcmd.arg = rca << 16;
+		appcmd.flags = MMC_RSP_R1;
+		appcmd.retries = 0;
+		memset(appcmd.resp, 0, sizeof(appcmd.resp));
+		appcmd.data = NULL;
+		
+		mrq.cmd = &appcmd;
+		appcmd.data = NULL;
+		
+		mmc_wait_for_req(host, &mrq);
+		
+		if (appcmd.error) {
+			err = appcmd.error;
+			continue;
+		}
+		
+		/* Check that card supported application commands */
+		if (!(appcmd.resp[0] & R1_APP_CMD))
+			return MMC_ERR_FAILED;
+
+		memset(&mrq, 0, sizeof(struct mmc_request));
+
+		memset(cmd->resp, 0, sizeof(cmd->resp));
+		cmd->retries = 0;
+
+		mrq.cmd = cmd;
+		cmd->data = NULL;
+
+		mmc_wait_for_req(host, &mrq);
+		
+		err = cmd->error;
+		if (cmd->error == MMC_ERR_NONE)
+			break;
+	}
+
+	return err;
+}
 
+EXPORT_SYMBOL(mmc_wait_for_app_cmd);
+
+static int mmc_select_card(struct mmc_host *host, struct mmc_card *card);
 
 /**
  *	__mmc_claim_host - exclusively claim a host
@@ -206,16 +282,10 @@ int __mmc_claim_host(struct mmc_host *ho
 	spin_unlock_irqrestore(&host->lock, flags);
 	remove_wait_queue(&host->wq, &wait);
 
-	if (card != (void *)-1 && host->card_selected != card) {
-		struct mmc_command cmd;
-
-		host->card_selected = card;
-
-		cmd.opcode = MMC_SELECT_CARD;
-		cmd.arg = card->rca << 16;
-		cmd.flags = MMC_RSP_R1;
-
-		err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
+	if (card != (void *)-1) {
+		err = mmc_select_card(host, card);
+		if (err != MMC_ERR_NONE)
+			return err;
 	}
 
 	return err;
@@ -245,6 +315,63 @@ void mmc_release_host(struct mmc_host *h
 
 EXPORT_SYMBOL(mmc_release_host);
 
+static int mmc_select_card(struct mmc_host *host, struct mmc_card *card)
+{
+	int err;
+	struct mmc_command cmd;
+
+	BUG_ON(host->card_busy == NULL);
+	
+	if (host->card_selected == card)
+		return MMC_ERR_NONE;
+
+	host->card_selected = card;
+
+	cmd.opcode = MMC_SELECT_CARD;
+	cmd.arg = card->rca << 16;
+	cmd.flags = MMC_RSP_R1;
+
+	err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
+	if (err != MMC_ERR_NONE)
+		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
+	 * 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)) {
+			struct mmc_command cmd;
+			cmd.opcode = SD_APP_SET_BUS_WIDTH;
+			cmd.arg = SD_BUS_WIDTH_4;
+			cmd.flags = MMC_RSP_R1;
+			
+			err = mmc_wait_for_app_cmd(host, card->rca, &cmd,
+				CMD_RETRIES);
+			if (err != MMC_ERR_NONE)
+				return err;
+			
+			host->ios.bus_width = MMC_BUS_WIDTH_4;
+		}
+	}
+
+	host->ops->set_ios(host, &host->ios);
+
+	return MMC_ERR_NONE;
+}
+
 /*
  * Ensure that no card is selected.
  */
@@ -321,48 +448,70 @@ static void mmc_decode_cid(struct mmc_ca
 
 	memset(&card->cid, 0, sizeof(struct mmc_cid));
 
-	/*
-	 * The selection of the format here is guesswork based upon
-	 * information people have sent to date.
-	 */
-	switch (card->csd.mmca_vsn) {
-	case 0: /* MMC v1.? */
-	case 1: /* MMC v1.4 */
-		card->cid.manfid	= UNSTUFF_BITS(resp, 104, 24);
-		card->cid.prod_name[0]	= UNSTUFF_BITS(resp, 96, 8);
-		card->cid.prod_name[1]	= UNSTUFF_BITS(resp, 88, 8);
-		card->cid.prod_name[2]	= UNSTUFF_BITS(resp, 80, 8);
-		card->cid.prod_name[3]	= UNSTUFF_BITS(resp, 72, 8);
-		card->cid.prod_name[4]	= UNSTUFF_BITS(resp, 64, 8);
-		card->cid.prod_name[5]	= UNSTUFF_BITS(resp, 56, 8);
-		card->cid.prod_name[6]	= UNSTUFF_BITS(resp, 48, 8);
-		card->cid.hwrev		= UNSTUFF_BITS(resp, 44, 4);
-		card->cid.fwrev		= UNSTUFF_BITS(resp, 40, 4);
-		card->cid.serial	= UNSTUFF_BITS(resp, 16, 24);
-		card->cid.month		= UNSTUFF_BITS(resp, 12, 4);
-		card->cid.year		= UNSTUFF_BITS(resp, 8, 4) + 1997;
-		break;
-
-	case 2: /* MMC v2.x ? */
-	case 3: /* MMC v3.x ? */
-		card->cid.manfid	= UNSTUFF_BITS(resp, 120, 8);
-		card->cid.oemid		= UNSTUFF_BITS(resp, 104, 16);
-		card->cid.prod_name[0]	= UNSTUFF_BITS(resp, 96, 8);
-		card->cid.prod_name[1]	= UNSTUFF_BITS(resp, 88, 8);
-		card->cid.prod_name[2]	= UNSTUFF_BITS(resp, 80, 8);
-		card->cid.prod_name[3]	= UNSTUFF_BITS(resp, 72, 8);
-		card->cid.prod_name[4]	= UNSTUFF_BITS(resp, 64, 8);
-		card->cid.prod_name[5]	= UNSTUFF_BITS(resp, 56, 8);
-		card->cid.serial	= UNSTUFF_BITS(resp, 16, 32);
-		card->cid.month		= UNSTUFF_BITS(resp, 12, 4);
-		card->cid.year		= UNSTUFF_BITS(resp, 8, 4) + 1997;
-		break;
-
-	default:
-		printk("%s: card has unknown MMCA version %d\n",
-			card->host->host_name, card->csd.mmca_vsn);
-		mmc_card_set_bad(card);
-		break;
+	if (mmc_card_sd(card)) {
+		/*
+		 * SD doesn't currently have a version field so we will
+		 * have to assume we can parse this.
+		 */
+		card->cid.manfid		= UNSTUFF_BITS(resp, 120, 8);
+		card->cid.oemid			= UNSTUFF_BITS(resp, 104, 16);
+		card->cid.prod_name[0]		= UNSTUFF_BITS(resp, 96, 8);
+		card->cid.prod_name[1]		= UNSTUFF_BITS(resp, 88, 8);
+		card->cid.prod_name[2]		= UNSTUFF_BITS(resp, 80, 8);
+		card->cid.prod_name[3]		= UNSTUFF_BITS(resp, 72, 8);
+		card->cid.prod_name[4]		= UNSTUFF_BITS(resp, 64, 8);
+		card->cid.hwrev			= UNSTUFF_BITS(resp, 60, 4);
+		card->cid.fwrev			= UNSTUFF_BITS(resp, 56, 4);
+		card->cid.serial		= UNSTUFF_BITS(resp, 24, 32);
+		card->cid.year			= UNSTUFF_BITS(resp, 12, 8);
+		card->cid.month			= UNSTUFF_BITS(resp, 8, 4);
+
+		card->cid.year += 2000; /* SD cards year offset */
+	}
+	else {
+		/*
+		 * The selection of the format here is based upon published
+		 * specs from sandisk and from what people have reported.
+		 */
+		switch (card->csd.mmca_vsn) {
+		case 0: /* MMC v1.0 - v1.2 */
+		case 1: /* MMC v1.4 */
+			card->cid.manfid	= UNSTUFF_BITS(resp, 104, 24);
+			card->cid.prod_name[0]	= UNSTUFF_BITS(resp, 96, 8);
+			card->cid.prod_name[1]	= UNSTUFF_BITS(resp, 88, 8);
+			card->cid.prod_name[2]	= UNSTUFF_BITS(resp, 80, 8);
+			card->cid.prod_name[3]	= UNSTUFF_BITS(resp, 72, 8);
+			card->cid.prod_name[4]	= UNSTUFF_BITS(resp, 64, 8);
+			card->cid.prod_name[5]	= UNSTUFF_BITS(resp, 56, 8);
+			card->cid.prod_name[6]	= UNSTUFF_BITS(resp, 48, 8);
+			card->cid.hwrev		= UNSTUFF_BITS(resp, 44, 4);
+			card->cid.fwrev		= UNSTUFF_BITS(resp, 40, 4);
+			card->cid.serial	= UNSTUFF_BITS(resp, 16, 24);
+			card->cid.month		= UNSTUFF_BITS(resp, 12, 4);
+			card->cid.year		= UNSTUFF_BITS(resp, 8, 4) + 1997;
+			break;
+
+		case 2: /* MMC v2.0 - v2.2 */
+		case 3: /* MMC v3.1 - v3.3 */
+			card->cid.manfid	= UNSTUFF_BITS(resp, 120, 8);
+			card->cid.oemid		= UNSTUFF_BITS(resp, 104, 16);
+			card->cid.prod_name[0]	= UNSTUFF_BITS(resp, 96, 8);
+			card->cid.prod_name[1]	= UNSTUFF_BITS(resp, 88, 8);
+			card->cid.prod_name[2]	= UNSTUFF_BITS(resp, 80, 8);
+			card->cid.prod_name[3]	= UNSTUFF_BITS(resp, 72, 8);
+			card->cid.prod_name[4]	= UNSTUFF_BITS(resp, 64, 8);
+			card->cid.prod_name[5]	= UNSTUFF_BITS(resp, 56, 8);
+			card->cid.serial	= UNSTUFF_BITS(resp, 16, 32);
+			card->cid.month		= UNSTUFF_BITS(resp, 12, 4);
+			card->cid.year		= UNSTUFF_BITS(resp, 8, 4) + 1997;
+			break;
+
+		default:
+			printk("%s: card has unknown MMCA version %d\n",
+				card->host->host_name, card->csd.mmca_vsn);
+			mmc_card_set_bad(card);
+			break;
+		}
 	}
 }
 
@@ -374,35 +523,88 @@ static void mmc_decode_csd(struct mmc_ca
 	struct mmc_csd *csd = &card->csd;
 	unsigned int e, m, csd_struct;
 	u32 *resp = card->raw_csd;
+	
+	if (mmc_card_sd(card)) {
+		csd_struct = UNSTUFF_BITS(resp, 126, 2);
+		if (csd_struct != 0) {
+			printk("%s: unrecognised CSD structure version %d\n",
+				card->host->host_name, csd_struct);
+			mmc_card_set_bad(card);
+			return;
+		}
+		
+		m = UNSTUFF_BITS(resp, 115, 4);
+		e = UNSTUFF_BITS(resp, 112, 3);
+		csd->tacc_ns	 = (tacc_exp[e] * tacc_mant[m] + 9) / 10;
+		csd->tacc_clks	 = UNSTUFF_BITS(resp, 104, 8) * 100;
+
+		m = UNSTUFF_BITS(resp, 99, 4);
+		e = UNSTUFF_BITS(resp, 96, 3);
+		csd->max_dtr	  = tran_exp[e] * tran_mant[m];
+		csd->cmdclass	  = UNSTUFF_BITS(resp, 84, 12);
+
+		e = UNSTUFF_BITS(resp, 47, 3);
+		m = UNSTUFF_BITS(resp, 62, 12);
+		csd->capacity	  = (1 + m) << (e + 2);
 
-	/*
-	 * We only understand CSD structure v1.1 and v2.
-	 * v2 has extra information in bits 15, 11 and 10.
-	 */
-	csd_struct = UNSTUFF_BITS(resp, 126, 2);
-	if (csd_struct != 1 && csd_struct != 2) {
-		printk("%s: unrecognised CSD structure version %d\n",
-			card->host->host_name, csd_struct);
-		mmc_card_set_bad(card);
-		return;
+		csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4);
 	}
+	else {
+		/*
+		 * We only understand CSD structure v1.1 and v1.2.
+		 * v1.2 has extra information in bits 15, 11 and 10.
+		 */
+		csd_struct = UNSTUFF_BITS(resp, 126, 2);
+		if (csd_struct != 1 && csd_struct != 2) {
+			printk("%s: unrecognised CSD structure version %d\n",
+				card->host->host_name, csd_struct);
+			mmc_card_set_bad(card);
+			return;
+		}
 
-	csd->mmca_vsn	 = UNSTUFF_BITS(resp, 122, 4);
-	m = UNSTUFF_BITS(resp, 115, 4);
-	e = UNSTUFF_BITS(resp, 112, 3);
-	csd->tacc_ns	 = (tacc_exp[e] * tacc_mant[m] + 9) / 10;
-	csd->tacc_clks	 = UNSTUFF_BITS(resp, 104, 8) * 100;
-
-	m = UNSTUFF_BITS(resp, 99, 4);
-	e = UNSTUFF_BITS(resp, 96, 3);
-	csd->max_dtr	  = tran_exp[e] * tran_mant[m];
-	csd->cmdclass	  = UNSTUFF_BITS(resp, 84, 12);
-
-	e = UNSTUFF_BITS(resp, 47, 3);
-	m = UNSTUFF_BITS(resp, 62, 12);
-	csd->capacity	  = (1 + m) << (e + 2);
+		csd->mmca_vsn	 = UNSTUFF_BITS(resp, 122, 4);
+		m = UNSTUFF_BITS(resp, 115, 4);
+		e = UNSTUFF_BITS(resp, 112, 3);
+		csd->tacc_ns	 = (tacc_exp[e] * tacc_mant[m] + 9) / 10;
+		csd->tacc_clks	 = UNSTUFF_BITS(resp, 104, 8) * 100;
+
+		m = UNSTUFF_BITS(resp, 99, 4);
+		e = UNSTUFF_BITS(resp, 96, 3);
+		csd->max_dtr	  = tran_exp[e] * tran_mant[m];
+		csd->cmdclass	  = UNSTUFF_BITS(resp, 84, 12);
+
+		e = UNSTUFF_BITS(resp, 47, 3);
+		m = UNSTUFF_BITS(resp, 62, 12);
+		csd->capacity	  = (1 + m) << (e + 2);
 
-	csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4);
+		csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4);
+	}
+}
+
+/*
+ * Given a 64-bit response, decode to our card SCR structure.
+ */
+static void mmc_decode_scr(struct mmc_card *card)
+{
+	struct sd_scr *scr = &card->scr;
+	unsigned int scr_struct;
+	u32 resp[4];
+
+	BUG_ON(!mmc_card_sd(card));
+	
+	resp[3] = card->raw_scr[1];
+	resp[2] = card->raw_scr[0];
+	
+	scr_struct = UNSTUFF_BITS(resp, 60, 4);
+	if (scr_struct != 0) {
+		printk("%s: unrecognised SCR structure version %d\n",
+			card->host->host_name, scr_struct);
+		mmc_card_set_bad(card);
+		return;
+	}
+	
+	scr->sda_vsn = UNSTUFF_BITS(resp, 56, 4);
+	scr->bus_widths = UNSTUFF_BITS(resp, 48, 4);
 }
 
 /*
@@ -475,6 +677,7 @@ static void mmc_power_up(struct mmc_host
 	host->ios.vdd = bit;
 	host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
 	host->ios.power_mode = MMC_POWER_UP;
+	host->ios.bus_width = MMC_BUS_WIDTH_1;
 	host->ops->set_ios(host, &host->ios);
 
 	mmc_delay(1);
@@ -492,6 +695,7 @@ static void mmc_power_off(struct mmc_hos
 	host->ios.vdd = 0;
 	host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
 	host->ios.power_mode = MMC_POWER_OFF;
+	host->ios.bus_width = MMC_BUS_WIDTH_1;
 	host->ops->set_ios(host, &host->ios);
 }
 
@@ -523,6 +727,34 @@ static int mmc_send_op_cond(struct mmc_h
 	return err;
 }
 
+static int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
+{
+	struct mmc_command cmd;
+	int i, err = 0;
+
+	cmd.opcode = SD_APP_OP_COND;
+	cmd.arg = ocr;
+	cmd.flags = MMC_RSP_R3;
+
+	for (i = 100; i; i--) {
+		err = mmc_wait_for_app_cmd(host, 0, &cmd, CMD_RETRIES);
+		if (err != MMC_ERR_NONE)
+			break;
+
+		if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0)
+			break;
+
+		err = MMC_ERR_TIMEOUT;
+
+		mmc_delay(10);
+	}
+
+	if (rocr)
+		*rocr = cmd.resp[0];
+
+	return err;
+}
+
 /*
  * Discover cards by requesting their CID.  If this command
  * times out, it is not an error; there are no further cards
@@ -565,14 +797,39 @@ static void mmc_discover_cards(struct mm
 		}
 
 		card->state &= ~MMC_STATE_DEAD;
+		
+		if (host->mode == MMC_MODE_SD) {
+			mmc_card_set_sd(card);
+
+			cmd.opcode = SD_SEND_RELATIVE_ADDR;
+			cmd.arg = 0;
+			cmd.flags = MMC_RSP_R1;
 
-		cmd.opcode = MMC_SET_RELATIVE_ADDR;
-		cmd.arg = card->rca << 16;
-		cmd.flags = MMC_RSP_R1;
+			err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
+			if (err != MMC_ERR_NONE)
+				mmc_card_set_dead(card);
+			
+			card->rca = cmd.resp[0] >> 16;
+			
+			if (!host->ops->get_ro) {
+				printk(KERN_WARNING "%s: host does not support "
+					"reading read-only switch. assuming "
+					"write-enable.\n", host->host_name);
+			}
+			else {
+				if (host->ops->get_ro(host))
+					mmc_card_set_readonly(card);
+			}
+		}
+		else {
+			cmd.opcode = MMC_SET_RELATIVE_ADDR;
+			cmd.arg = card->rca << 16;
+			cmd.flags = MMC_RSP_R1;
 
-		err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
-		if (err != MMC_ERR_NONE)
-			mmc_card_set_dead(card);
+			err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
+			if (err != MMC_ERR_NONE)
+				mmc_card_set_dead(card);
+		}
 	}
 }
 
@@ -604,6 +861,80 @@ static void mmc_read_csds(struct mmc_hos
 	}
 }
 
+static void mmc_read_scrs(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;
+	
+	list_for_each_entry(card, &host->cards, node) {
+		if (card->state & (MMC_STATE_DEAD|MMC_STATE_PRESENT))
+			continue;
+		if (!mmc_card_sd(card))
+			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_APP_CMD;
+		cmd.arg = card->rca << 16;
+		cmd.flags = MMC_RSP_R1;
+		
+		err = mmc_wait_for_cmd(host, &cmd, 0);
+		if ((err != MMC_ERR_NONE) || !(cmd.resp[0] & R1_APP_CMD)) {
+			mmc_card_set_dead(card);
+			continue;
+		}
+		
+		memset(&cmd, 0, sizeof(struct mmc_command));
+		
+		cmd.opcode = SD_APP_SEND_SCR;
+		cmd.arg = 0;
+		cmd.flags = MMC_RSP_R1;
+		
+		memset(&data, 0, sizeof(struct mmc_data));
+		
+		data.timeout_ns = card->csd.tacc_ns * 10;
+		data.timeout_clks = card->csd.tacc_clks * 10;
+		data.blksz_bits = 3;
+		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, (u8*)card->raw_scr, 64);
+		
+		err = mmc_wait_for_req(host, &mrq);
+		if (err != MMC_ERR_NONE) {
+			mmc_card_set_dead(card);
+			continue;
+		}
+		
+		card->raw_scr[0] = ntohl(card->raw_scr[0]);
+		card->raw_scr[1] = ntohl(card->raw_scr[1]);
+
+		mmc_decode_scr(card);
+	}
+	
+	mmc_deselect_cards(host);
+}
+
 static unsigned int mmc_calculate_clock(struct mmc_host *host)
 {
 	struct mmc_card *card;
@@ -655,13 +986,26 @@ static void mmc_setup(struct mmc_host *h
 	if (host->ios.power_mode != MMC_POWER_ON) {
 		int err;
 		u32 ocr;
+		
+		host->mode = MMC_MODE_MMC;
 
 		mmc_power_up(host);
 		mmc_idle_cards(host);
 
 		err = mmc_send_op_cond(host, 0, &ocr);
+		
+		/*
+		 * If we fail to detect any cards then try
+		 * searching for SD cards.
+		 */
 		if (err != MMC_ERR_NONE)
-			return;
+		{
+			err = mmc_send_app_op_cond(host, 0, &ocr);
+			if (err != MMC_ERR_NONE)
+				return;
+			
+			host->mode = MMC_MODE_SD;
+		}
 
 		host->ocr = mmc_select_voltage(host, ocr);
 
@@ -714,7 +1058,10 @@ static void mmc_setup(struct mmc_host *h
 	 * all get the idea that they should be ready for CMD2.
 	 * (My SanDisk card seems to need this.)
 	 */
-	mmc_send_op_cond(host, host->ocr, NULL);
+	if (host->mode == MMC_MODE_SD)
+		mmc_send_app_op_cond(host, host->ocr, NULL);
+	else
+		mmc_send_op_cond(host, host->ocr, NULL);
 
 	mmc_discover_cards(host);
 
@@ -725,6 +1072,9 @@ static void mmc_setup(struct mmc_host *h
 	host->ops->set_ios(host, &host->ios);
 
 	mmc_read_csds(host);
+	
+	if (host->mode == MMC_MODE_SD)
+		mmc_read_scrs(host);
 }
 
 
--- linux/drivers/mmc/mmc_block.c	2005-01-01 23:46:36.990024519 +0100
+++ linux-wbsd/drivers/mmc/mmc_block.c	2004-12-26 01:16:32.778971274 +0100
@@ -95,6 +95,10 @@ static int mmc_blk_open(struct inode *in
 		if (md->usage == 2)
 			check_disk_change(inode->i_bdev);
 		ret = 0;
+		
+		if ((filp->f_mode & FMODE_WRITE) &&
+			mmc_card_readonly(md->queue.card))
+			ret = -EROFS;
 	}
 
 	return ret;
@@ -387,6 +391,7 @@ static struct mmc_blk_data *mmc_blk_allo
 		md->disk->private_data = md;
 		md->disk->queue = md->queue.queue;
 		md->disk->driverfs_dev = &card->dev;
+		md->disk->flags |= GENHD_FL_REMOVABLE;
 
 		sprintf(md->disk->disk_name, "mmcblk%d", devidx);
 		sprintf(md->disk->devfs_name, "mmc/blk%d", devidx);
@@ -444,9 +449,10 @@ static int mmc_blk_probe(struct mmc_card
 	if (err)
 		goto out;
 
-	printk(KERN_INFO "%s: %s %s %dKiB\n",
+	printk(KERN_INFO "%s: %s %s %dKiB %s\n",
 		md->disk->disk_name, mmc_card_id(card), mmc_card_name(card),
-		(card->csd.capacity << card->csd.read_blkbits) / 1024);
+		(card->csd.capacity << card->csd.read_blkbits) / 1024,
+		mmc_card_readonly(card)?"(ro)":"");
 
 	mmc_set_drvdata(card, md);
 	add_disk(md->disk);
--- linux/drivers/mmc/mmc_sysfs.c	2004-10-18 23:54:37.000000000 +0200
+++ linux-wbsd/drivers/mmc/mmc_sysfs.c	2004-12-24 02:21:29.839785413 +0100
@@ -163,6 +163,7 @@ MMC_ATTR(cid, "%08x%08x%08x%08x\n", card
 	card->raw_cid[2], card->raw_cid[3]);
 MMC_ATTR(csd, "%08x%08x%08x%08x\n", card->raw_csd[0], card->raw_csd[1],
 	card->raw_csd[2], card->raw_csd[3]);
+MMC_ATTR(scr, "%08x%08x\n", card->raw_scr[0], card->raw_scr[1]);
 MMC_ATTR(date, "%02d/%04d\n", card->cid.month, card->cid.year);
 MMC_ATTR(fwrev, "0x%x\n", card->cid.fwrev);
 MMC_ATTR(hwrev, "0x%x\n", card->cid.hwrev);
@@ -174,6 +175,7 @@ MMC_ATTR(serial, "0x%08x\n", card->cid.s
 static struct device_attribute *mmc_dev_attributes[] = {
 	&dev_attr_cid,
 	&dev_attr_csd,
+	&dev_attr_scr,
 	&dev_attr_date,
 	&dev_attr_fwrev,
 	&dev_attr_hwrev,

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH][MMC] Secure Digital (SD) support
  2005-03-03 12:22 [PATCH][MMC] Secure Digital (SD) support Pierre Ossman
@ 2005-03-04 13:22 ` Pavel Machek
  2005-03-04 15:00 ` Marcel Holtmann
  2005-03-05 11:37 ` Russell King
  2 siblings, 0 replies; 21+ messages in thread
From: Pavel Machek @ 2005-03-04 13:22 UTC (permalink / raw)
  To: Pierre Ossman; +Cc: LKML, Russell King, Ian Molton, Richard Purdie

Hi!

> Here are the patches for Secure Digital support that I've been 
> sitting on for a while. I tried to get some feedback on inclusion of 
> this previously but since I didn't get any I'll just submit the thing.
> It was originally diffed against 2.6.10 but it applies to 2.6.11 just 
> fine (only minor fuzz).

This is great! Hopefully it will mean no-more-binary-only-modules-on-zaurus...


-- 
64 bytes from 195.113.31.123: icmp_seq=28 ttl=51 time=448769.1 ms         


^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH][MMC] Secure Digital (SD) support
  2005-03-03 12:22 [PATCH][MMC] Secure Digital (SD) support Pierre Ossman
  2005-03-04 13:22 ` Pavel Machek
@ 2005-03-04 15:00 ` Marcel Holtmann
  2005-03-04 15:12   ` Pierre Ossman
  2005-03-05 11:37 ` Russell King
  2 siblings, 1 reply; 21+ messages in thread
From: Marcel Holtmann @ 2005-03-04 15:00 UTC (permalink / raw)
  To: Pierre Ossman; +Cc: LKML, Russell King, Ian Molton, Richard Purdie

Hi Pierre,

> Here are the patches for Secure Digital support that I've been sitting 
> on for a while. I tried to get some feedback on inclusion of this 
> previously but since I didn't get any I'll just submit the thing.
> It was originally diffed against 2.6.10 but it applies to 2.6.11 just 
> fine (only minor fuzz).

lately I got a request for the support of a Bluetooth SD card. These are
using SDIO and I think at the moment only memory cards are handled. Do
you have any plans for SDIO support?

Regards

Marcel



^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH][MMC] Secure Digital (SD) support
  2005-03-04 15:00 ` Marcel Holtmann
@ 2005-03-04 15:12   ` Pierre Ossman
  2005-03-04 16:22     ` Marcel Holtmann
  2005-03-04 21:04     ` Ian Molton
  0 siblings, 2 replies; 21+ messages in thread
From: Pierre Ossman @ 2005-03-04 15:12 UTC (permalink / raw)
  To: Marcel Holtmann; +Cc: LKML, Russell King, Ian Molton, Richard Purdie

Marcel Holtmann wrote:

>Hi Pierre,
>
>  
>
>>Here are the patches for Secure Digital support that I've been sitting 
>>on for a while. I tried to get some feedback on inclusion of this 
>>previously but since I didn't get any I'll just submit the thing.
>>It was originally diffed against 2.6.10 but it applies to 2.6.11 just 
>>fine (only minor fuzz).
>>    
>>
>
>lately I got a request for the support of a Bluetooth SD card. These are
>using SDIO and I think at the moment only memory cards are handled. Do
>you have any plans for SDIO support?
>
>  
>

I would if I had some hardware to play with *hint* *hint* ;)
The SDIO spec is publically available on the SD card associations web 
page so it shouldn't be too difficult to get some basic support. But I 
can't do much as long as I don't have any hardware to test it with. I 
might also need specs for the card itself. I haven't looked too much at 
SDIO at the moment.

Rgds
Pierre


^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH][MMC] Secure Digital (SD) support
  2005-03-04 15:12   ` Pierre Ossman
@ 2005-03-04 16:22     ` Marcel Holtmann
  2005-03-04 21:04     ` Ian Molton
  1 sibling, 0 replies; 21+ messages in thread
From: Marcel Holtmann @ 2005-03-04 16:22 UTC (permalink / raw)
  To: Pierre Ossman; +Cc: LKML, Russell King, Ian Molton, Richard Purdie

Hi Pierre,

> >lately I got a request for the support of a Bluetooth SD card. These are
> >using SDIO and I think at the moment only memory cards are handled. Do
> >you have any plans for SDIO support?
> 
> I would if I had some hardware to play with *hint* *hint* ;)

I don't have one of these cards either :(

> The SDIO spec is publically available on the SD card associations web 
> page so it shouldn't be too difficult to get some basic support. But I 
> can't do much as long as I don't have any hardware to test it with. I 
> might also need specs for the card itself. I haven't looked too much at 
> SDIO at the moment.

The Bluetooth HCI transport for SDIO is also available and I think most
SD card manufactures are using it.

So what we need is a hardware sponsor. Any volunteers?

Regards

Marcel



^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH][MMC] Secure Digital (SD) support
  2005-03-04 15:12   ` Pierre Ossman
  2005-03-04 16:22     ` Marcel Holtmann
@ 2005-03-04 21:04     ` Ian Molton
  1 sibling, 0 replies; 21+ messages in thread
From: Ian Molton @ 2005-03-04 21:04 UTC (permalink / raw)
  To: Pierre Ossman; +Cc: Marcel Holtmann, LKML, Russell King, Richard Purdie

Pierre Ossman wrote:

> I would if I had some hardware to play with *hint* *hint* ;)

Same here. I have some basic chipset docs.

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH][MMC] Secure Digital (SD) support
  2005-03-03 12:22 [PATCH][MMC] Secure Digital (SD) support Pierre Ossman
  2005-03-04 13:22 ` Pavel Machek
  2005-03-04 15:00 ` Marcel Holtmann
@ 2005-03-05 11:37 ` Russell King
  2005-03-05 12:23   ` Pierre Ossman
  2 siblings, 1 reply; 21+ messages in thread
From: Russell King @ 2005-03-05 11:37 UTC (permalink / raw)
  To: Pierre Ossman; +Cc: LKML, Ian Molton, Richard Purdie

On Thu, Mar 03, 2005 at 01:22:56PM +0100, Pierre Ossman wrote:
> Here are the patches for Secure Digital support that I've been sitting 
> on for a while. I tried to get some feedback on inclusion of this 
> previously but since I didn't get any I'll just submit the thing.
> It was originally diffed against 2.6.10 but it applies to 2.6.11 just 
> fine (only minor fuzz).

Can we please come to a consensus about GEN_FL_REMOVABLE.  After
talking to other kernel developers, particularly in the block
interface area, I am convinced that it is fundamentally incorrect
to set this flag for MMC/SD devices.

Unfortunately, it appears that you're not convinced.  This needs
resolving since it is an interface issue.

-- 
Russell King
 Linux kernel    2.6 ARM Linux   - http://www.arm.linux.org.uk/
 maintainer of:  2.6 Serial core

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH][MMC] Secure Digital (SD) support
  2005-03-05 11:37 ` Russell King
@ 2005-03-05 12:23   ` Pierre Ossman
  2005-03-05 12:44     ` Russell King
  0 siblings, 1 reply; 21+ messages in thread
From: Pierre Ossman @ 2005-03-05 12:23 UTC (permalink / raw)
  To: Russell King; +Cc: LKML, Ian Molton, Richard Purdie

Russell King wrote:

>On Thu, Mar 03, 2005 at 01:22:56PM +0100, Pierre Ossman wrote:
>  
>
>>Here are the patches for Secure Digital support that I've been sitting 
>>on for a while. I tried to get some feedback on inclusion of this 
>>previously but since I didn't get any I'll just submit the thing.
>>It was originally diffed against 2.6.10 but it applies to 2.6.11 just 
>>fine (only minor fuzz).
>>    
>>
>
>Can we please come to a consensus about GEN_FL_REMOVABLE.  After
>talking to other kernel developers, particularly in the block
>interface area, I am convinced that it is fundamentally incorrect
>to set this flag for MMC/SD devices.
>
>Unfortunately, it appears that you're not convinced.  This needs
>resolving since it is an interface issue.
>
>  
>
Oh, sorry. That part wasn't supposed to be included in there.
As I haven't found any applications depending on any specific behaviour 
then I'm quite content with your behaviour :)
I can make a new patch or you can just undo that line once you've 
applied the current one.

Rgds
Pierre


^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH][MMC] Secure Digital (SD) support
  2005-03-05 12:23   ` Pierre Ossman
@ 2005-03-05 12:44     ` Russell King
  2005-03-05 13:46       ` Pierre Ossman
  2005-03-06  1:34       ` [PATCH][MMC][0/6] " Pierre Ossman
  0 siblings, 2 replies; 21+ messages in thread
From: Russell King @ 2005-03-05 12:44 UTC (permalink / raw)
  To: Pierre Ossman, Linus Torvalds; +Cc: LKML, Ian Molton, Richard Purdie

On Sat, Mar 05, 2005 at 01:23:16PM +0100, Pierre Ossman wrote:
> I can make a new patch or you can just undo that line once you've 
> applied the current one.

I'd rather not just apply this patch - there's rather a lot there to
just apply on top of what's already merged.

Is there any chance you can split it up into a smaller set of changes
so it's more obvious what's going on at each stage please?

We'll also need to run this by Linus first, explaining why you believe
it's now ok to merge this.  (Added Linus...)

-- 
Russell King
 Linux kernel    2.6 ARM Linux   - http://www.arm.linux.org.uk/
 maintainer of:  2.6 Serial core

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH][MMC] Secure Digital (SD) support
  2005-03-05 12:44     ` Russell King
@ 2005-03-05 13:46       ` Pierre Ossman
  2005-03-05 16:24         ` Richard Purdie
  2005-05-06 14:15         ` Pierre Ossman
  2005-03-06  1:34       ` [PATCH][MMC][0/6] " Pierre Ossman
  1 sibling, 2 replies; 21+ messages in thread
From: Pierre Ossman @ 2005-03-05 13:46 UTC (permalink / raw)
  To: Russell King; +Cc: Linus Torvalds, LKML, Ian Molton, Richard Purdie

Russell King wrote:

>On Sat, Mar 05, 2005 at 01:23:16PM +0100, Pierre Ossman wrote:
>  
>
>>I can make a new patch or you can just undo that line once you've 
>>applied the current one.
>>    
>>
>
>I'd rather not just apply this patch - there's rather a lot there to
>just apply on top of what's already merged.
>
>Is there any chance you can split it up into a smaller set of changes
>so it's more obvious what's going on at each stage please?
>  
>
Sure. I'll try to divide it into smaller pieces. It will result in some 
patches that are just there to prepare for the other ones though (i.e. 
they don't add any functionality by themselves).

>We'll also need to run this by Linus first, explaining why you believe
>it's now ok to merge this.  (Added Linus...)
>
>  
>
First of, I can't really back up the claim that it isn't ok. The SDA has 
a paragraph about non-disclosure in their "IP Policy" 
(http://www.sdcard.org/membership/images/ippolicy.pdf) but it also 
states that exceptions can be granted.

Against this stands the new information that the SDA is changing its 
policy and making the specs public. This information comes from some of 
the guys at HP research and hasn't been confirmed by any public 
statement from SDA. The SDA have, however, already released the SDIO 
specs. Presumably as part of this new policy.

It was also pointed out in the previous thread by myself, Alan Cox and 
Ian Molton that SD specs have been publically available from different 
companies for quite some time. As such it is difficult for anyone to 
claim that these are secret and can be regulated by a NDA. The only part 
that hasn't been found in the wild is the spec for the 'secure' parts of 
the cards. But that also means that it isn't included in this patch so 
it shouldn't pose a problem.

As always, IANAL so I can't give any definite answer. But from my point 
of view they would have a very weak case if they tried to claim that the 
information in this patch is a trade secret.

Rgds
Pierre



^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH][MMC] Secure Digital (SD) support
  2005-03-05 13:46       ` Pierre Ossman
@ 2005-03-05 16:24         ` Richard Purdie
  2005-05-06 14:15         ` Pierre Ossman
  1 sibling, 0 replies; 21+ messages in thread
From: Richard Purdie @ 2005-03-05 16:24 UTC (permalink / raw)
  To: Pierre Ossman, Russell King; +Cc: Linus Torvalds, LKML, Ian Molton

Pierre Ossman:
> First of, I can't really back up the claim that it isn't ok. The SDA has a 
> paragraph about non-disclosure in their "IP Policy" 
> (http://www.sdcard.org/membership/images/ippolicy.pdf) but it also states 
> that exceptions can be granted.

That IP policy covers their members and has no bearing on us as we have no 
agreements with them.

The code is "our" own so it isn't covered by any IP or copyright 
restrictions other than the GPL.

There aren't any patents relating to SD cards.

The simple sequences we use have been gleaned from various public documents 
(intel's website, SD card manufacturer data sheets, etc.) so nobody can 
claim we're using anything secret.

I therefore can't see a problem with including the code.

Richard 


^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH][MMC][0/6] Secure Digital (SD) support
  2005-03-05 12:44     ` Russell King
  2005-03-05 13:46       ` Pierre Ossman
@ 2005-03-06  1:34       ` Pierre Ossman
  2005-03-06  1:37         ` [PATCH][MMC][1/6] Secure Digital (SD) support : protocol Pierre Ossman
                           ` (6 more replies)
  1 sibling, 7 replies; 21+ messages in thread
From: Pierre Ossman @ 2005-03-06  1:34 UTC (permalink / raw)
  To: Russell King; +Cc: LKML, Ian Molton, Richard Purdie

As promised, here is the patch broken down into smaller pieces. The 
patch is now divided into six distinct parts:

* Protocol definitions.
* SD card initialisation.
* Reading read-only switch.
* Getting SCR register.
* Exposing SCR register through sysfs.
* Wide (4-bit) bus support.

Rgds
Pierre

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH][MMC][1/6] Secure Digital (SD) support : protocol
  2005-03-06  1:34       ` [PATCH][MMC][0/6] " Pierre Ossman
@ 2005-03-06  1:37         ` Pierre Ossman
  2005-03-19 16:35           ` Russell King
  2005-03-06  1:44         ` [PATCH][MMC][2/6] Secure Digital (SD) support : init Pierre Ossman
                           ` (5 subsequent siblings)
  6 siblings, 1 reply; 21+ messages in thread
From: Pierre Ossman @ 2005-03-06  1:37 UTC (permalink / raw)
  To: Russell King; +Cc: LKML, Ian Molton, Richard Purdie

[-- Attachment #1: Type: text/plain, Size: 152 bytes --]

Protocol definitions.

The basic commands needed for the later patches. The R1_APP_CMD seems to 
be misdefined in protocol.h so this patch changes it.


[-- Attachment #2: mmc-sd-protocol.patch --]
[-- Type: text/x-patch, Size: 1778 bytes --]

Index: linux-sd/include/linux/mmc/mmc.h
===================================================================
--- linux-sd/include/linux/mmc/mmc.h	(revision 135)
+++ linux-sd/include/linux/mmc/mmc.h	(working copy)
@@ -37,6 +37,7 @@
 #define MMC_RSP_R1B	(MMC_RSP_SHORT|MMC_RSP_CRC|MMC_RSP_BUSY)
 #define MMC_RSP_R2	(MMC_RSP_LONG|MMC_RSP_CRC)
 #define MMC_RSP_R3	(MMC_RSP_SHORT)
+#define MMC_RSP_R6	(MMC_RSP_SHORT|MMC_RSP_CRC)
 
 	unsigned int		retries;	/* max number of retries */
 	unsigned int		error;		/* command error */
Index: linux-sd/include/linux/mmc/protocol.h
===================================================================
--- linux-sd/include/linux/mmc/protocol.h	(revision 135)
+++ linux-sd/include/linux/mmc/protocol.h	(working copy)
@@ -76,6 +76,16 @@
 #define MMC_APP_CMD              55   /* ac   [31:16] RCA        R1  */
 #define MMC_GEN_CMD              56   /* adtc [0] RD/WR          R1b */
 
+/* SD commands                           type  argument     response */
+  /* class 8 */
+/* This is basically the same command as for MMC with some quirks. */
+#define SD_SEND_RELATIVE_ADDR     3   /* ac                      R6  */
+
+  /* Application commands */
+#define SD_APP_SET_BUS_WIDTH      6   /* ac   [1:0] bus width    R1  */
+#define SD_APP_OP_COND           41   /* bcr  [31:0] OCR         R3  */
+#define SD_APP_SEND_SCR          51   /* adtc                    R1  */
+
 /*
   MMC status in R1
   Type
@@ -113,7 +123,7 @@
 #define R1_STATUS(x)            (x & 0xFFFFE000)
 #define R1_CURRENT_STATE(x)    	((x & 0x00001E00) >> 9)	/* sx, b (4 bits) */
 #define R1_READY_FOR_DATA	(1 << 8)	/* sx, a */
-#define R1_APP_CMD		(1 << 7)	/* sr, c */
+#define R1_APP_CMD		(1 << 5)	/* sr, c */
 
 /* These are unpacked versions of the actual responses */
 

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH][MMC][2/6] Secure Digital (SD) support : init
  2005-03-06  1:34       ` [PATCH][MMC][0/6] " Pierre Ossman
  2005-03-06  1:37         ` [PATCH][MMC][1/6] Secure Digital (SD) support : protocol Pierre Ossman
@ 2005-03-06  1:44         ` Pierre Ossman
  2005-03-06  1:47         ` [PATCH][MMC][3/6] Secure Digital (SD) support : ro Pierre Ossman
                           ` (4 subsequent siblings)
  6 siblings, 0 replies; 21+ messages in thread
From: Pierre Ossman @ 2005-03-06  1:44 UTC (permalink / raw)
  To: Russell King; +Cc: LKML, Ian Molton, Richard Purdie

[-- Attachment #1: Type: text/plain, Size: 865 bytes --]

SD card initialisation.

This patch contains the central parts of the SD support.

The system first tries to detect MMC cards, and if none are found then 
it procedes to look for an SD card. This is incorrect acording to SD 
specifications but I find it odd that MMC is supposed to cope with SD 
commands and not the other way around (since MMC is the older of the 
two). This behaviour is the one Windows uses and has posed no problems 
with any cards tested so far.

It provides flags for the card and host to mark them as SD. The host 
needs to be marked because the MMC layer needs to determine if it should 
send MMC or SD commands at points where no specific card is involved.

A new helper function called mmc_wait_for_app_cmd() is added to handle 
the APP commands which are used frequently with SD.

CID and CSD parsing are extended to handle SD formats.


[-- Attachment #2: mmc-sd-init.patch --]
[-- Type: text/x-patch, Size: 13813 bytes --]

Index: linux-sd/include/linux/mmc/card.h
===================================================================
--- linux-sd/include/linux/mmc/card.h	(revision 135)
+++ linux-sd/include/linux/mmc/card.h	(working copy)
@@ -47,6 +47,7 @@
 #define MMC_STATE_PRESENT	(1<<0)		/* present in sysfs */
 #define MMC_STATE_DEAD		(1<<1)		/* device no longer in stack */
 #define MMC_STATE_BAD		(1<<2)		/* unrecognised device */
+#define MMC_STATE_SDCARD	(1<<3)		/* is an SD card */
 	u32			raw_cid[4];	/* raw card CID */
 	u32			raw_csd[4];	/* raw card CSD */
 	struct mmc_cid		cid;		/* card identification */
@@ -56,10 +57,12 @@
 #define mmc_card_present(c)	((c)->state & MMC_STATE_PRESENT)
 #define mmc_card_dead(c)	((c)->state & MMC_STATE_DEAD)
 #define mmc_card_bad(c)		((c)->state & MMC_STATE_BAD)
+#define mmc_card_sd(c)		((c)->state & MMC_STATE_SDCARD)
 
 #define mmc_card_set_present(c)	((c)->state |= MMC_STATE_PRESENT)
 #define mmc_card_set_dead(c)	((c)->state |= MMC_STATE_DEAD)
 #define mmc_card_set_bad(c)	((c)->state |= MMC_STATE_BAD)
+#define mmc_card_set_sd(c)	((c)->state |= MMC_STATE_SDCARD)
 
 #define mmc_card_name(c)	((c)->cid.prod_name)
 #define mmc_card_id(c)		((c)->dev.bus_id)
Index: linux-sd/include/linux/mmc/mmc.h
===================================================================
--- linux-sd/include/linux/mmc/mmc.h	(revision 136)
+++ linux-sd/include/linux/mmc/mmc.h	(working copy)
@@ -88,6 +88,8 @@
 
 extern int mmc_wait_for_req(struct mmc_host *, struct mmc_request *);
 extern int mmc_wait_for_cmd(struct mmc_host *, struct mmc_command *, int);
+extern int mmc_wait_for_app_cmd(struct mmc_host *, unsigned int,
+	struct mmc_command *, int);
 
 extern int __mmc_claim_host(struct mmc_host *host, struct mmc_card *card);
 
Index: linux-sd/include/linux/mmc/host.h
===================================================================
--- linux-sd/include/linux/mmc/host.h	(revision 135)
+++ linux-sd/include/linux/mmc/host.h	(working copy)
@@ -79,6 +79,10 @@
 	/* private data */
 	struct mmc_ios		ios;		/* current io bus settings */
 	u32			ocr;		/* the current OCR setting */
+	
+	unsigned int		mode;		/* current card mode of host */
+#define MMC_MODE_MMC		0
+#define MMC_MODE_SD		1
 
 	struct list_head	cards;		/* devices attached to this host */
 
Index: linux-sd/drivers/mmc/mmc.c
===================================================================
--- linux-sd/drivers/mmc/mmc.c	(revision 135)
+++ linux-sd/drivers/mmc/mmc.c	(working copy)
@@ -172,8 +172,80 @@
 
 EXPORT_SYMBOL(mmc_wait_for_cmd);
 
+/**
+ *	mmc_wait_for_app_cmd - start an application command and wait for
+ 			       completion
+ *	@host: MMC host to start command
+ *	@rca: RCA to send MMC_APP_CMD to
+ *	@cmd: MMC command to start
+ *	@retries: maximum number of retries
+ *
+ *	Sends a MMC_APP_CMD, checks the card response, sends the command
+ *	in the parameter and waits for it to complete. Return any error
+ *	that occurred while the command was executing.  Do not attempt to
+ *	parse the response.
+ */
+int mmc_wait_for_app_cmd(struct mmc_host *host, unsigned int rca,
+	struct mmc_command *cmd, int retries)
+{
+	struct mmc_request mrq;
+	struct mmc_command appcmd;
+	
+	int i, err;
 
+	BUG_ON(host->card_busy == NULL);
+	BUG_ON(retries < 0);
+	
+	err = MMC_ERR_INVALID;
+	
+	/*
+	 * We have to resend MMC_APP_CMD for each attempt so
+	 * we cannot use the retries field in mmc_command.
+	 */
+	for (i = 0;i <= retries;i++) {
+		memset(&mrq, 0, sizeof(struct mmc_request));
 
+		appcmd.opcode = MMC_APP_CMD;
+		appcmd.arg = rca << 16;
+		appcmd.flags = MMC_RSP_R1;
+		appcmd.retries = 0;
+		memset(appcmd.resp, 0, sizeof(appcmd.resp));
+		appcmd.data = NULL;
+		
+		mrq.cmd = &appcmd;
+		appcmd.data = NULL;
+		
+		mmc_wait_for_req(host, &mrq);
+		
+		if (appcmd.error) {
+			err = appcmd.error;
+			continue;
+		}
+		
+		/* Check that card supported application commands */
+		if (!(appcmd.resp[0] & R1_APP_CMD))
+			return MMC_ERR_FAILED;
+
+		memset(&mrq, 0, sizeof(struct mmc_request));
+
+		memset(cmd->resp, 0, sizeof(cmd->resp));
+		cmd->retries = 0;
+
+		mrq.cmd = cmd;
+		cmd->data = NULL;
+
+		mmc_wait_for_req(host, &mrq);
+		
+		err = cmd->error;
+		if (cmd->error == MMC_ERR_NONE)
+			break;
+	}
+
+	return err;
+}
+
+EXPORT_SYMBOL(mmc_wait_for_app_cmd);
+
 /**
  *	__mmc_claim_host - exclusively claim a host
  *	@host: mmc host to claim
@@ -322,48 +394,70 @@
 
 	memset(&card->cid, 0, sizeof(struct mmc_cid));
 
-	/*
-	 * The selection of the format here is guesswork based upon
-	 * information people have sent to date.
-	 */
-	switch (card->csd.mmca_vsn) {
-	case 0: /* MMC v1.? */
-	case 1: /* MMC v1.4 */
-		card->cid.manfid	= UNSTUFF_BITS(resp, 104, 24);
-		card->cid.prod_name[0]	= UNSTUFF_BITS(resp, 96, 8);
-		card->cid.prod_name[1]	= UNSTUFF_BITS(resp, 88, 8);
-		card->cid.prod_name[2]	= UNSTUFF_BITS(resp, 80, 8);
-		card->cid.prod_name[3]	= UNSTUFF_BITS(resp, 72, 8);
-		card->cid.prod_name[4]	= UNSTUFF_BITS(resp, 64, 8);
-		card->cid.prod_name[5]	= UNSTUFF_BITS(resp, 56, 8);
-		card->cid.prod_name[6]	= UNSTUFF_BITS(resp, 48, 8);
-		card->cid.hwrev		= UNSTUFF_BITS(resp, 44, 4);
-		card->cid.fwrev		= UNSTUFF_BITS(resp, 40, 4);
-		card->cid.serial	= UNSTUFF_BITS(resp, 16, 24);
-		card->cid.month		= UNSTUFF_BITS(resp, 12, 4);
-		card->cid.year		= UNSTUFF_BITS(resp, 8, 4) + 1997;
-		break;
+	if (mmc_card_sd(card)) {
+		/*
+		 * SD doesn't currently have a version field so we will
+		 * have to assume we can parse this.
+		 */
+		card->cid.manfid		= UNSTUFF_BITS(resp, 120, 8);
+		card->cid.oemid			= UNSTUFF_BITS(resp, 104, 16);
+		card->cid.prod_name[0]		= UNSTUFF_BITS(resp, 96, 8);
+		card->cid.prod_name[1]		= UNSTUFF_BITS(resp, 88, 8);
+		card->cid.prod_name[2]		= UNSTUFF_BITS(resp, 80, 8);
+		card->cid.prod_name[3]		= UNSTUFF_BITS(resp, 72, 8);
+		card->cid.prod_name[4]		= UNSTUFF_BITS(resp, 64, 8);
+		card->cid.hwrev			= UNSTUFF_BITS(resp, 60, 4);
+		card->cid.fwrev			= UNSTUFF_BITS(resp, 56, 4);
+		card->cid.serial		= UNSTUFF_BITS(resp, 24, 32);
+		card->cid.year			= UNSTUFF_BITS(resp, 12, 8);
+		card->cid.month			= UNSTUFF_BITS(resp, 8, 4);
 
-	case 2: /* MMC v2.x ? */
-	case 3: /* MMC v3.x ? */
-		card->cid.manfid	= UNSTUFF_BITS(resp, 120, 8);
-		card->cid.oemid		= UNSTUFF_BITS(resp, 104, 16);
-		card->cid.prod_name[0]	= UNSTUFF_BITS(resp, 96, 8);
-		card->cid.prod_name[1]	= UNSTUFF_BITS(resp, 88, 8);
-		card->cid.prod_name[2]	= UNSTUFF_BITS(resp, 80, 8);
-		card->cid.prod_name[3]	= UNSTUFF_BITS(resp, 72, 8);
-		card->cid.prod_name[4]	= UNSTUFF_BITS(resp, 64, 8);
-		card->cid.prod_name[5]	= UNSTUFF_BITS(resp, 56, 8);
-		card->cid.serial	= UNSTUFF_BITS(resp, 16, 32);
-		card->cid.month		= UNSTUFF_BITS(resp, 12, 4);
-		card->cid.year		= UNSTUFF_BITS(resp, 8, 4) + 1997;
-		break;
+		card->cid.year += 2000; /* SD cards year offset */
+	}
+	else {
+		/*
+		 * The selection of the format here is based upon published
+		 * specs from sandisk and from what people have reported.
+		 */
+		switch (card->csd.mmca_vsn) {
+		case 0: /* MMC v1.0 - v1.2 */
+		case 1: /* MMC v1.4 */
+			card->cid.manfid	= UNSTUFF_BITS(resp, 104, 24);
+			card->cid.prod_name[0]	= UNSTUFF_BITS(resp, 96, 8);
+			card->cid.prod_name[1]	= UNSTUFF_BITS(resp, 88, 8);
+			card->cid.prod_name[2]	= UNSTUFF_BITS(resp, 80, 8);
+			card->cid.prod_name[3]	= UNSTUFF_BITS(resp, 72, 8);
+			card->cid.prod_name[4]	= UNSTUFF_BITS(resp, 64, 8);
+			card->cid.prod_name[5]	= UNSTUFF_BITS(resp, 56, 8);
+			card->cid.prod_name[6]	= UNSTUFF_BITS(resp, 48, 8);
+			card->cid.hwrev		= UNSTUFF_BITS(resp, 44, 4);
+			card->cid.fwrev		= UNSTUFF_BITS(resp, 40, 4);
+			card->cid.serial	= UNSTUFF_BITS(resp, 16, 24);
+			card->cid.month		= UNSTUFF_BITS(resp, 12, 4);
+			card->cid.year		= UNSTUFF_BITS(resp, 8, 4) + 1997;
+			break;
 
-	default:
-		printk("%s: card has unknown MMCA version %d\n",
-			card->host->host_name, card->csd.mmca_vsn);
-		mmc_card_set_bad(card);
-		break;
+		case 2: /* MMC v2.0 - v2.2 */
+		case 3: /* MMC v3.1 - v3.3 */
+			card->cid.manfid	= UNSTUFF_BITS(resp, 120, 8);
+			card->cid.oemid		= UNSTUFF_BITS(resp, 104, 16);
+			card->cid.prod_name[0]	= UNSTUFF_BITS(resp, 96, 8);
+			card->cid.prod_name[1]	= UNSTUFF_BITS(resp, 88, 8);
+			card->cid.prod_name[2]	= UNSTUFF_BITS(resp, 80, 8);
+			card->cid.prod_name[3]	= UNSTUFF_BITS(resp, 72, 8);
+			card->cid.prod_name[4]	= UNSTUFF_BITS(resp, 64, 8);
+			card->cid.prod_name[5]	= UNSTUFF_BITS(resp, 56, 8);
+			card->cid.serial	= UNSTUFF_BITS(resp, 16, 32);
+			card->cid.month		= UNSTUFF_BITS(resp, 12, 4);
+			card->cid.year		= UNSTUFF_BITS(resp, 8, 4) + 1997;
+			break;
+
+		default:
+			printk("%s: card has unknown MMCA version %d\n",
+				card->host->host_name, card->csd.mmca_vsn);
+			mmc_card_set_bad(card);
+			break;
+		}
 	}
 }
 
@@ -375,35 +469,62 @@
 	struct mmc_csd *csd = &card->csd;
 	unsigned int e, m, csd_struct;
 	u32 *resp = card->raw_csd;
+	
+	if (mmc_card_sd(card)) {
+		csd_struct = UNSTUFF_BITS(resp, 126, 2);
+		if (csd_struct != 0) {
+			printk("%s: unrecognised CSD structure version %d\n",
+				card->host->host_name, csd_struct);
+			mmc_card_set_bad(card);
+			return;
+		}
+		
+		m = UNSTUFF_BITS(resp, 115, 4);
+		e = UNSTUFF_BITS(resp, 112, 3);
+		csd->tacc_ns	 = (tacc_exp[e] * tacc_mant[m] + 9) / 10;
+		csd->tacc_clks	 = UNSTUFF_BITS(resp, 104, 8) * 100;
 
-	/*
-	 * We only understand CSD structure v1.1 and v2.
-	 * v2 has extra information in bits 15, 11 and 10.
-	 */
-	csd_struct = UNSTUFF_BITS(resp, 126, 2);
-	if (csd_struct != 1 && csd_struct != 2) {
-		printk("%s: unrecognised CSD structure version %d\n",
-			card->host->host_name, csd_struct);
-		mmc_card_set_bad(card);
-		return;
+		m = UNSTUFF_BITS(resp, 99, 4);
+		e = UNSTUFF_BITS(resp, 96, 3);
+		csd->max_dtr	  = tran_exp[e] * tran_mant[m];
+		csd->cmdclass	  = UNSTUFF_BITS(resp, 84, 12);
+
+		e = UNSTUFF_BITS(resp, 47, 3);
+		m = UNSTUFF_BITS(resp, 62, 12);
+		csd->capacity	  = (1 + m) << (e + 2);
+
+		csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4);
 	}
+	else {
+		/*
+		 * We only understand CSD structure v1.1 and v1.2.
+		 * v1.2 has extra information in bits 15, 11 and 10.
+		 */
+		csd_struct = UNSTUFF_BITS(resp, 126, 2);
+		if (csd_struct != 1 && csd_struct != 2) {
+			printk("%s: unrecognised CSD structure version %d\n",
+				card->host->host_name, csd_struct);
+			mmc_card_set_bad(card);
+			return;
+		}
 
-	csd->mmca_vsn	 = UNSTUFF_BITS(resp, 122, 4);
-	m = UNSTUFF_BITS(resp, 115, 4);
-	e = UNSTUFF_BITS(resp, 112, 3);
-	csd->tacc_ns	 = (tacc_exp[e] * tacc_mant[m] + 9) / 10;
-	csd->tacc_clks	 = UNSTUFF_BITS(resp, 104, 8) * 100;
+		csd->mmca_vsn	 = UNSTUFF_BITS(resp, 122, 4);
+		m = UNSTUFF_BITS(resp, 115, 4);
+		e = UNSTUFF_BITS(resp, 112, 3);
+		csd->tacc_ns	 = (tacc_exp[e] * tacc_mant[m] + 9) / 10;
+		csd->tacc_clks	 = UNSTUFF_BITS(resp, 104, 8) * 100;
 
-	m = UNSTUFF_BITS(resp, 99, 4);
-	e = UNSTUFF_BITS(resp, 96, 3);
-	csd->max_dtr	  = tran_exp[e] * tran_mant[m];
-	csd->cmdclass	  = UNSTUFF_BITS(resp, 84, 12);
+		m = UNSTUFF_BITS(resp, 99, 4);
+		e = UNSTUFF_BITS(resp, 96, 3);
+		csd->max_dtr	  = tran_exp[e] * tran_mant[m];
+		csd->cmdclass	  = UNSTUFF_BITS(resp, 84, 12);
 
-	e = UNSTUFF_BITS(resp, 47, 3);
-	m = UNSTUFF_BITS(resp, 62, 12);
-	csd->capacity	  = (1 + m) << (e + 2);
+		e = UNSTUFF_BITS(resp, 47, 3);
+		m = UNSTUFF_BITS(resp, 62, 12);
+		csd->capacity	  = (1 + m) << (e + 2);
 
-	csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4);
+		csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4);
+	}
 }
 
 /*
@@ -524,6 +645,34 @@
 	return err;
 }
 
+static int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
+{
+	struct mmc_command cmd;
+	int i, err = 0;
+
+	cmd.opcode = SD_APP_OP_COND;
+	cmd.arg = ocr;
+	cmd.flags = MMC_RSP_R3;
+
+	for (i = 100; i; i--) {
+		err = mmc_wait_for_app_cmd(host, 0, &cmd, CMD_RETRIES);
+		if (err != MMC_ERR_NONE)
+			break;
+
+		if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0)
+			break;
+
+		err = MMC_ERR_TIMEOUT;
+
+		mmc_delay(10);
+	}
+
+	if (rocr)
+		*rocr = cmd.resp[0];
+
+	return err;
+}
+
 /*
  * Discover cards by requesting their CID.  If this command
  * times out, it is not an error; there are no further cards
@@ -566,14 +715,29 @@
 		}
 
 		card->state &= ~MMC_STATE_DEAD;
+		
+		if (host->mode == MMC_MODE_SD) {
+			mmc_card_set_sd(card);
 
-		cmd.opcode = MMC_SET_RELATIVE_ADDR;
-		cmd.arg = card->rca << 16;
-		cmd.flags = MMC_RSP_R1;
+			cmd.opcode = SD_SEND_RELATIVE_ADDR;
+			cmd.arg = 0;
+			cmd.flags = MMC_RSP_R1;
 
-		err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
-		if (err != MMC_ERR_NONE)
-			mmc_card_set_dead(card);
+			err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
+			if (err != MMC_ERR_NONE)
+				mmc_card_set_dead(card);
+			else
+				card->rca = cmd.resp[0] >> 16;
+		}
+		else {
+			cmd.opcode = MMC_SET_RELATIVE_ADDR;
+			cmd.arg = card->rca << 16;
+			cmd.flags = MMC_RSP_R1;
+
+			err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
+			if (err != MMC_ERR_NONE)
+				mmc_card_set_dead(card);
+		}
 	}
 }
 
@@ -656,13 +820,26 @@
 	if (host->ios.power_mode != MMC_POWER_ON) {
 		int err;
 		u32 ocr;
+		
+		host->mode = MMC_MODE_MMC;
 
 		mmc_power_up(host);
 		mmc_idle_cards(host);
 
 		err = mmc_send_op_cond(host, 0, &ocr);
+		
+		/*
+		 * If we fail to detect any cards then try
+		 * searching for SD cards.
+		 */
 		if (err != MMC_ERR_NONE)
-			return;
+		{
+			err = mmc_send_app_op_cond(host, 0, &ocr);
+			if (err != MMC_ERR_NONE)
+				return;
+			
+			host->mode = MMC_MODE_SD;
+		}
 
 		host->ocr = mmc_select_voltage(host, ocr);
 
@@ -702,7 +879,10 @@
 	 * all get the idea that they should be ready for CMD2.
 	 * (My SanDisk card seems to need this.)
 	 */
-	mmc_send_op_cond(host, host->ocr, NULL);
+	if (host->mode == MMC_MODE_SD)
+		mmc_send_app_op_cond(host, host->ocr, NULL);
+	else
+		mmc_send_op_cond(host, host->ocr, NULL);
 
 	mmc_discover_cards(host);
 

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH][MMC][3/6] Secure Digital (SD) support : ro
  2005-03-06  1:34       ` [PATCH][MMC][0/6] " Pierre Ossman
  2005-03-06  1:37         ` [PATCH][MMC][1/6] Secure Digital (SD) support : protocol Pierre Ossman
  2005-03-06  1:44         ` [PATCH][MMC][2/6] Secure Digital (SD) support : init Pierre Ossman
@ 2005-03-06  1:47         ` Pierre Ossman
  2005-03-06  1:50         ` [PATCH][MMC][4/6] Secure Digital (SD) support : SCR Pierre Ossman
                           ` (3 subsequent siblings)
  6 siblings, 0 replies; 21+ messages in thread
From: Pierre Ossman @ 2005-03-06  1:47 UTC (permalink / raw)
  To: Russell King; +Cc: LKML, Ian Molton, Richard Purdie

[-- Attachment #1: Type: text/plain, Size: 396 bytes --]

Read-only support.

This patch adds a new callback for the drivers to facilitate reading the 
SD card read-only switch. If the callback is not provided then a warning 
will be printed and it will default to write-enable.

The read-only switch is a host enforced read-only so the MMC block layer 
has been changed to not allow rw mounts of ro cards. It also prints a 
'(ro)' for read-only cards.


[-- Attachment #2: mmc-sd-ro.patch --]
[-- Type: text/x-patch, Size: 3270 bytes --]

Index: linux-sd/include/linux/mmc/card.h
===================================================================
--- linux-sd/include/linux/mmc/card.h	(revision 137)
+++ linux-sd/include/linux/mmc/card.h	(working copy)
@@ -48,6 +48,7 @@
 #define MMC_STATE_DEAD		(1<<1)		/* device no longer in stack */
 #define MMC_STATE_BAD		(1<<2)		/* unrecognised device */
 #define MMC_STATE_SDCARD	(1<<3)		/* is an SD card */
+#define MMC_STATE_READONLY	(1<<4)		/* card is read-only */
 	u32			raw_cid[4];	/* raw card CID */
 	u32			raw_csd[4];	/* raw card CSD */
 	struct mmc_cid		cid;		/* card identification */
@@ -58,11 +59,13 @@
 #define mmc_card_dead(c)	((c)->state & MMC_STATE_DEAD)
 #define mmc_card_bad(c)		((c)->state & MMC_STATE_BAD)
 #define mmc_card_sd(c)		((c)->state & MMC_STATE_SDCARD)
+#define mmc_card_readonly(c)	((c)->state & MMC_STATE_READONLY)
 
 #define mmc_card_set_present(c)	((c)->state |= MMC_STATE_PRESENT)
 #define mmc_card_set_dead(c)	((c)->state |= MMC_STATE_DEAD)
 #define mmc_card_set_bad(c)	((c)->state |= MMC_STATE_BAD)
 #define mmc_card_set_sd(c)	((c)->state |= MMC_STATE_SDCARD)
+#define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY)
 
 #define mmc_card_name(c)	((c)->cid.prod_name)
 #define mmc_card_id(c)		((c)->dev.bus_id)
Index: linux-sd/include/linux/mmc/host.h
===================================================================
--- linux-sd/include/linux/mmc/host.h	(revision 137)
+++ linux-sd/include/linux/mmc/host.h	(working copy)
@@ -56,6 +56,7 @@
 struct mmc_host_ops {
 	void	(*request)(struct mmc_host *host, struct mmc_request *req);
 	void	(*set_ios)(struct mmc_host *host, struct mmc_ios *ios);
+	int	(*get_ro)(struct mmc_host *host);
 };
 
 struct mmc_card;
Index: linux-sd/drivers/mmc/mmc_block.c
===================================================================
--- linux-sd/drivers/mmc/mmc_block.c	(revision 135)
+++ linux-sd/drivers/mmc/mmc_block.c	(working copy)
@@ -95,6 +95,10 @@
 		if (md->usage == 2)
 			check_disk_change(inode->i_bdev);
 		ret = 0;
+		
+		if ((filp->f_mode & FMODE_WRITE) &&
+			mmc_card_readonly(md->queue.card))
+			ret = -EROFS;
 	}
 
 	return ret;
@@ -400,9 +404,10 @@
 	if (err)
 		goto out;
 
-	printk(KERN_INFO "%s: %s %s %dKiB\n",
+	printk(KERN_INFO "%s: %s %s %dKiB %s\n",
 		md->disk->disk_name, mmc_card_id(card), mmc_card_name(card),
-		(card->csd.capacity << card->csd.read_blkbits) / 1024);
+		(card->csd.capacity << card->csd.read_blkbits) / 1024,
+		mmc_card_readonly(card)?"(ro)":"");
 
 	mmc_set_drvdata(card, md);
 	add_disk(md->disk);
Index: linux-sd/drivers/mmc/mmc.c
===================================================================
--- linux-sd/drivers/mmc/mmc.c	(revision 137)
+++ linux-sd/drivers/mmc/mmc.c	(working copy)
@@ -726,8 +726,20 @@
 			err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
 			if (err != MMC_ERR_NONE)
 				mmc_card_set_dead(card);
-			else
+			else {			
 				card->rca = cmd.resp[0] >> 16;
+				
+				if (!host->ops->get_ro) {
+					printk(KERN_WARNING "%s: host does not "
+						"support reading read-only "
+						"switch. assuming write-enable.\n",
+						host->host_name);
+				}
+				else {
+					if (host->ops->get_ro(host))
+						mmc_card_set_readonly(card);
+				}
+			}
 		}
 		else {
 			cmd.opcode = MMC_SET_RELATIVE_ADDR;

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH][MMC][4/6] Secure Digital (SD) support : SCR
  2005-03-06  1:34       ` [PATCH][MMC][0/6] " Pierre Ossman
                           ` (2 preceding siblings ...)
  2005-03-06  1:47         ` [PATCH][MMC][3/6] Secure Digital (SD) support : ro Pierre Ossman
@ 2005-03-06  1:50         ` Pierre Ossman
  2005-03-06  1:52         ` [PATCH][MMC][5/6] Secure Digital (SD) support : sysfs Pierre Ossman
                           ` (2 subsequent siblings)
  6 siblings, 0 replies; 21+ messages in thread
From: Pierre Ossman @ 2005-03-06  1:50 UTC (permalink / raw)
  To: Russell King; +Cc: LKML, Ian Molton, Richard Purdie

[-- Attachment #1: Type: text/plain, Size: 374 bytes --]

SCR download.

This patch downloads the SCR register from the card. Unlike the other 
registers this one is transfered over the data bus. That required some 
changes to other routines to allow a card to be selected after the host 
was aquired.

This is one of the more error prone parts. The transfer is very small (8 
bytes) and might trigger corner cases in the drivers.


[-- Attachment #2: mmc-sd-scr.patch --]
[-- Type: text/x-patch, Size: 5201 bytes --]

Index: linux-sd/include/linux/mmc/card.h
===================================================================
--- linux-sd/include/linux/mmc/card.h	(revision 138)
+++ linux-sd/include/linux/mmc/card.h	(working copy)
@@ -33,6 +33,13 @@
 	unsigned int		capacity;
 };
 
+struct sd_scr {
+	unsigned char		sda_vsn;
+	unsigned char		bus_widths;
+#define SD_SCR_BUS_WIDTH_1	(1<<0)
+#define SD_SCR_BUS_WIDTH_4	(1<<2)
+};
+
 struct mmc_host;
 
 /*
@@ -51,8 +58,10 @@
 #define MMC_STATE_READONLY	(1<<4)		/* card is read-only */
 	u32			raw_cid[4];	/* raw card CID */
 	u32			raw_csd[4];	/* raw card CSD */
+	u32			raw_scr[2];	/* raw card SCR */
 	struct mmc_cid		cid;		/* card identification */
 	struct mmc_csd		csd;		/* card specific */
+	struct sd_scr		scr;		/* extra SD information */
 };
 
 #define mmc_card_present(c)	((c)->state & MMC_STATE_PRESENT)
Index: linux-sd/drivers/mmc/mmc.c
===================================================================
--- linux-sd/drivers/mmc/mmc.c	(revision 138)
+++ linux-sd/drivers/mmc/mmc.c	(working copy)
@@ -16,6 +16,8 @@
 #include <linux/delay.h>
 #include <linux/pagemap.h>
 #include <linux/err.h>
+#include <asm/scatterlist.h>
+#include <linux/scatterlist.h>
 
 #include <linux/mmc/card.h>
 #include <linux/mmc/host.h>
@@ -246,6 +248,8 @@
 
 EXPORT_SYMBOL(mmc_wait_for_app_cmd);
 
+static int mmc_select_card(struct mmc_host *host, struct mmc_card *card);
+
 /**
  *	__mmc_claim_host - exclusively claim a host
  *	@host: mmc host to claim
@@ -278,16 +282,10 @@
 	spin_unlock_irqrestore(&host->lock, flags);
 	remove_wait_queue(&host->wq, &wait);
 
-	if (card != (void *)-1 && host->card_selected != card) {
-		struct mmc_command cmd;
-
-		host->card_selected = card;
-
-		cmd.opcode = MMC_SELECT_CARD;
-		cmd.arg = card->rca << 16;
-		cmd.flags = MMC_RSP_R1;
-
-		err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
+	if (card != (void *)-1) {
+		err = mmc_select_card(host, card);
+		if (err != MMC_ERR_NONE)
+			return err;
 	}
 
 	return err;
@@ -317,6 +315,29 @@
 
 EXPORT_SYMBOL(mmc_release_host);
 
+static int mmc_select_card(struct mmc_host *host, struct mmc_card *card)
+{
+	int err;
+	struct mmc_command cmd;
+
+	BUG_ON(host->card_busy == NULL);
+	
+	if (host->card_selected == card)
+		return MMC_ERR_NONE;
+
+	host->card_selected = card;
+
+	cmd.opcode = MMC_SELECT_CARD;
+	cmd.arg = card->rca << 16;
+	cmd.flags = MMC_RSP_R1;
+
+	err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
+	if (err != MMC_ERR_NONE)
+		return err;
+
+	return MMC_ERR_NONE;
+}
+
 /*
  * Ensure that no card is selected.
  */
@@ -528,6 +549,32 @@
 }
 
 /*
+ * Given a 64-bit response, decode to our card SCR structure.
+ */
+static void mmc_decode_scr(struct mmc_card *card)
+{
+	struct sd_scr *scr = &card->scr;
+	unsigned int scr_struct;
+	u32 resp[4];
+
+	BUG_ON(!mmc_card_sd(card));
+	
+	resp[3] = card->raw_scr[1];
+	resp[2] = card->raw_scr[0];
+	
+	scr_struct = UNSTUFF_BITS(resp, 60, 4);
+	if (scr_struct != 0) {
+		printk("%s: unrecognised SCR structure version %d\n",
+			card->host->host_name, scr_struct);
+		mmc_card_set_bad(card);
+		return;
+	}
+	
+	scr->sda_vsn = UNSTUFF_BITS(resp, 56, 4);
+	scr->bus_widths = UNSTUFF_BITS(resp, 48, 4);
+}
+
+/*
  * Locate a MMC card on this MMC host given a raw CID.
  */
 static struct mmc_card *mmc_find_card(struct mmc_host *host, u32 *raw_cid)
@@ -781,6 +828,80 @@
 	}
 }
 
+static void mmc_read_scrs(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;
+	
+	list_for_each_entry(card, &host->cards, node) {
+		if (card->state & (MMC_STATE_DEAD|MMC_STATE_PRESENT))
+			continue;
+		if (!mmc_card_sd(card))
+			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_APP_CMD;
+		cmd.arg = card->rca << 16;
+		cmd.flags = MMC_RSP_R1;
+		
+		err = mmc_wait_for_cmd(host, &cmd, 0);
+		if ((err != MMC_ERR_NONE) || !(cmd.resp[0] & R1_APP_CMD)) {
+			mmc_card_set_dead(card);
+			continue;
+		}
+		
+		memset(&cmd, 0, sizeof(struct mmc_command));
+		
+		cmd.opcode = SD_APP_SEND_SCR;
+		cmd.arg = 0;
+		cmd.flags = MMC_RSP_R1;
+		
+		memset(&data, 0, sizeof(struct mmc_data));
+		
+		data.timeout_ns = card->csd.tacc_ns * 10;
+		data.timeout_clks = card->csd.tacc_clks * 10;
+		data.blksz_bits = 3;
+		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, (u8*)card->raw_scr, 64);
+		
+		err = mmc_wait_for_req(host, &mrq);
+		if (err != MMC_ERR_NONE) {
+			mmc_card_set_dead(card);
+			continue;
+		}
+		
+		card->raw_scr[0] = ntohl(card->raw_scr[0]);
+		card->raw_scr[1] = ntohl(card->raw_scr[1]);
+
+		mmc_decode_scr(card);
+	}
+	
+	mmc_deselect_cards(host);
+}
+
 static unsigned int mmc_calculate_clock(struct mmc_host *host)
 {
 	struct mmc_card *card;
@@ -905,6 +1026,9 @@
 	host->ops->set_ios(host, &host->ios);
 
 	mmc_read_csds(host);
+	
+	if (host->mode == MMC_MODE_SD)
+		mmc_read_scrs(host);
 }
 
 

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH][MMC][5/6] Secure Digital (SD) support : sysfs
  2005-03-06  1:34       ` [PATCH][MMC][0/6] " Pierre Ossman
                           ` (3 preceding siblings ...)
  2005-03-06  1:50         ` [PATCH][MMC][4/6] Secure Digital (SD) support : SCR Pierre Ossman
@ 2005-03-06  1:52         ` Pierre Ossman
  2005-03-06  1:57         ` [PATCH][MMC][6/6] Secure Digital (SD) support : wide bus Pierre Ossman
  2005-03-12 17:35         ` [PATCH][MMC][7/6] Secure Digital (SD) support : Copyright Pierre Ossman
  6 siblings, 0 replies; 21+ messages in thread
From: Pierre Ossman @ 2005-03-06  1:52 UTC (permalink / raw)
  To: Russell King; +Cc: LKML, Ian Molton, Richard Purdie

[-- Attachment #1: Type: text/plain, Size: 214 bytes --]

SCR sysfs access.

This provides access to the SCR register via sysfs. Since the latest bk 
contains some changes to the sysfs part this probably needs updating. 
The patch is trivial though so it should be easy.


[-- Attachment #2: mmc-sd-sysfs.patch --]
[-- Type: text/x-patch, Size: 789 bytes --]

Index: linux-sd/drivers/mmc/mmc_sysfs.c
===================================================================
--- linux-sd/drivers/mmc/mmc_sysfs.c	(revision 135)
+++ linux-sd/drivers/mmc/mmc_sysfs.c	(working copy)
@@ -163,6 +163,7 @@
 	card->raw_cid[2], card->raw_cid[3]);
 MMC_ATTR(csd, "%08x%08x%08x%08x\n", card->raw_csd[0], card->raw_csd[1],
 	card->raw_csd[2], card->raw_csd[3]);
+MMC_ATTR(scr, "%08x%08x\n", card->raw_scr[0], card->raw_scr[1]);
 MMC_ATTR(date, "%02d/%04d\n", card->cid.month, card->cid.year);
 MMC_ATTR(fwrev, "0x%x\n", card->cid.fwrev);
 MMC_ATTR(hwrev, "0x%x\n", card->cid.hwrev);
@@ -174,6 +175,7 @@
 static struct device_attribute *mmc_dev_attributes[] = {
 	&dev_attr_cid,
 	&dev_attr_csd,
+	&dev_attr_scr,
 	&dev_attr_date,
 	&dev_attr_fwrev,
 	&dev_attr_hwrev,

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH][MMC][6/6] Secure Digital (SD) support : wide bus
  2005-03-06  1:34       ` [PATCH][MMC][0/6] " Pierre Ossman
                           ` (4 preceding siblings ...)
  2005-03-06  1:52         ` [PATCH][MMC][5/6] Secure Digital (SD) support : sysfs Pierre Ossman
@ 2005-03-06  1:57         ` Pierre Ossman
  2005-03-12 17:35         ` [PATCH][MMC][7/6] Secure Digital (SD) support : Copyright Pierre Ossman
  6 siblings, 0 replies; 21+ messages in thread
From: Pierre Ossman @ 2005-03-06  1:57 UTC (permalink / raw)
  To: Russell King; +Cc: LKML, Ian Molton, Richard Purdie

[-- Attachment #1: Type: text/plain, Size: 737 bytes --]

Wide bus support.

This adds 4-bit bus support to the MMC layer. It is designed to 
(hopefully) be compatible with a future 4-bit MMC implementation. This 
is done by seperating the three different instances of bus width defines:

* Protocol definition: SD_BUS_WIDTH_x
* SCR contents: SD_SCR_BUS_WIDTH_x
* Host mode: MMC_BUS_WIDTH_x

They have the same values atm but drivers should not rely on this. 
MMC_BUS_WIDTH_x is not meant to be SD specific.

The MMC layer changes bus width when a card is selected. This is because 
the SD spec says that a card is only required to keep a certain bus 
width as long as it's selected.

Layers further up do not need to know which mode the host/card is in. 
They will only see a change in speed.


[-- Attachment #2: mmc-sd-4bit.patch --]
[-- Type: text/x-patch, Size: 2920 bytes --]

Index: linux-sd/include/linux/mmc/host.h
===================================================================
--- linux-sd/include/linux/mmc/host.h	(revision 138)
+++ linux-sd/include/linux/mmc/host.h	(working copy)
@@ -51,6 +51,11 @@
 #define MMC_POWER_OFF		0
 #define MMC_POWER_UP		1
 #define MMC_POWER_ON		2
+
+	unsigned char	bus_width;		/* data bus width */
+
+#define MMC_BUS_WIDTH_1		0
+#define MMC_BUS_WIDTH_4		2
 };
 
 struct mmc_host_ops {
@@ -69,7 +74,11 @@
 	unsigned int		f_max;
 	u32			ocr_avail;
 	char			host_name[8];
+	
+	unsigned long		caps;		/* Host capabilities */
 
+#define MMC_CAP_4_BIT_DATA	(1 << 0)	/* Can the host do 4 bit transfers */
+
 	/* host specific block data */
 	unsigned int		max_seg_size;	/* see blk_queue_max_segment_size */
 	unsigned short		max_hw_segs;	/* see blk_queue_max_hw_segments */
Index: linux-sd/include/linux/mmc/protocol.h
===================================================================
--- linux-sd/include/linux/mmc/protocol.h	(revision 136)
+++ linux-sd/include/linux/mmc/protocol.h	(working copy)
@@ -209,5 +209,12 @@
 #define CSD_SPEC_VER_2      2           /* Implements system specification 2.0 - 2.2 */
 #define CSD_SPEC_VER_3      3           /* Implements system specification 3.1 */
 
+
+/*
+ * SD bus widths
+ */
+#define SD_BUS_WIDTH_1      0
+#define SD_BUS_WIDTH_4      2
+
 #endif  /* MMC_MMC_PROTOCOL_H */
 
Index: linux-sd/drivers/mmc/mmc.c
===================================================================
--- linux-sd/drivers/mmc/mmc.c	(revision 139)
+++ linux-sd/drivers/mmc/mmc.c	(working copy)
@@ -335,6 +335,40 @@
 	if (err != MMC_ERR_NONE)
 		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
+	 * 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)) {
+			struct mmc_command cmd;
+			cmd.opcode = SD_APP_SET_BUS_WIDTH;
+			cmd.arg = SD_BUS_WIDTH_4;
+			cmd.flags = MMC_RSP_R1;
+			
+			err = mmc_wait_for_app_cmd(host, card->rca, &cmd,
+				CMD_RETRIES);
+			if (err != MMC_ERR_NONE)
+				return err;
+			
+			host->ios.bus_width = MMC_BUS_WIDTH_4;
+		}
+	}
+
+	host->ops->set_ios(host, &host->ios);
+
 	return MMC_ERR_NONE;
 }
 
@@ -644,6 +678,7 @@
 	host->ios.vdd = bit;
 	host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
 	host->ios.power_mode = MMC_POWER_UP;
+	host->ios.bus_width = MMC_BUS_WIDTH_1;
 	host->ops->set_ios(host, &host->ios);
 
 	mmc_delay(1);
@@ -661,6 +696,7 @@
 	host->ios.vdd = 0;
 	host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
 	host->ios.power_mode = MMC_POWER_OFF;
+	host->ios.bus_width = MMC_BUS_WIDTH_1;
 	host->ops->set_ios(host, &host->ios);
 }
 

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH][MMC][7/6] Secure Digital (SD) support : Copyright
  2005-03-06  1:34       ` [PATCH][MMC][0/6] " Pierre Ossman
                           ` (5 preceding siblings ...)
  2005-03-06  1:57         ` [PATCH][MMC][6/6] Secure Digital (SD) support : wide bus Pierre Ossman
@ 2005-03-12 17:35         ` Pierre Ossman
  6 siblings, 0 replies; 21+ messages in thread
From: Pierre Ossman @ 2005-03-12 17:35 UTC (permalink / raw)
  To: Russell King; +Cc: LKML, Ian Molton, Richard Purdie

[-- Attachment #1: Type: text/plain, Size: 183 bytes --]

I suppose a copyright notice is appropriate to indicate the origins of
the SD additions.

mmc.c is the only file with substancial changes so it should be enough
with a notice there.


[-- Attachment #2: mmc-sd-copyright.patch --]
[-- Type: text/x-patch, Size: 593 bytes --]

Index: linux-sd/drivers/mmc/mmc.c
===================================================================
--- linux-sd/drivers/mmc/mmc.c	(revision 141)
+++ linux-sd/drivers/mmc/mmc.c	(working copy)
@@ -2,6 +2,8 @@
  *  linux/drivers/mmc/mmc.c
  *
  *  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.
  *
  * 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

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH][MMC][1/6] Secure Digital (SD) support : protocol
  2005-03-06  1:37         ` [PATCH][MMC][1/6] Secure Digital (SD) support : protocol Pierre Ossman
@ 2005-03-19 16:35           ` Russell King
  0 siblings, 0 replies; 21+ messages in thread
From: Russell King @ 2005-03-19 16:35 UTC (permalink / raw)
  To: Pierre Ossman; +Cc: LKML, Ian Molton, Richard Purdie

On Sun, Mar 06, 2005 at 02:37:01AM +0100, Pierre Ossman wrote:
> Protocol definitions.
> 
> The basic commands needed for the later patches. The R1_APP_CMD seems to 
> be misdefined in protocol.h so this patch changes it.

Applied, thanks.

-- 
Russell King
 Linux kernel    2.6 ARM Linux   - http://www.arm.linux.org.uk/
 maintainer of:  2.6 Serial core

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH][MMC] Secure Digital (SD) support
  2005-03-05 13:46       ` Pierre Ossman
  2005-03-05 16:24         ` Richard Purdie
@ 2005-05-06 14:15         ` Pierre Ossman
  1 sibling, 0 replies; 21+ messages in thread
From: Pierre Ossman @ 2005-05-06 14:15 UTC (permalink / raw)
  To: LKML; +Cc: Russell King, Linus Torvalds, Ian Molton, Richard Purdie

Pierre Ossman wrote:
> Russell King wrote:
> 
>> We'll also need to run this by Linus first, explaining why you believe
>> it's now ok to merge this.  (Added Linus...)
>>
> 
> It was also pointed out in the previous thread by myself, Alan Cox and
> Ian Molton that SD specs have been publically available from different
> companies for quite some time. As such it is difficult for anyone to
> claim that these are secret and can be regulated by a NDA. The only part
> that hasn't been found in the wild is the spec for the 'secure' parts of
> the cards. But that also means that it isn't included in this patch so
> it shouldn't pose a problem.
> 

This issue doesn't seem to reach any kind of resolution so I figured I'd
take a poke at the people responsible. :)

Just to back up the claim that the specs are in the open here are some
links:

http://www.google.com/search?hl=en&q=%22Secure+Digital+Card%22+%22Product+Manual%22+site%3Asandisk.com&btnG=Google+Search

Which gives you several PDF:s with enough information to implement a SD
host. The one I've been using is:

http://www.sandisk.com/download/Product%20Manuals/Product%20ManualSDCardv1.7.pdf


Rgds
Pierre

^ permalink raw reply	[flat|nested] 21+ messages in thread

end of thread, other threads:[~2005-05-06 14:18 UTC | newest]

Thread overview: 21+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2005-03-03 12:22 [PATCH][MMC] Secure Digital (SD) support Pierre Ossman
2005-03-04 13:22 ` Pavel Machek
2005-03-04 15:00 ` Marcel Holtmann
2005-03-04 15:12   ` Pierre Ossman
2005-03-04 16:22     ` Marcel Holtmann
2005-03-04 21:04     ` Ian Molton
2005-03-05 11:37 ` Russell King
2005-03-05 12:23   ` Pierre Ossman
2005-03-05 12:44     ` Russell King
2005-03-05 13:46       ` Pierre Ossman
2005-03-05 16:24         ` Richard Purdie
2005-05-06 14:15         ` Pierre Ossman
2005-03-06  1:34       ` [PATCH][MMC][0/6] " Pierre Ossman
2005-03-06  1:37         ` [PATCH][MMC][1/6] Secure Digital (SD) support : protocol Pierre Ossman
2005-03-19 16:35           ` Russell King
2005-03-06  1:44         ` [PATCH][MMC][2/6] Secure Digital (SD) support : init Pierre Ossman
2005-03-06  1:47         ` [PATCH][MMC][3/6] Secure Digital (SD) support : ro Pierre Ossman
2005-03-06  1:50         ` [PATCH][MMC][4/6] Secure Digital (SD) support : SCR Pierre Ossman
2005-03-06  1:52         ` [PATCH][MMC][5/6] Secure Digital (SD) support : sysfs Pierre Ossman
2005-03-06  1:57         ` [PATCH][MMC][6/6] Secure Digital (SD) support : wide bus Pierre Ossman
2005-03-12 17:35         ` [PATCH][MMC][7/6] Secure Digital (SD) support : Copyright Pierre Ossman

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).