Commit 201ee40f authored by Russell King's avatar Russell King

[MMC] Add v2.x and v3.x CID parsing.

parent b41465f9
......@@ -300,51 +300,110 @@ static u32 mmc_select_voltage(struct mmc_host *host, u32 ocr)
return ocr;
}
#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)
{
struct mmc_cid *cid = &card->cid;
u32 *resp = card->raw_cid;
memset(cid, 0, sizeof(struct mmc_cid));
cid->manfid = resp[0] >> 8;
cid->prod_name[0] = resp[0];
cid->prod_name[1] = resp[1] >> 24;
cid->prod_name[2] = resp[1] >> 16;
cid->prod_name[3] = resp[1] >> 8;
cid->prod_name[4] = resp[1];
cid->prod_name[5] = resp[2] >> 24;
cid->prod_name[6] = resp[2] >> 16;
cid->prod_name[7] = '\0';
cid->hwrev = (resp[2] >> 12) & 15;
cid->fwrev = (resp[2] >> 8) & 15;
cid->serial = (resp[2] & 255) << 16 | (resp[3] >> 16);
cid->month = (resp[3] >> 12) & 15;
cid->year = (resp[3] >> 8) & 15;
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;
}
}
/*
* Given a 128-bit response, decode to our card CSD structure.
*/
static void mmc_decode_csd(struct mmc_card *card)
{
struct mmc_csd *csd = &card->csd;
unsigned int e, m;
unsigned int e, m, csd_struct;
u32 *resp = card->raw_csd;
csd->mmc_prot = (resp[0] >> 26) & 15;
m = (resp[0] >> 19) & 15;
e = (resp[0] >> 16) & 7;
/*
* 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->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 = ((resp[0] >> 8) & 255) * 100;
csd->tacc_clks = UNSTUFF_BITS(resp, 104, 8) * 100;
m = (resp[0] >> 3) & 15;
e = resp[0] & 7;
m = UNSTUFF_BITS(resp, 99, 4);
e = UNSTUFF_BITS(resp, 96, 3);
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;
m = (resp[1] << 2 | resp[2] >> 30) & 0x3fff;
e = UNSTUFF_BITS(resp, 47, 3);
m = UNSTUFF_BITS(resp, 62, 12);
csd->capacity = (1 + m) << (e + 2);
csd->read_blkbits = (resp[1] >> 16) & 15;
csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4);
}
/*
......
......@@ -67,8 +67,9 @@ mmc_bus_hotplug(struct device *dev, char **envp, int num_envp, char *buf,
i = 0;
add_env("MMC_CCC=%s", ccc);
add_env("MMC_MANFID=%03x", card->cid.manfid);
add_env("MMC_SLOT_NAME=%s", card->dev.bus_id);
add_env("MMC_MANFID=%06x", card->cid.manfid);
add_env("MMC_NAME=%s", mmc_card_name(card));
add_env("MMC_OEMID=%04x", card->cid.oemid);
return 0;
}
......@@ -162,12 +163,13 @@ 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, 1997 + card->cid.year);
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);
MMC_ATTR(manfid, "0x%03x\n", card->cid.manfid);
MMC_ATTR(manfid, "0x%06x\n", card->cid.manfid);
MMC_ATTR(name, "%s\n", card->cid.prod_name);
MMC_ATTR(serial, "0x%06x\n", card->cid.serial);
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[] = {
&dev_attr_cid,
......@@ -177,6 +179,7 @@ static struct device_attribute *mmc_dev_attributes[] = {
&dev_attr_hwrev,
&dev_attr_manfid,
&dev_attr_name,
&dev_attr_oemid,
&dev_attr_serial,
};
......
......@@ -14,16 +14,17 @@
struct mmc_cid {
unsigned int manfid;
unsigned int serial;
char prod_name[8];
unsigned int serial;
unsigned short oemid;
unsigned short year;
unsigned char hwrev;
unsigned char fwrev;
unsigned char month;
unsigned char year;
};
struct mmc_csd {
unsigned char mmc_prot;
unsigned char mmca_vsn;
unsigned short cmdclass;
unsigned short tacc_clks;
unsigned int tacc_ns;
......
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