Commit 335eadf2 authored by Pierre Ossman's avatar Pierre Ossman Committed by Linus Torvalds

[PATCH] sd: initialize SD cards

Support for the Secure Digital protocol in the MMC layer.

A summary of the legal issues surrounding SD cards, as understood by yours
truly:

Members of the Secure Digital Association, hereafter SDA, are required to sign
a NDA[1] before given access to any specifications.  It has been speculated
that including an SD implementation would forbid these members to redistribute
Linux.  This is the basic problem with SD support so it is unclear if it even
is a problem since it has no effect on those of us that aren't members.

The SDA doesn't seem to enforce these rules though since the patches included
here are based on documentation made public by some of the members.  The most
complete specs[2] are actually released by Sandisk, one of the founding
companies of the SDA.

Because of this the NDA is considered a non-issue by most involved in the
discussions concerning these patches.  It might be that the SDA is only
interested in protecting the so called "secure" bits of SD, which so far
hasn't been found in any public spec.  (The card is split into two sections,
one "normal" and one "secure" which has an access scheme similar to TPM:s).

(As a side note, Microsoft is working to make things easier for us since they
want to be able to include the source code for a SD driver in one of their
development kits.  HP is making sure that the new NDA will allow a Linux
implementation.  So far only the SDIO specs have been opened up[3].  More will
hopefully follow.)

 [1] http://www.sdcard.org/membership/images/ippolicy.pdf
 [2] http://www.sandisk.com/pdf/oem/ProdManualSDCardv1.9.pdf
 [3] http://www.sdcard.org/sdio/Simplified%20SDIO%20Card%20Specification.pdf

This patch contains the central parts of the SD support.  If no MMC cards are
found on a bus then the MMC layer proceeds looking for SD cards.  Helper
functions are extended to handle the special needs of SD cards.
Signed-off-by: default avatarPierre Ossman <drzeus@drzeus.cx>
Cc: Russell King <rmk@arm.linux.org.uk>
Cc: David Brownell <david-b@pacbell.net>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 328b9227
...@@ -172,7 +172,79 @@ int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, int retries ...@@ -172,7 +172,79 @@ int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, int retries
EXPORT_SYMBOL(mmc_wait_for_cmd); 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 * __mmc_claim_host - exclusively claim a host
...@@ -322,48 +394,70 @@ static void mmc_decode_cid(struct mmc_card *card) ...@@ -322,48 +394,70 @@ static void mmc_decode_cid(struct mmc_card *card)
memset(&card->cid, 0, sizeof(struct mmc_cid)); memset(&card->cid, 0, sizeof(struct mmc_cid));
/* if (mmc_card_sd(card)) {
* The selection of the format here is guesswork based upon /*
* information people have sent to date. * SD doesn't currently have a version field so we will
*/ * have to assume we can parse this.
switch (card->csd.mmca_vsn) { */
case 0: /* MMC v1.? */ card->cid.manfid = UNSTUFF_BITS(resp, 120, 8);
case 1: /* MMC v1.4 */ card->cid.oemid = UNSTUFF_BITS(resp, 104, 16);
card->cid.manfid = UNSTUFF_BITS(resp, 104, 24); card->cid.prod_name[0] = UNSTUFF_BITS(resp, 96, 8);
card->cid.prod_name[0] = UNSTUFF_BITS(resp, 96, 8); card->cid.prod_name[1] = UNSTUFF_BITS(resp, 88, 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[2] = UNSTUFF_BITS(resp, 80, 8); card->cid.prod_name[3] = UNSTUFF_BITS(resp, 72, 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[4] = UNSTUFF_BITS(resp, 64, 8); card->cid.hwrev = UNSTUFF_BITS(resp, 60, 4);
card->cid.prod_name[5] = UNSTUFF_BITS(resp, 56, 8); card->cid.fwrev = UNSTUFF_BITS(resp, 56, 4);
card->cid.prod_name[6] = UNSTUFF_BITS(resp, 48, 8); card->cid.serial = UNSTUFF_BITS(resp, 24, 32);
card->cid.hwrev = UNSTUFF_BITS(resp, 44, 4); card->cid.year = UNSTUFF_BITS(resp, 12, 8);
card->cid.fwrev = UNSTUFF_BITS(resp, 40, 4); card->cid.month = UNSTUFF_BITS(resp, 8, 4);
card->cid.serial = UNSTUFF_BITS(resp, 16, 24);
card->cid.month = UNSTUFF_BITS(resp, 12, 4); card->cid.year += 2000; /* SD cards year offset */
card->cid.year = UNSTUFF_BITS(resp, 8, 4) + 1997; }
break; else {
/*
case 2: /* MMC v2.x ? */ * The selection of the format here is based upon published
case 3: /* MMC v3.x ? */ * specs from sandisk and from what people have reported.
card->cid.manfid = UNSTUFF_BITS(resp, 120, 8); */
card->cid.oemid = UNSTUFF_BITS(resp, 104, 16); switch (card->csd.mmca_vsn) {
card->cid.prod_name[0] = UNSTUFF_BITS(resp, 96, 8); case 0: /* MMC v1.0 - v1.2 */
card->cid.prod_name[1] = UNSTUFF_BITS(resp, 88, 8); case 1: /* MMC v1.4 */
card->cid.prod_name[2] = UNSTUFF_BITS(resp, 80, 8); card->cid.manfid = UNSTUFF_BITS(resp, 104, 24);
card->cid.prod_name[3] = UNSTUFF_BITS(resp, 72, 8); card->cid.prod_name[0] = UNSTUFF_BITS(resp, 96, 8);
card->cid.prod_name[4] = UNSTUFF_BITS(resp, 64, 8); card->cid.prod_name[1] = UNSTUFF_BITS(resp, 88, 8);
card->cid.prod_name[5] = UNSTUFF_BITS(resp, 56, 8); card->cid.prod_name[2] = UNSTUFF_BITS(resp, 80, 8);
card->cid.serial = UNSTUFF_BITS(resp, 16, 32); card->cid.prod_name[3] = UNSTUFF_BITS(resp, 72, 8);
card->cid.month = UNSTUFF_BITS(resp, 12, 4); card->cid.prod_name[4] = UNSTUFF_BITS(resp, 64, 8);
card->cid.year = UNSTUFF_BITS(resp, 8, 4) + 1997; card->cid.prod_name[5] = UNSTUFF_BITS(resp, 56, 8);
break; card->cid.prod_name[6] = UNSTUFF_BITS(resp, 48, 8);
card->cid.hwrev = UNSTUFF_BITS(resp, 44, 4);
default: card->cid.fwrev = UNSTUFF_BITS(resp, 40, 4);
printk("%s: card has unknown MMCA version %d\n", card->cid.serial = UNSTUFF_BITS(resp, 16, 24);
mmc_hostname(card->host), card->csd.mmca_vsn); card->cid.month = UNSTUFF_BITS(resp, 12, 4);
mmc_card_set_bad(card); card->cid.year = UNSTUFF_BITS(resp, 8, 4) + 1997;
break; 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",
mmc_hostname(card->host), card->csd.mmca_vsn);
mmc_card_set_bad(card);
break;
}
} }
} }
...@@ -376,34 +470,61 @@ static void mmc_decode_csd(struct mmc_card *card) ...@@ -376,34 +470,61 @@ static void mmc_decode_csd(struct mmc_card *card)
unsigned int e, m, csd_struct; unsigned int e, m, csd_struct;
u32 *resp = card->raw_csd; u32 *resp = card->raw_csd;
/* if (mmc_card_sd(card)) {
* We only understand CSD structure v1.1 and v2. csd_struct = UNSTUFF_BITS(resp, 126, 2);
* v2 has extra information in bits 15, 11 and 10. if (csd_struct != 0) {
*/ printk("%s: unrecognised CSD structure version %d\n",
csd_struct = UNSTUFF_BITS(resp, 126, 2); mmc_hostname(card->host), csd_struct);
if (csd_struct != 1 && csd_struct != 2) { mmc_card_set_bad(card);
printk("%s: unrecognised CSD structure version %d\n", return;
mmc_hostname(card->host), 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);
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",
mmc_hostname(card->host), csd_struct);
mmc_card_set_bad(card);
return;
}
csd->mmca_vsn = UNSTUFF_BITS(resp, 122, 4); csd->mmca_vsn = UNSTUFF_BITS(resp, 122, 4);
m = UNSTUFF_BITS(resp, 115, 4); m = UNSTUFF_BITS(resp, 115, 4);
e = UNSTUFF_BITS(resp, 112, 3); e = UNSTUFF_BITS(resp, 112, 3);
csd->tacc_ns = (tacc_exp[e] * tacc_mant[m] + 9) / 10; csd->tacc_ns = (tacc_exp[e] * tacc_mant[m] + 9) / 10;
csd->tacc_clks = UNSTUFF_BITS(resp, 104, 8) * 100; csd->tacc_clks = UNSTUFF_BITS(resp, 104, 8) * 100;
m = UNSTUFF_BITS(resp, 99, 4); m = UNSTUFF_BITS(resp, 99, 4);
e = UNSTUFF_BITS(resp, 96, 3); e = UNSTUFF_BITS(resp, 96, 3);
csd->max_dtr = tran_exp[e] * tran_mant[m]; csd->max_dtr = tran_exp[e] * tran_mant[m];
csd->cmdclass = UNSTUFF_BITS(resp, 84, 12); csd->cmdclass = UNSTUFF_BITS(resp, 84, 12);
e = UNSTUFF_BITS(resp, 47, 3); e = UNSTUFF_BITS(resp, 47, 3);
m = UNSTUFF_BITS(resp, 62, 12); m = UNSTUFF_BITS(resp, 62, 12);
csd->capacity = (1 + m) << (e + 2); csd->capacity = (1 + m) << (e + 2);
csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4); csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4);
}
} }
/* /*
...@@ -536,6 +657,34 @@ static int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) ...@@ -536,6 +657,34 @@ static int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
return err; 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 * Discover cards by requesting their CID. If this command
* times out, it is not an error; there are no further cards * times out, it is not an error; there are no further cards
...@@ -579,13 +728,28 @@ static void mmc_discover_cards(struct mmc_host *host) ...@@ -579,13 +728,28 @@ static void mmc_discover_cards(struct mmc_host *host)
card->state &= ~MMC_STATE_DEAD; card->state &= ~MMC_STATE_DEAD;
cmd.opcode = MMC_SET_RELATIVE_ADDR; if (host->mode == MMC_MODE_SD) {
cmd.arg = card->rca << 16; mmc_card_set_sd(card);
cmd.flags = MMC_RSP_R1;
err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES); cmd.opcode = SD_SEND_RELATIVE_ADDR;
if (err != MMC_ERR_NONE) cmd.arg = 0;
mmc_card_set_dead(card); cmd.flags = MMC_RSP_R1;
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);
}
} }
} }
...@@ -669,12 +833,25 @@ static void mmc_setup(struct mmc_host *host) ...@@ -669,12 +833,25 @@ static void mmc_setup(struct mmc_host *host)
int err; int err;
u32 ocr; u32 ocr;
host->mode = MMC_MODE_MMC;
mmc_power_up(host); mmc_power_up(host);
mmc_idle_cards(host); mmc_idle_cards(host);
err = mmc_send_op_cond(host, 0, &ocr); 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) 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); host->ocr = mmc_select_voltage(host, ocr);
...@@ -714,7 +891,10 @@ static void mmc_setup(struct mmc_host *host) ...@@ -714,7 +891,10 @@ static void mmc_setup(struct mmc_host *host)
* all get the idea that they should be ready for CMD2. * all get the idea that they should be ready for CMD2.
* (My SanDisk card seems to need this.) * (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); mmc_discover_cards(host);
......
...@@ -47,6 +47,7 @@ struct mmc_card { ...@@ -47,6 +47,7 @@ struct mmc_card {
#define MMC_STATE_PRESENT (1<<0) /* present in sysfs */ #define MMC_STATE_PRESENT (1<<0) /* present in sysfs */
#define MMC_STATE_DEAD (1<<1) /* device no longer in stack */ #define MMC_STATE_DEAD (1<<1) /* device no longer in stack */
#define MMC_STATE_BAD (1<<2) /* unrecognised device */ #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_cid[4]; /* raw card CID */
u32 raw_csd[4]; /* raw card CSD */ u32 raw_csd[4]; /* raw card CSD */
struct mmc_cid cid; /* card identification */ struct mmc_cid cid; /* card identification */
...@@ -56,10 +57,12 @@ struct mmc_card { ...@@ -56,10 +57,12 @@ struct mmc_card {
#define mmc_card_present(c) ((c)->state & MMC_STATE_PRESENT) #define mmc_card_present(c) ((c)->state & MMC_STATE_PRESENT)
#define mmc_card_dead(c) ((c)->state & MMC_STATE_DEAD) #define mmc_card_dead(c) ((c)->state & MMC_STATE_DEAD)
#define mmc_card_bad(c) ((c)->state & MMC_STATE_BAD) #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_present(c) ((c)->state |= MMC_STATE_PRESENT)
#define mmc_card_set_dead(c) ((c)->state |= MMC_STATE_DEAD) #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_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_name(c) ((c)->cid.prod_name)
#define mmc_card_id(c) ((c)->dev.bus_id) #define mmc_card_id(c) ((c)->dev.bus_id)
......
...@@ -87,6 +87,10 @@ struct mmc_host { ...@@ -87,6 +87,10 @@ struct mmc_host {
struct mmc_ios ios; /* current io bus settings */ struct mmc_ios ios; /* current io bus settings */
u32 ocr; /* the current OCR setting */ 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 */ struct list_head cards; /* devices attached to this host */
wait_queue_head_t wq; wait_queue_head_t wq;
......
...@@ -88,6 +88,8 @@ struct mmc_card; ...@@ -88,6 +88,8 @@ struct mmc_card;
extern int mmc_wait_for_req(struct mmc_host *, struct mmc_request *); 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_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); extern int __mmc_claim_host(struct mmc_host *host, struct mmc_card *card);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment