Commit 6e58ddeb authored by Linus Torvalds's avatar Linus Torvalds

Merge bk://bk.arm.linux.org.uk/linux-2.6-mmc

into ppc970.osdl.org:/home/torvalds/v2.6/linux
parents 6e544044 201ee40f
...@@ -300,58 +300,121 @@ static u32 mmc_select_voltage(struct mmc_host *host, u32 ocr) ...@@ -300,58 +300,121 @@ static u32 mmc_select_voltage(struct mmc_host *host, u32 ocr)
return ocr; return ocr;
} }
static void mmc_decode_cid(struct mmc_cid *cid, u32 *resp) #define UNSTUFF_BITS(resp,start,size) \
({ \
const u32 __mask = (1 << (size)) - 1; \
const int __off = 3 - ((start) / 32); \
const int __shft = (start) & 31; \
u32 __res; \
\
__res = resp[__off] >> __shft; \
if ((size) + __shft >= 32) \
__res |= resp[__off-1] << (32 - __shft); \
__res & __mask; \
})
/*
* Given the decoded CSD structure, decode the raw CID to our CID structure.
*/
static void mmc_decode_cid(struct mmc_card *card)
{ {
memset(cid, 0, sizeof(struct mmc_cid)); u32 *resp = card->raw_cid;
cid->manfid = resp[0] >> 8; memset(&card->cid, 0, sizeof(struct mmc_cid));
cid->prod_name[0] = resp[0];
cid->prod_name[1] = resp[1] >> 24; /*
cid->prod_name[2] = resp[1] >> 16; * The selection of the format here is guesswork based upon
cid->prod_name[3] = resp[1] >> 8; * information people have sent to date.
cid->prod_name[4] = resp[1]; */
cid->prod_name[5] = resp[2] >> 24; switch (card->csd.mmca_vsn) {
cid->prod_name[6] = resp[2] >> 16; case 0: /* MMC v1.? */
cid->prod_name[7] = '\0'; case 1: /* MMC v1.4 */
cid->hwrev = (resp[2] >> 12) & 15; card->cid.manfid = UNSTUFF_BITS(resp, 104, 24);
cid->fwrev = (resp[2] >> 8) & 15; card->cid.prod_name[0] = UNSTUFF_BITS(resp, 96, 8);
cid->serial = (resp[2] & 255) << 16 | (resp[3] >> 16); card->cid.prod_name[1] = UNSTUFF_BITS(resp, 88, 8);
cid->month = (resp[3] >> 12) & 15; card->cid.prod_name[2] = UNSTUFF_BITS(resp, 80, 8);
cid->year = (resp[3] >> 8) & 15; 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;
}
} }
static void mmc_decode_csd(struct mmc_csd *csd, u32 *resp) /*
* Given a 128-bit response, decode to our card CSD structure.
*/
static void mmc_decode_csd(struct mmc_card *card)
{ {
unsigned int e, m; struct mmc_csd *csd = &card->csd;
unsigned int e, m, csd_struct;
u32 *resp = card->raw_csd;
csd->mmc_prot = (resp[0] >> 26) & 15; /*
m = (resp[0] >> 19) & 15; * We only understand CSD structure v1.1 and v2.
e = (resp[0] >> 16) & 7; * 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->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_ns = (tacc_exp[e] * tacc_mant[m] + 9) / 10;
csd->tacc_clks = ((resp[0] >> 8) & 255) * 100; csd->tacc_clks = UNSTUFF_BITS(resp, 104, 8) * 100;
m = (resp[0] >> 3) & 15; m = UNSTUFF_BITS(resp, 99, 4);
e = resp[0] & 7; 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 = (resp[1] >> 20) & 0xfff; csd->cmdclass = UNSTUFF_BITS(resp, 84, 12);
e = (resp[2] >> 15) & 7; e = UNSTUFF_BITS(resp, 47, 3);
m = (resp[1] << 2 | resp[2] >> 30) & 0x3fff; m = UNSTUFF_BITS(resp, 62, 12);
csd->capacity = (1 + m) << (e + 2); csd->capacity = (1 + m) << (e + 2);
csd->read_blkbits = (resp[1] >> 16) & 15; csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4);
} }
/* /*
* Locate a MMC card on this MMC host given a CID. * Locate a MMC card on this MMC host given a raw CID.
*/ */
static struct mmc_card * static struct mmc_card *mmc_find_card(struct mmc_host *host, u32 *raw_cid)
mmc_find_card(struct mmc_host *host, struct mmc_cid *cid)
{ {
struct mmc_card *card; struct mmc_card *card;
list_for_each_entry(card, &host->cards, node) { list_for_each_entry(card, &host->cards, node) {
if (memcmp(&card->cid, cid, sizeof(struct mmc_cid)) == 0) if (memcmp(card->raw_cid, raw_cid, sizeof(card->raw_cid)) == 0)
return card; return card;
} }
return NULL; return NULL;
...@@ -361,7 +424,7 @@ mmc_find_card(struct mmc_host *host, struct mmc_cid *cid) ...@@ -361,7 +424,7 @@ mmc_find_card(struct mmc_host *host, struct mmc_cid *cid)
* Allocate a new MMC card, and assign a unique RCA. * Allocate a new MMC card, and assign a unique RCA.
*/ */
static struct mmc_card * static struct mmc_card *
mmc_alloc_card(struct mmc_host *host, struct mmc_cid *cid, unsigned int *frca) mmc_alloc_card(struct mmc_host *host, u32 *raw_cid, unsigned int *frca)
{ {
struct mmc_card *card, *c; struct mmc_card *card, *c;
unsigned int rca = *frca; unsigned int rca = *frca;
...@@ -371,7 +434,7 @@ mmc_alloc_card(struct mmc_host *host, struct mmc_cid *cid, unsigned int *frca) ...@@ -371,7 +434,7 @@ mmc_alloc_card(struct mmc_host *host, struct mmc_cid *cid, unsigned int *frca)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
mmc_init_card(card, host); mmc_init_card(card, host);
memcpy(&card->cid, cid, sizeof(struct mmc_cid)); memcpy(card->raw_cid, raw_cid, sizeof(card->raw_cid));
again: again:
list_for_each_entry(c, &host->cards, node) list_for_each_entry(c, &host->cards, node)
...@@ -456,7 +519,7 @@ static int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) ...@@ -456,7 +519,7 @@ static int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
* to be discovered. Add new cards to the list. * to be discovered. Add new cards to the list.
* *
* Create a mmc_card entry for each discovered card, assigning * Create a mmc_card entry for each discovered card, assigning
* it an RCA, and save the CID. * it an RCA, and save the raw CID for decoding later.
*/ */
static void mmc_discover_cards(struct mmc_host *host) static void mmc_discover_cards(struct mmc_host *host)
{ {
...@@ -465,7 +528,6 @@ static void mmc_discover_cards(struct mmc_host *host) ...@@ -465,7 +528,6 @@ static void mmc_discover_cards(struct mmc_host *host)
while (1) { while (1) {
struct mmc_command cmd; struct mmc_command cmd;
struct mmc_cid cid;
cmd.opcode = MMC_ALL_SEND_CID; cmd.opcode = MMC_ALL_SEND_CID;
cmd.arg = 0; cmd.arg = 0;
...@@ -482,11 +544,9 @@ static void mmc_discover_cards(struct mmc_host *host) ...@@ -482,11 +544,9 @@ static void mmc_discover_cards(struct mmc_host *host)
break; break;
} }
mmc_decode_cid(&cid, cmd.resp); card = mmc_find_card(host, cmd.resp);
card = mmc_find_card(host, &cid);
if (!card) { if (!card) {
card = mmc_alloc_card(host, &cid, &first_rca); card = mmc_alloc_card(host, cmd.resp, &first_rca);
if (IS_ERR(card)) { if (IS_ERR(card)) {
err = PTR_ERR(card); err = PTR_ERR(card);
break; break;
...@@ -502,7 +562,7 @@ static void mmc_discover_cards(struct mmc_host *host) ...@@ -502,7 +562,7 @@ static void mmc_discover_cards(struct mmc_host *host)
err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES); err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
if (err != MMC_ERR_NONE) if (err != MMC_ERR_NONE)
card->state |= MMC_STATE_DEAD; mmc_card_set_dead(card);
} }
} }
...@@ -523,11 +583,14 @@ static void mmc_read_csds(struct mmc_host *host) ...@@ -523,11 +583,14 @@ static void mmc_read_csds(struct mmc_host *host)
err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES); err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
if (err != MMC_ERR_NONE) { if (err != MMC_ERR_NONE) {
card->state |= MMC_STATE_DEAD; mmc_card_set_dead(card);
continue; continue;
} }
mmc_decode_csd(&card->csd, cmd.resp); memcpy(card->raw_csd, cmd.resp, sizeof(card->raw_csd));
mmc_decode_csd(card);
mmc_decode_cid(card);
} }
} }
...@@ -573,7 +636,7 @@ static void mmc_check_cards(struct mmc_host *host) ...@@ -573,7 +636,7 @@ static void mmc_check_cards(struct mmc_host *host)
if (err == MMC_ERR_NONE) if (err == MMC_ERR_NONE)
continue; continue;
card->state |= MMC_STATE_DEAD; mmc_card_set_dead(card);
} }
} }
...@@ -678,9 +741,9 @@ static void mmc_rescan(void *data) ...@@ -678,9 +741,9 @@ static void mmc_rescan(void *data)
*/ */
if (!mmc_card_present(card) && !mmc_card_dead(card)) { if (!mmc_card_present(card) && !mmc_card_dead(card)) {
if (mmc_register_card(card)) if (mmc_register_card(card))
card->state |= MMC_STATE_DEAD; mmc_card_set_dead(card);
else else
card->state |= MMC_STATE_PRESENT; mmc_card_set_present(card);
} }
/* /*
......
...@@ -31,11 +31,12 @@ static void mmc_release_card(struct device *dev) ...@@ -31,11 +31,12 @@ static void mmc_release_card(struct device *dev)
/* /*
* This currently matches any MMC driver to any MMC card - drivers * This currently matches any MMC driver to any MMC card - drivers
* themselves make the decision whether to drive this card in their * themselves make the decision whether to drive this card in their
* probe method. * probe method. However, we force "bad" cards to fail.
*/ */
static int mmc_bus_match(struct device *dev, struct device_driver *drv) static int mmc_bus_match(struct device *dev, struct device_driver *drv)
{ {
return 1; struct mmc_card *card = dev_to_mmc_card(dev);
return !mmc_card_bad(card);
} }
static int static int
...@@ -66,8 +67,9 @@ mmc_bus_hotplug(struct device *dev, char **envp, int num_envp, char *buf, ...@@ -66,8 +67,9 @@ mmc_bus_hotplug(struct device *dev, char **envp, int num_envp, char *buf,
i = 0; i = 0;
add_env("MMC_CCC=%s", ccc); add_env("MMC_CCC=%s", ccc);
add_env("MMC_MANFID=%03x", card->cid.manfid); add_env("MMC_MANFID=%06x", card->cid.manfid);
add_env("MMC_SLOT_NAME=%s", card->dev.bus_id); add_env("MMC_NAME=%s", mmc_card_name(card));
add_env("MMC_OEMID=%04x", card->cid.oemid);
return 0; return 0;
} }
...@@ -157,20 +159,28 @@ static ssize_t mmc_dev_show_##name (struct device *dev, char *buf) \ ...@@ -157,20 +159,28 @@ static ssize_t mmc_dev_show_##name (struct device *dev, char *buf) \
} \ } \
static DEVICE_ATTR(name, S_IRUGO, mmc_dev_show_##name, NULL) static DEVICE_ATTR(name, S_IRUGO, mmc_dev_show_##name, NULL)
MMC_ATTR(date, "%02d/%04d\n", card->cid.month, 1997 + card->cid.year); MMC_ATTR(cid, "%08x%08x%08x%08x\n", card->raw_cid[0], card->raw_cid[1],
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(date, "%02d/%04d\n", card->cid.month, card->cid.year);
MMC_ATTR(fwrev, "0x%x\n", card->cid.fwrev); MMC_ATTR(fwrev, "0x%x\n", card->cid.fwrev);
MMC_ATTR(hwrev, "0x%x\n", card->cid.hwrev); MMC_ATTR(hwrev, "0x%x\n", card->cid.hwrev);
MMC_ATTR(manfid, "0x%03x\n", card->cid.manfid); MMC_ATTR(manfid, "0x%06x\n", card->cid.manfid);
MMC_ATTR(serial, "0x%06x\n", card->cid.serial);
MMC_ATTR(name, "%s\n", card->cid.prod_name); MMC_ATTR(name, "%s\n", card->cid.prod_name);
MMC_ATTR(oemid, "0x%04x\n", card->cid.oemid);
MMC_ATTR(serial, "0x%08x\n", card->cid.serial);
static struct device_attribute *mmc_dev_attributes[] = { static struct device_attribute *mmc_dev_attributes[] = {
&dev_attr_cid,
&dev_attr_csd,
&dev_attr_date, &dev_attr_date,
&dev_attr_fwrev, &dev_attr_fwrev,
&dev_attr_hwrev, &dev_attr_hwrev,
&dev_attr_manfid, &dev_attr_manfid,
&dev_attr_serial,
&dev_attr_name, &dev_attr_name,
&dev_attr_oemid,
&dev_attr_serial,
}; };
/* /*
......
...@@ -14,16 +14,17 @@ ...@@ -14,16 +14,17 @@
struct mmc_cid { struct mmc_cid {
unsigned int manfid; unsigned int manfid;
unsigned int serial;
char prod_name[8]; char prod_name[8];
unsigned int serial;
unsigned short oemid;
unsigned short year;
unsigned char hwrev; unsigned char hwrev;
unsigned char fwrev; unsigned char fwrev;
unsigned char month; unsigned char month;
unsigned char year;
}; };
struct mmc_csd { struct mmc_csd {
unsigned char mmc_prot; unsigned char mmca_vsn;
unsigned short cmdclass; unsigned short cmdclass;
unsigned short tacc_clks; unsigned short tacc_clks;
unsigned int tacc_ns; unsigned int tacc_ns;
...@@ -43,14 +44,22 @@ struct mmc_card { ...@@ -43,14 +44,22 @@ struct mmc_card {
struct device dev; /* the device */ struct device dev; /* the device */
unsigned int rca; /* relative card address of device */ unsigned int rca; /* relative card address of device */
unsigned int state; /* (our) card state */ unsigned int state; /* (our) card state */
#define MMC_STATE_PRESENT (1<<0) #define MMC_STATE_PRESENT (1<<0) /* present in sysfs */
#define MMC_STATE_DEAD (1<<1) #define MMC_STATE_DEAD (1<<1) /* device no longer in stack */
#define MMC_STATE_BAD (1<<2) /* unrecognised device */
u32 raw_cid[4]; /* raw card CID */
u32 raw_csd[4]; /* raw card CSD */
struct mmc_cid cid; /* card identification */ struct mmc_cid cid; /* card identification */
struct mmc_csd csd; /* card specific */ struct mmc_csd csd; /* card specific */
}; };
#define mmc_card_dead(c) ((c)->state & MMC_STATE_DEAD)
#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_bad(c) ((c)->state & MMC_STATE_BAD)
#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_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)
......
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