summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/mmc/core/Makefile2
-rw-r--r--drivers/mmc/core/core.c817
-rw-r--r--drivers/mmc/core/core.h37
-rw-r--r--drivers/mmc/core/mmc.c430
-rw-r--r--drivers/mmc/core/sd.c431
-rw-r--r--include/linux/mmc/host.h7
6 files changed, 1041 insertions, 683 deletions
diff --git a/drivers/mmc/core/Makefile b/drivers/mmc/core/Makefile
index 5977abf..1075b02 100644
--- a/drivers/mmc/core/Makefile
+++ b/drivers/mmc/core/Makefile
@@ -7,5 +7,5 @@ ifeq ($(CONFIG_MMC_DEBUG),y)
endif
obj-$(CONFIG_MMC) += mmc_core.o
-mmc_core-y := core.o sysfs.o mmc_ops.o sd_ops.o
+mmc_core-y := core.o sysfs.o mmc.o mmc_ops.o sd.o sd_ops.o
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 310be2f..75333a2 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -32,36 +32,8 @@
#include "mmc_ops.h"
#include "sd_ops.h"
-#define CMD_RETRIES 3
-
-/*
- * OCR Bit positions to 10s of Vdd mV.
- */
-static const unsigned short mmc_ocr_bit_to_vdd[] = {
- 150, 155, 160, 165, 170, 180, 190, 200,
- 210, 220, 230, 240, 250, 260, 270, 280,
- 290, 300, 310, 320, 330, 340, 350, 360
-};
-
-static const unsigned int tran_exp[] = {
- 10000, 100000, 1000000, 10000000,
- 0, 0, 0, 0
-};
-
-static const unsigned char tran_mant[] = {
- 0, 10, 12, 13, 15, 20, 25, 30,
- 35, 40, 45, 50, 55, 60, 70, 80,
-};
-
-static const unsigned int tacc_exp[] = {
- 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000,
-};
-
-static const unsigned int tacc_mant[] = {
- 0, 10, 12, 13, 15, 20, 25, 30,
- 35, 40, 45, 50, 55, 60, 70, 80,
-};
-
+extern int mmc_attach_mmc(struct mmc_host *host, u32 ocr);
+extern int mmc_attach_sd(struct mmc_host *host, u32 ocr);
/**
* mmc_request_done - finish processing an MMC request
@@ -303,6 +275,10 @@ void mmc_release_host(struct mmc_host *host)
EXPORT_SYMBOL(mmc_release_host);
+/*
+ * Internal function that does the actual ios call to the host driver,
+ * optionally printing some debug output.
+ */
static inline void mmc_set_ios(struct mmc_host *host)
{
struct mmc_ios *ios = &host->ios;
@@ -316,6 +292,9 @@ static inline void mmc_set_ios(struct mmc_host *host)
host->ops->set_ios(host, ios);
}
+/*
+ * Control chip select pin on a host.
+ */
void mmc_set_chip_select(struct mmc_host *host, int mode)
{
host->ios.chip_select = mode;
@@ -323,10 +302,43 @@ void mmc_set_chip_select(struct mmc_host *host, int mode)
}
/*
+ * Sets the host clock to the highest possible frequency that
+ * is below "hz".
+ */
+void mmc_set_clock(struct mmc_host *host, unsigned int hz)
+{
+ WARN_ON(hz < host->f_min);
+
+ if (hz > host->f_max)
+ hz = host->f_max;
+
+ host->ios.clock = hz;
+ mmc_set_ios(host);
+}
+
+/*
+ * Change the bus mode (open drain/push-pull) of a host.
+ */
+void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode)
+{
+ host->ios.bus_mode = mode;
+ mmc_set_ios(host);
+}
+
+/*
+ * Change data bus width of a host.
+ */
+void mmc_set_bus_width(struct mmc_host *host, unsigned int width)
+{
+ host->ios.bus_width = width;
+ mmc_set_ios(host);
+}
+
+/*
* Mask off any voltages we don't support and select
* the lowest voltage
*/
-static u32 mmc_select_voltage(struct mmc_host *host, u32 ocr)
+u32 mmc_select_voltage(struct mmc_host *host, u32 ocr)
{
int bit;
@@ -347,235 +359,19 @@ static u32 mmc_select_voltage(struct mmc_host *host, u32 ocr)
return ocr;
}
-#define UNSTUFF_BITS(resp,start,size) \
- ({ \
- const int __size = size; \
- const u32 __mask = (__size < 32 ? 1 << __size : 0) - 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) % 32); \
- __res & __mask; \
- })
-
-/*
- * Given the decoded CSD structure, decode the raw CID to our CID structure.
- */
-static void mmc_decode_cid(struct mmc_card *card)
-{
- u32 *resp = card->raw_cid;
-
- memset(&card->cid, 0, sizeof(struct mmc_cid));
-
- 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 */
- case 4: /* MMC v4 */
- 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;
- }
- }
-}
-
-/*
- * 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, csd_struct;
- u32 *resp = card->raw_csd;
-
- if (mmc_card_sd(card)) {
- csd_struct = UNSTUFF_BITS(resp, 126, 2);
-
- switch (csd_struct) {
- case 0:
- 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_partial = UNSTUFF_BITS(resp, 79, 1);
- csd->write_misalign = UNSTUFF_BITS(resp, 78, 1);
- csd->read_misalign = UNSTUFF_BITS(resp, 77, 1);
- csd->r2w_factor = UNSTUFF_BITS(resp, 26, 3);
- csd->write_blkbits = UNSTUFF_BITS(resp, 22, 4);
- csd->write_partial = UNSTUFF_BITS(resp, 21, 1);
- break;
- case 1:
- /*
- * This is a block-addressed SDHC card. Most
- * interesting fields are unused and have fixed
- * values. To avoid getting tripped by buggy cards,
- * we assume those fixed values ourselves.
- */
- mmc_card_set_blockaddr(card);
-
- csd->tacc_ns = 0; /* Unused */
- csd->tacc_clks = 0; /* Unused */
-
- 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, 48, 22);
- csd->capacity = (1 + m) << 10;
-
- csd->read_blkbits = 9;
- csd->read_partial = 0;
- csd->write_misalign = 0;
- csd->read_misalign = 0;
- csd->r2w_factor = 4; /* Unused */
- csd->write_blkbits = 9;
- csd->write_partial = 0;
- break;
- default:
- printk("%s: unrecognised CSD structure version %d\n",
- mmc_hostname(card->host), csd_struct);
- mmc_card_set_bad(card);
- return;
- }
- } 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);
- 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_partial = UNSTUFF_BITS(resp, 79, 1);
- csd->write_misalign = UNSTUFF_BITS(resp, 78, 1);
- csd->read_misalign = UNSTUFF_BITS(resp, 77, 1);
- csd->r2w_factor = UNSTUFF_BITS(resp, 26, 3);
- csd->write_blkbits = UNSTUFF_BITS(resp, 22, 4);
- csd->write_partial = UNSTUFF_BITS(resp, 21, 1);
- }
-}
-
/*
- * Given a 64-bit response, decode to our card SCR structure.
+ * Select timing parameters for host.
*/
-static void mmc_decode_scr(struct mmc_card *card)
+void mmc_set_timing(struct mmc_host *host, unsigned int timing)
{
- 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",
- mmc_hostname(card->host), scr_struct);
- mmc_card_set_bad(card);
- return;
- }
-
- scr->sda_vsn = UNSTUFF_BITS(resp, 56, 4);
- scr->bus_widths = UNSTUFF_BITS(resp, 48, 4);
+ host->ios.timing = timing;
+ mmc_set_ios(host);
}
/*
* Allocate a new MMC card
*/
-static struct mmc_card *
-mmc_alloc_card(struct mmc_host *host, u32 *raw_cid)
+struct mmc_card *mmc_alloc_card(struct mmc_host *host)
{
struct mmc_card *card;
@@ -584,7 +380,6 @@ mmc_alloc_card(struct mmc_host *host, u32 *raw_cid)
return ERR_PTR(-ENOMEM);
mmc_init_card(card, host);
- memcpy(card->raw_cid, raw_cid, sizeof(card->raw_cid));
return card;
}
@@ -634,406 +429,66 @@ static void mmc_power_off(struct mmc_host *host)
}
/*
- * Discover the card by requesting its CID.
- *
- * Create a mmc_card entry for the discovered card, assigning
- * it an RCA, and save the raw CID for decoding later.
+ * Assign a mmc bus handler to a host. Only one bus handler may control a
+ * host at any given time.
*/
-static void mmc_discover_card(struct mmc_host *host)
+void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops)
{
- unsigned int err;
- u32 cid[4];
-
- BUG_ON(host->card);
-
- err = mmc_all_send_cid(host, cid);
- if (err != MMC_ERR_NONE) {
- printk(KERN_ERR "%s: error requesting CID: %d\n",
- mmc_hostname(host), err);
- return;
- }
-
- host->card = mmc_alloc_card(host, cid);
- if (IS_ERR(host->card)) {
- err = PTR_ERR(host->card);
- host->card = NULL;
- return;
- }
-
- if (host->mode == MMC_MODE_SD) {
- host->card->type = MMC_TYPE_SD;
-
- err = mmc_send_relative_addr(host, &host->card->rca);
- if (err != MMC_ERR_NONE)
- mmc_card_set_dead(host->card);
- else {
- if (!host->ops->get_ro) {
- printk(KERN_WARNING "%s: host does not "
- "support reading read-only "
- "switch. assuming write-enable.\n",
- mmc_hostname(host));
- } else {
- if (host->ops->get_ro(host))
- mmc_card_set_readonly(host->card);
- }
- }
- } else {
- host->card->type = MMC_TYPE_MMC;
- host->card->rca = 1;
-
- err = mmc_set_relative_addr(host->card);
- if (err != MMC_ERR_NONE)
- mmc_card_set_dead(host->card);
- }
-}
-
-static void mmc_read_csd(struct mmc_host *host)
-{
- int err;
-
- if (!host->card)
- return;
- if (mmc_card_dead(host->card))
- return;
-
- err = mmc_send_csd(host->card, host->card->raw_csd);
- if (err != MMC_ERR_NONE) {
- mmc_card_set_dead(host->card);
- return;
- }
-
- mmc_decode_csd(host->card);
- mmc_decode_cid(host->card);
-}
-
-static void mmc_process_ext_csd(struct mmc_host *host)
-{
- int err;
- u8 *ext_csd;
-
- if (!host->card)
- return;
- if (mmc_card_dead(host->card))
- return;
- if (mmc_card_sd(host->card))
- return;
- if (host->card->csd.mmca_vsn < CSD_SPEC_VER_4)
- return;
-
- /*
- * As the ext_csd is so large and mostly unused, we don't store the
- * raw block in mmc_card.
- */
- ext_csd = kmalloc(512, GFP_KERNEL);
- if (!ext_csd) {
- printk("%s: could not allocate a buffer to receive the ext_csd."
- "mmc v4 cards will be treated as v3.\n",
- mmc_hostname(host));
- return;
- }
-
- err = mmc_send_ext_csd(host->card, ext_csd);
- if (err != MMC_ERR_NONE) {
- if (host->card->csd.capacity == (4096 * 512)) {
- printk(KERN_ERR "%s: unable to read EXT_CSD "
- "on a possible high capacity card. "
- "Card will be ignored.\n",
- mmc_hostname(host));
- mmc_card_set_dead(host->card);
- } else {
- printk(KERN_WARNING "%s: unable to read "
- "EXT_CSD, performance might "
- "suffer.\n",
- mmc_hostname(host));
- }
- goto out;
- }
-
- host->card->ext_csd.sectors =
- ext_csd[EXT_CSD_SEC_CNT + 0] << 0 |
- ext_csd[EXT_CSD_SEC_CNT + 1] << 8 |
- ext_csd[EXT_CSD_SEC_CNT + 2] << 16 |
- ext_csd[EXT_CSD_SEC_CNT + 3] << 24;
- if (host->card->ext_csd.sectors)
- mmc_card_set_blockaddr(host->card);
-
- switch (ext_csd[EXT_CSD_CARD_TYPE]) {
- case EXT_CSD_CARD_TYPE_52 | EXT_CSD_CARD_TYPE_26:
- host->card->ext_csd.hs_max_dtr = 52000000;
- break;
- case EXT_CSD_CARD_TYPE_26:
- host->card->ext_csd.hs_max_dtr = 26000000;
- break;
- default:
- /* MMC v4 spec says this cannot happen */
- printk("%s: card is mmc v4 but doesn't support "
- "any high-speed modes.\n",
- mmc_hostname(host));
- goto out;
- }
-
- if (host->caps & MMC_CAP_MMC_HIGHSPEED) {
- /* Activate highspeed support. */
- err = mmc_switch(host->card, MMC_SWITCH_MODE_WRITE_BYTE,
- EXT_CSD_HS_TIMING, 1);
- if (err != MMC_ERR_NONE) {
- printk("%s: failed to switch card to mmc v4 "
- "high-speed mode.\n",
- mmc_hostname(host));
- goto out;
- }
-
- mmc_card_set_highspeed(host->card);
-
- host->ios.timing = MMC_TIMING_MMC_HS;
- mmc_set_ios(host);
- }
+ unsigned long flags;
- /* Check for host support for wide-bus modes. */
- if (host->caps & MMC_CAP_4_BIT_DATA) {
- /* Activate 4-bit support. */
- err = mmc_switch(host->card, MMC_SWITCH_MODE_WRITE_BYTE,
- EXT_CSD_BUS_WIDTH, EXT_CSD_BUS_WIDTH_4 |
- EXT_CSD_CMD_SET_NORMAL);
- if (err != MMC_ERR_NONE) {
- printk("%s: failed to switch card to "
- "mmc v4 4-bit bus mode.\n",
- mmc_hostname(host));
- goto out;
- }
+ BUG_ON(!host);
+ BUG_ON(!ops);
- host->ios.bus_width = MMC_BUS_WIDTH_4;
- mmc_set_ios(host);
- }
+ BUG_ON(!host->claimed);
-out:
- kfree(ext_csd);
-}
+ spin_lock_irqsave(&host->lock, flags);
-static void mmc_read_scr(struct mmc_host *host)
-{
- int err;
+ BUG_ON(host->bus_ops);
+ BUG_ON(host->bus_refs);
- if (!host->card)
- return;
- if (mmc_card_dead(host->card))
- return;
- if (!mmc_card_sd(host->card))
- return;
-
- err = mmc_app_send_scr(host->card, host->card->raw_scr);
- if (err != MMC_ERR_NONE) {
- mmc_card_set_dead(host->card);
- return;
- }
+ host->bus_ops = ops;
+ host->bus_refs = 1;
+ host->bus_dead = 0;
- mmc_decode_scr(host->card);
+ spin_unlock_irqrestore(&host->lock, flags);
}
-static void mmc_read_switch_caps(struct mmc_host *host)
+/*
+ * Remove the current bus handler from a host. Assumes that there are
+ * no interesting cards left, so the bus is powered down.
+ */
+void mmc_detach_bus(struct mmc_host *host)
{
- int err;
- unsigned char *status;
-
- if (!(host->caps & MMC_CAP_SD_HIGHSPEED))
- return;
-
- if (!host->card)
- return;
- if (mmc_card_dead(host->card))
- return;
- if (!mmc_card_sd(host->card))
- return;
- if (host->card->scr.sda_vsn < SCR_SPEC_VER_1)
- return;
-
- status = kmalloc(64, GFP_KERNEL);
- if (!status) {
- printk(KERN_WARNING "%s: Unable to allocate buffer for "
- "reading switch capabilities.\n",
- mmc_hostname(host));
- return;
- }
-
- err = mmc_sd_switch(host->card, SD_SWITCH_CHECK,
- SD_SWITCH_GRP_ACCESS, SD_SWITCH_ACCESS_HS, status);
- if (err != MMC_ERR_NONE) {
- printk("%s: unable to read switch capabilities, "
- "performance might suffer.\n",
- mmc_hostname(host));
- goto out;
- }
-
- if (status[13] & 0x02)
- host->card->sw_caps.hs_max_dtr = 50000000;
+ unsigned long flags;
- err = mmc_sd_switch(host->card, SD_SWITCH_SET,
- SD_SWITCH_GRP_ACCESS, SD_SWITCH_ACCESS_HS, status);
- if (err != MMC_ERR_NONE || (status[16] & 0xF) != 1) {
- printk(KERN_WARNING "%s: Problem switching card "
- "into high-speed mode!\n",
- mmc_hostname(host));
- goto out;
- }
+ BUG_ON(!host);
- mmc_card_set_highspeed(host->card);
+ BUG_ON(!host->claimed);
+ BUG_ON(!host->bus_ops);
- host->ios.timing = MMC_TIMING_SD_HS;
- mmc_set_ios(host);
+ spin_lock_irqsave(&host->lock, flags);
-out:
- kfree(status);
-}
+ host->bus_dead = 1;
-static unsigned int mmc_calculate_clock(struct mmc_host *host)
-{
- unsigned int max_dtr = host->f_max;
-
- if (host->card && !mmc_card_dead(host->card)) {
- if (mmc_card_highspeed(host->card) && mmc_card_sd(host->card)) {
- if (max_dtr > host->card->sw_caps.hs_max_dtr)
- max_dtr = host->card->sw_caps.hs_max_dtr;
- } else if (mmc_card_highspeed(host->card) && !mmc_card_sd(host->card)) {
- if (max_dtr > host->card->ext_csd.hs_max_dtr)
- max_dtr = host->card->ext_csd.hs_max_dtr;
- } else if (max_dtr > host->card->csd.max_dtr) {
- max_dtr = host->card->csd.max_dtr;
- }
- }
+ spin_unlock_irqrestore(&host->lock, flags);
- pr_debug("%s: selected %d.%03dMHz transfer rate\n",
- mmc_hostname(host),
- max_dtr / 1000000, (max_dtr / 1000) % 1000);
+ mmc_power_off(host);
- return max_dtr;
+ mmc_bus_put(host);
}
/*
- * Check whether cards we already know about are still present.
- * We do this by requesting status, and checking whether a card
- * responds.
- *
- * A request for status does not cause a state change in data
- * transfer mode.
+ * Cleanup when the last reference to the bus operator is dropped.
*/
-static void mmc_check_card(struct mmc_card *card)
+void __mmc_release_bus(struct mmc_host *host)
{
- int err;
-
- BUG_ON(!card);
+ BUG_ON(!host);
+ BUG_ON(host->bus_refs);
+ BUG_ON(!host->bus_dead);
- err = mmc_send_status(card, NULL);
- if (err == MMC_ERR_NONE)
- return;
-
- mmc_card_set_dead(card);
+ host->bus_ops = NULL;
}
-static void mmc_setup(struct mmc_host *host)
-{
- int err;
- u32 ocr;
-
- host->mode = MMC_MODE_SD;
-
- mmc_power_up(host);
- mmc_go_idle(host);
-
- err = mmc_send_if_cond(host, host->ocr_avail);
- if (err != MMC_ERR_NONE) {
- return;
- }
- err = mmc_send_app_op_cond(host, 0, &ocr);
-
- /*
- * If we fail to detect any SD cards then try
- * searching for MMC cards.
- */
- if (err != MMC_ERR_NONE) {
- host->mode = MMC_MODE_MMC;
-
- err = mmc_send_op_cond(host, 0, &ocr);
- if (err != MMC_ERR_NONE)
- return;
- }
-
- host->ocr = mmc_select_voltage(host, ocr);
-
- if (host->ocr == 0)
- return;
-
- /*
- * Since we're changing the OCR value, we seem to
- * need to tell some cards to go back to the idle
- * state. We wait 1ms to give cards time to
- * respond.
- */
- mmc_go_idle(host);
-
- /*
- * Send the selected OCR multiple times... until the cards
- * all get the idea that they should be ready for CMD2.
- * (My SanDisk card seems to need this.)
- */
- if (host->mode == MMC_MODE_SD) {
- /*
- * If SD_SEND_IF_COND indicates an SD 2.0
- * compliant card and we should set bit 30
- * of the ocr to indicate that we can handle
- * block-addressed SDHC cards.
- */
- err = mmc_send_if_cond(host, host->ocr);
- if (err == MMC_ERR_NONE)
- ocr = host->ocr | (1 << 30);
-
- mmc_send_app_op_cond(host, ocr, NULL);
- } else {
- /* The extra bit indicates that we support high capacity */
- mmc_send_op_cond(host, host->ocr | (1 << 30), NULL);
- }
-
- mmc_discover_card(host);
-
- /*
- * Ok, now switch to push-pull mode.
- */
- host->ios.bus_mode = MMC_BUSMODE_PUSHPULL;
- mmc_set_ios(host);
-
- mmc_read_csd(host);
-
- if (host->card && !mmc_card_dead(host->card)) {
- err = mmc_select_card(host->card);
- if (err != MMC_ERR_NONE)
- mmc_card_set_dead(host->card);
- }
-
- /*
- * The card is in 1 bit mode by default so
- * we only need to change if it supports the
- * wider version.
- */
- if (host->card && !mmc_card_dead(host->card) &&
- mmc_card_sd(host->card) &&
- (host->card->scr.bus_widths & SD_SCR_BUS_WIDTH_4) &&
- (host->card->host->caps & MMC_CAP_4_BIT_DATA)) {
- err = mmc_app_set_bus_width(host->card, SD_BUS_WIDTH_4);
- if (err != MMC_ERR_NONE)
- mmc_card_set_dead(host->card);
- else {
- host->ios.bus_width = MMC_BUS_WIDTH_4;
- mmc_set_ios(host);
- }
- }
-
- if (host->mode == MMC_MODE_SD) {
- mmc_read_scr(host);
- mmc_read_switch_caps(host);
- } else
- mmc_process_ext_csd(host);
-}
-
-
/**
* mmc_detect_change - process change of state on a MMC socket
* @host: host which changed state.
@@ -1060,62 +515,49 @@ static void mmc_rescan(struct work_struct *work)
{
struct mmc_host *host =
container_of(work, struct mmc_host, detect.work);
+ u32 ocr;
+ int err;
- mmc_claim_host(host);
-
- /*
- * Check for removed card and newly inserted ones. We check for
- * removed cards first so we can intelligently re-select the VDD.
- */
- if (host->card) {
- mmc_check_card(host->card);
-
- mmc_release_host(host);
-
- if (mmc_card_dead(host->card)) {
- mmc_remove_card(host->card);
- host->card = NULL;
- }
-
- goto out;
- }
-
- mmc_setup(host);
+ mmc_bus_get(host);
- if (host->card && !mmc_card_dead(host->card)) {
+ if (host->bus_ops == NULL) {
/*
- * (Re-)calculate the fastest clock rate which the
- * attached cards and the host support.
+ * Only we can add a new handler, so it's safe to
+ * release the lock here.
*/
- host->ios.clock = mmc_calculate_clock(host);
- mmc_set_ios(host);
- }
+ mmc_bus_put(host);
- mmc_release_host(host);
+ mmc_claim_host(host);
- /*
- * If this is a new and good card, register it.
- */
- if (host->card && !mmc_card_dead(host->card)) {
- if (mmc_register_card(host->card))
- mmc_card_set_dead(host->card);
- }
+ mmc_power_up(host);
+ mmc_go_idle(host);
- /*
- * If this card is dead, destroy it.
- */
- if (host->card && mmc_card_dead(host->card)) {
- mmc_remove_card(host->card);
- host->card = NULL;
- }
+ mmc_send_if_cond(host, host->ocr_avail);
-out:
- /*
- * If we discover that there are no cards on the
- * bus, turn off the clock and power down.
- */
- if (!host->card)
- mmc_power_off(host);
+ err = mmc_send_app_op_cond(host, 0, &ocr);
+ if (err == MMC_ERR_NONE) {
+ if (mmc_attach_sd(host, ocr))
+ mmc_power_off(host);
+ } else {
+ /*
+ * If we fail to detect any SD cards then try
+ * searching for MMC cards.
+ */
+ err = mmc_send_op_cond(host, 0, &ocr);
+ if (err == MMC_ERR_NONE) {
+ if (mmc_attach_mmc(host, ocr))
+ mmc_power_off(host);
+ } else {
+ mmc_power_off(host);
+ mmc_release_host(host);
+ }
+ }
+ } else {
+ if (host->bus_ops->detect && !host->bus_dead)
+ host->bus_ops->detect(host);
+
+ mmc_bus_put(host);
+ }
}
@@ -1190,10 +632,18 @@ void mmc_remove_host(struct mmc_host *host)
mmc_flush_scheduled_work();
- if (host->card) {
- mmc_remove_card(host->card);
- host->card = NULL;
+ mmc_bus_get(host);
+ if (host->bus_ops && !host->bus_dead) {
+ if (host->bus_ops->remove)
+ host->bus_ops->remove(host);
+
+ mmc_claim_host(host);
+ mmc_detach_bus(host);
+ mmc_release_host(host);
}
+ mmc_bus_put(host);
+
+ BUG_ON(host->card);
mmc_power_off(host);
mmc_remove_host_sysfs(host);
@@ -1225,10 +675,15 @@ int mmc_suspend_host(struct mmc_host *host, pm_message_t state)
{
mmc_flush_scheduled_work();
- if (host->card) {
- mmc_remove_card(host->card);
- host->card = NULL;
+ mmc_bus_get(host);
+ if (host->bus_ops && !host->bus_dead) {
+ if (host->bus_ops->remove)
+ host->bus_ops->remove(host);
+ mmc_detach_bus(host);
}
+ mmc_bus_put(host);
+
+ BUG_ON(host->card);
mmc_power_off(host);
diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h
index 1c10663..fad8edc 100644
--- a/drivers/mmc/core/core.h
+++ b/drivers/mmc/core/core.h
@@ -15,7 +15,44 @@
#define MMC_CMD_RETRIES 3
+struct mmc_bus_ops {
+ void (*remove)(struct mmc_host *);
+ void (*detect)(struct mmc_host *);
+};
+
+void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops);
+void mmc_detach_bus(struct mmc_host *host);
+
+void __mmc_release_bus(struct mmc_host *host);
+
+static inline void mmc_bus_get(struct mmc_host *host)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&host->lock, flags);
+ host->bus_refs++;
+ spin_unlock_irqrestore(&host->lock, flags);
+}
+
+static inline void mmc_bus_put(struct mmc_host *host)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&host->lock, flags);
+ host->bus_refs--;
+ if ((host->bus_refs == 0) && host->bus_ops)
+ __mmc_release_bus(host);
+ spin_unlock_irqrestore(&host->lock, flags);
+}
+
void mmc_set_chip_select(struct mmc_host *host, int mode);
+void mmc_set_clock(struct mmc_host *host, unsigned int hz);
+void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode);
+void mmc_set_bus_width(struct mmc_host *host, unsigned int width);
+u32 mmc_select_voltage(struct mmc_host *host, u32 ocr);
+void mmc_set_timing(struct mmc_host *host, unsigned int timing);
+
+struct mmc_card *mmc_alloc_card(struct mmc_host *host);
static inline void mmc_delay(unsigned int ms)
{
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
new file mode 100644
index 0000000..c528017
--- /dev/null
+++ b/drivers/mmc/core/mmc.c
@@ -0,0 +1,430 @@
+/*
+ * linux/drivers/mmc/mmc.c
+ *
+ * Copyright (C) 2003-2004 Russell King, All Rights Reserved.
+ * Copyright (C) 2005-2007 Pierre Ossman, All Rights Reserved.
+ * MMCv4 support Copyright (C) 2006 Philip Langdale, 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
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/err.h>
+
+#include <linux/mmc/host.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/mmc.h>
+
+#include "core.h"
+#include "sysfs.h"
+#include "mmc_ops.h"
+
+static const unsigned int tran_exp[] = {
+ 10000, 100000, 1000000, 10000000,
+ 0, 0, 0, 0
+};
+
+static const unsigned char tran_mant[] = {
+ 0, 10, 12, 13, 15, 20, 25, 30,
+ 35, 40, 45, 50, 55, 60, 70, 80,
+};
+
+static const unsigned int tacc_exp[] = {
+ 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000,
+};
+
+static const unsigned int tacc_mant[] = {
+ 0, 10, 12, 13, 15, 20, 25, 30,
+ 35, 40, 45, 50, 55, 60, 70, 80,
+};
+
+#define UNSTUFF_BITS(resp,start,size) \
+ ({ \
+ const int __size = size; \
+ const u32 __mask = (__size < 32 ? 1 << __size : 0) - 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) % 32); \
+ __res & __mask; \
+ })
+
+/*
+ * Given the decoded CSD structure, decode the raw CID to our CID structure.
+ */
+static void mmc_decode_cid(struct mmc_card *card)
+{
+ u32 *resp = card->raw_cid;
+
+ /*
+ * 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 */
+ case 4: /* MMC v4 */
+ 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;
+ }
+}
+
+/*
+ * 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, csd_struct;
+ u32 *resp = card->raw_csd;
+
+ /*
+ * 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);
+ 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_partial = UNSTUFF_BITS(resp, 79, 1);
+ csd->write_misalign = UNSTUFF_BITS(resp, 78, 1);
+ csd->read_misalign = UNSTUFF_BITS(resp, 77, 1);
+ csd->r2w_factor = UNSTUFF_BITS(resp, 26, 3);
+ csd->write_blkbits = UNSTUFF_BITS(resp, 22, 4);
+ csd->write_partial = UNSTUFF_BITS(resp, 21, 1);
+}
+
+/*
+ * Read and decode extended CSD. Switch to high-speed and wide bus
+ * if supported.
+ */
+static int mmc_process_ext_csd(struct mmc_card *card)
+{
+ int err;
+ u8 *ext_csd;
+
+ BUG_ON(!card);
+
+ err = MMC_ERR_FAILED;
+
+ if (card->csd.mmca_vsn < CSD_SPEC_VER_4)
+ return MMC_ERR_NONE;
+
+ /*
+ * As the ext_csd is so large and mostly unused, we don't store the
+ * raw block in mmc_card.
+ */
+ ext_csd = kmalloc(512, GFP_KERNEL);
+ if (!ext_csd) {
+ printk(KERN_ERR "%s: could not allocate a buffer to "
+ "receive the ext_csd. mmc v4 cards will be "
+ "treated as v3.\n", mmc_hostname(card->host));
+ return MMC_ERR_FAILED;
+ }
+
+ err = mmc_send_ext_csd(card, ext_csd);
+ if (err != MMC_ERR_NONE) {
+ /*
+ * High capacity cards should have this "magic" size
+ * stored in their CSD.
+ */
+ if (card->csd.capacity == (4096 * 512)) {
+ printk(KERN_ERR "%s: unable to read EXT_CSD "
+ "on a possible high capacity card. "
+ "Card will be ignored.\n",
+ mmc_hostname(card->host));
+ } else {
+ printk(KERN_WARNING "%s: unable to read "
+ "EXT_CSD, performance might "
+ "suffer.\n",
+ mmc_hostname(card->host));
+ err = MMC_ERR_NONE;
+ }
+ goto out;
+ }
+
+ card->ext_csd.sectors =
+ ext_csd[EXT_CSD_SEC_CNT + 0] << 0 |
+ ext_csd[EXT_CSD_SEC_CNT + 1] << 8 |
+ ext_csd[EXT_CSD_SEC_CNT + 2] << 16 |
+ ext_csd[EXT_CSD_SEC_CNT + 3] << 24;
+ if (card->ext_csd.sectors)
+ mmc_card_set_blockaddr(card);
+
+ switch (ext_csd[EXT_CSD_CARD_TYPE]) {
+ case EXT_CSD_CARD_TYPE_52 | EXT_CSD_CARD_TYPE_26:
+ card->ext_csd.hs_max_dtr = 52000000;
+ break;
+ case EXT_CSD_CARD_TYPE_26:
+ card->ext_csd.hs_max_dtr = 26000000;
+ break;
+ default:
+ /* MMC v4 spec says this cannot happen */
+ printk(KERN_WARNING "%s: card is mmc v4 but doesn't "
+ "support any high-speed modes.\n",
+ mmc_hostname(card->host));
+ goto out;
+ }
+
+ if (card->host->caps & MMC_CAP_MMC_HIGHSPEED) {
+ /* Activate highspeed support. */
+ err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+ EXT_CSD_HS_TIMING, 1);
+ if (err != MMC_ERR_NONE) {
+ printk(KERN_WARNING "%s: failed to switch "
+ "card to mmc v4 high-speed mode.\n",
+ mmc_hostname(card->host));
+ err = MMC_ERR_NONE;
+ goto out;
+ }
+
+ mmc_card_set_highspeed(card);
+
+ mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
+ }
+
+ /* Check for host support for wide-bus modes. */
+ if (card->host->caps & MMC_CAP_4_BIT_DATA) {
+ /* Activate 4-bit support. */
+ err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+ EXT_CSD_BUS_WIDTH, EXT_CSD_BUS_WIDTH_4);
+ if (err != MMC_ERR_NONE) {
+ printk(KERN_WARNING "%s: failed to switch "
+ "card to mmc v4 4-bit bus mode.\n",
+ mmc_hostname(card->host));
+ err = MMC_ERR_NONE;
+ goto out;
+ }
+
+ mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4);
+ }
+
+out:
+ kfree(ext_csd);
+
+ return err;
+}
+
+/*
+ * Host is being removed. Free up the current card.
+ */
+static void mmc_remove(struct mmc_host *host)
+{
+ BUG_ON(!host);
+ BUG_ON(!host->card);
+
+ mmc_remove_card(host->card);
+ host->card = NULL;
+}
+
+/*
+ * Card detection callback from host.
+ */
+static void mmc_detect(struct mmc_host *host)
+{
+ int err;
+
+ BUG_ON(!host);
+ BUG_ON(!host->card);
+
+ mmc_claim_host(host);
+
+ /*
+ * Just check if our card has been removed.
+ */
+ err = mmc_send_status(host->card, NULL);
+
+ mmc_release_host(host);
+
+ if (err != MMC_ERR_NONE) {
+ mmc_remove_card(host->card);
+ host->card = NULL;
+
+ mmc_claim_host(host);
+ mmc_detach_bus(host);
+ mmc_release_host(host);
+ }
+}
+
+static const struct mmc_bus_ops mmc_ops = {
+ .remove = mmc_remove,
+ .detect = mmc_detect,
+};
+
+/*
+ * Starting point for MMC card init.
+ */
+int mmc_attach_mmc(struct mmc_host *host, u32 ocr)
+{
+ struct mmc_card *card;
+ int err;
+ u32 cid[4];
+ unsigned int max_dtr;
+
+ BUG_ON(!host);
+ BUG_ON(!host->claimed);
+
+ mmc_attach_bus(host, &mmc_ops);
+
+ host->ocr = mmc_select_voltage(host, ocr);
+
+ /*
+ * Can we support the voltage of the card?
+ */
+ if (!host->ocr)
+ goto err;
+
+ /*
+ * Since we're changing the OCR value, we seem to
+ * need to tell some cards to go back to the idle
+ * state. We wait 1ms to give cards time to
+ * respond.
+ */
+ mmc_go_idle(host);
+
+ /* The extra bit indicates that we support high capacity */
+ mmc_send_op_cond(host, host->ocr | (1 << 30), NULL);
+
+ /*
+ * Fetch CID from card.
+ */
+ err = mmc_all_send_cid(host, cid);
+ if (err != MMC_ERR_NONE)
+ goto err;
+
+ /*
+ * Allocate card structure.
+ */
+ card = mmc_alloc_card(host);
+ if (IS_ERR(card))
+ goto err;
+
+ card->type = MMC_TYPE_MMC;
+ card->rca = 1;
+ memcpy(card->raw_cid, cid, sizeof(card->raw_cid));
+
+ /*
+ * Set card RCA.
+ */
+ err = mmc_set_relative_addr(card);
+ if (err != MMC_ERR_NONE)
+ goto free_card;
+
+ mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL);
+
+ /*
+ * Fetch CSD from card.
+ */
+ err = mmc_send_csd(card, card->raw_csd);
+ if (err != MMC_ERR_NONE)
+ goto free_card;
+
+ mmc_decode_csd(card);
+ mmc_decode_cid(card);
+
+ /*
+ * Fetch and process extened CSD.
+ * This will switch into high-speed and wide bus modes,
+ * as available.
+ */
+ err = mmc_select_card(card);
+ if (err != MMC_ERR_NONE)
+ goto free_card;
+
+ err = mmc_process_ext_csd(card);
+ if (err != MMC_ERR_NONE)
+ goto free_card;
+
+ /*
+ * Compute bus speed.
+ */
+ max_dtr = (unsigned int)-1;
+
+ if (mmc_card_highspeed(card)) {
+ if (max_dtr > card->ext_csd.hs_max_dtr)
+ max_dtr = card->ext_csd.hs_max_dtr;
+ } else if (max_dtr > card->csd.max_dtr) {
+ max_dtr = card->csd.max_dtr;
+ }
+
+ mmc_set_clock(host, max_dtr);
+
+ host->card = card;
+
+ mmc_release_host(host);
+
+ err = mmc_register_card(card);
+ if (err)
+ goto reclaim_host;
+
+ return 0;
+
+reclaim_host:
+ mmc_claim_host(host);
+free_card:
+ mmc_remove_card(card);
+ host->card = NULL;
+err:
+ mmc_detach_bus(host);
+ mmc_release_host(host);
+
+ return 0;
+}
+
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
new file mode 100644
index 0000000..6c6beb4
--- /dev/null
+++ b/drivers/mmc/core/sd.c
@@ -0,0 +1,431 @@
+/*
+ * linux/drivers/mmc/sd.c
+ *
+ * Copyright (C) 2003-2004 Russell King, All Rights Reserved.
+ * SD support Copyright (C) 2004 Ian Molton, All Rights Reserved.
+ * Copyright (C) 2005-2007 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
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/err.h>
+
+#include <linux/mmc/host.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/mmc.h>
+
+#include "core.h"
+#include "sysfs.h"
+#include "mmc_ops.h"
+#include "sd_ops.h"
+
+#include "core.h"
+
+static const unsigned int tran_exp[] = {
+ 10000, 100000, 1000000, 10000000,
+ 0, 0, 0, 0
+};
+
+static const unsigned char tran_mant[] = {
+ 0, 10, 12, 13, 15, 20, 25, 30,
+ 35, 40, 45, 50, 55, 60, 70, 80,
+};
+
+static const unsigned int tacc_exp[] = {
+ 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000,
+};
+
+static const unsigned int tacc_mant[] = {
+ 0, 10, 12, 13, 15, 20, 25, 30,
+ 35, 40, 45, 50, 55, 60, 70, 80,
+};
+
+#define UNSTUFF_BITS(resp,start,size) \
+ ({ \
+ const int __size = size; \
+ const u32 __mask = (__size < 32 ? 1 << __size : 0) - 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) % 32); \
+ __res & __mask; \
+ })
+
+/*
+ * Given the decoded CSD structure, decode the raw CID to our CID structure.
+ */
+static void mmc_decode_cid(struct mmc_card *card)
+{
+ u32 *resp = card->raw_cid;
+
+ memset(&card->cid, 0, sizeof(struct mmc_cid));
+
+ /*
+ * 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 */
+}
+
+/*
+ * 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, csd_struct;
+ u32 *resp = card->raw_csd;
+
+ csd_struct = UNSTUFF_BITS(resp, 126, 2);
+
+ switch (csd_struct) {
+ case 0:
+ 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_partial = UNSTUFF_BITS(resp, 79, 1);
+ csd->write_misalign = UNSTUFF_BITS(resp, 78, 1);
+ csd->read_misalign = UNSTUFF_BITS(resp, 77, 1);
+ csd->r2w_factor = UNSTUFF_BITS(resp, 26, 3);
+ csd->write_blkbits = UNSTUFF_BITS(resp, 22, 4);
+ csd->write_partial = UNSTUFF_BITS(resp, 21, 1);
+ break;
+ case 1:
+ /*
+ * This is a block-addressed SDHC card. Most
+ * interesting fields are unused and have fixed
+ * values. To avoid getting tripped by buggy cards,
+ * we assume those fixed values ourselves.
+ */
+ mmc_card_set_blockaddr(card);
+
+ csd->tacc_ns = 0; /* Unused */
+ csd->tacc_clks = 0; /* Unused */
+
+ 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, 48, 22);
+ csd->capacity = (1 + m) << 10;
+
+ csd->read_blkbits = 9;
+ csd->read_partial = 0;
+ csd->write_misalign = 0;
+ csd->read_misalign = 0;
+ csd->r2w_factor = 4; /* Unused */
+ csd->write_blkbits = 9;
+ csd->write_partial = 0;
+ break;
+ default:
+ printk("%s: unrecognised CSD structure version %d\n",
+ mmc_hostname(card->host), csd_struct);
+ mmc_card_set_bad(card);
+ return;
+ }
+}
+
+/*
+ * 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",
+ mmc_hostname(card->host), scr_struct);
+ mmc_card_set_bad(card);
+ return;
+ }
+
+ scr->sda_vsn = UNSTUFF_BITS(resp, 56, 4);
+ scr->bus_widths = UNSTUFF_BITS(resp, 48, 4);
+}
+
+/*
+ * Test if the card supports high-speed mode and, if so, switch to it.
+ */
+static int mmc_switch_hs(struct mmc_card *card)
+{
+ int err;
+ u8 *status;
+
+ if (!(card->host->caps & MMC_CAP_SD_HIGHSPEED))
+ return MMC_ERR_NONE;
+
+ err = MMC_ERR_FAILED;
+
+ status = kmalloc(64, GFP_KERNEL);
+ if (!status) {
+ printk("%s: could not allocate a buffer for switch "
+ "capabilities.\n",
+ mmc_hostname(card->host));
+ return err;
+ }
+
+ err = mmc_sd_switch(card, 0, 0, 1, status);
+ if (err != MMC_ERR_NONE) {
+ /*
+ * Card not supporting high-speed will ignore the
+ * command.
+ */
+ if (err == MMC_ERR_TIMEOUT)
+ err = MMC_ERR_NONE;
+ goto out;
+ }
+
+ if (status[13] & 0x02)
+ card->sw_caps.hs_max_dtr = 50000000;
+
+ err = mmc_sd_switch(card, 1, 0, 1, status);
+ if (err != MMC_ERR_NONE)
+ goto out;
+
+ if ((status[16] & 0xF) != 1) {
+ printk(KERN_WARNING "%s: Problem switching card "
+ "into high-speed mode!\n",
+ mmc_hostname(card->host));
+ } else {
+ mmc_card_set_highspeed(card);
+ mmc_set_timing(card->host, MMC_TIMING_SD_HS);
+ }
+
+out:
+ kfree(status);
+
+ return err;
+}
+
+/*
+ * Host is being removed. Free up the current card.
+ */
+static void mmc_sd_remove(struct mmc_host *host)
+{
+ BUG_ON(!host);
+ BUG_ON(!host->card);
+
+ mmc_remove_card(host->card);
+ host->card = NULL;
+}
+
+/*
+ * Card detection callback from host.
+ */
+static void mmc_sd_detect(struct mmc_host *host)
+{
+ int err;
+
+ BUG_ON(!host);
+ BUG_ON(!host->card);
+
+ mmc_claim_host(host);
+
+ /*
+ * Just check if our card has been removed.
+ */
+ err = mmc_send_status(host->card, NULL);
+
+ mmc_release_host(host);
+
+ if (err != MMC_ERR_NONE) {
+ mmc_remove_card(host->card);
+ host->card = NULL;
+
+ mmc_claim_host(host);
+ mmc_detach_bus(host);
+ mmc_release_host(host);
+ }
+}
+
+static const struct mmc_bus_ops mmc_sd_ops = {
+ .remove = mmc_sd_remove,
+ .detect = mmc_sd_detect,
+};
+
+/*
+ * Starting point for SD card init.
+ */
+int mmc_attach_sd(struct mmc_host *host, u32 ocr)
+{
+ struct mmc_card *card;
+ int err;
+ u32 cid[4];
+ unsigned int max_dtr;
+
+ BUG_ON(!host);
+ BUG_ON(!host->claimed);
+
+ mmc_attach_bus(host, &mmc_sd_ops);
+
+ host->ocr = mmc_select_voltage(host, ocr);
+
+ /*
+ * Can we support the voltage(s) of the card(s)?
+ */
+ if (!host->ocr)
+ goto err;
+
+ /*
+ * Since we're changing the OCR value, we seem to
+ * need to tell some cards to go back to the idle
+ * state. We wait 1ms to give cards time to
+ * respond.
+ */
+ mmc_go_idle(host);
+
+ /*
+ * If SD_SEND_IF_COND indicates an SD 2.0
+ * compliant card and we should set bit 30
+ * of the ocr to indicate that we can handle
+ * block-addressed SDHC cards.
+ */
+ err = mmc_send_if_cond(host, host->ocr);
+ if (err == MMC_ERR_NONE)
+ ocr = host->ocr | (1 << 30);
+
+ mmc_send_app_op_cond(host, ocr, NULL);
+
+ /*
+ * Fetch CID from card.
+ */
+ err = mmc_all_send_cid(host, cid);
+ if (err != MMC_ERR_NONE)
+ goto err;
+
+ /*
+ * Allocate card structure.
+ */
+ card = mmc_alloc_card(host);
+ if (IS_ERR(card))
+ goto err;
+
+ card->type = MMC_TYPE_SD;
+ memcpy(card->raw_cid, cid, sizeof(card->raw_cid));
+
+ /*
+ * Set card RCA.
+ */
+ err = mmc_send_relative_addr(host, &card->rca);
+ if (err != MMC_ERR_NONE)
+ goto free_card;
+
+ mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL);
+
+ /*
+ * Fetch CSD from card.
+ */
+ err = mmc_send_csd(card, card->raw_csd);
+ if (err != MMC_ERR_NONE)
+ goto free_card;
+
+ mmc_decode_csd(card);
+ mmc_decode_cid(card);
+
+ /*
+ * Fetch SCR from card.
+ */
+ err = mmc_select_card(card);
+ if (err != MMC_ERR_NONE)
+ goto free_card;
+
+ err = mmc_app_send_scr(card, card->raw_scr);
+ if (err != MMC_ERR_NONE)
+ goto free_card;
+
+ mmc_decode_scr(card);
+
+ /*
+ * Check if card can be switched into high-speed mode.
+ */
+ err = mmc_switch_hs(card);
+ if (err != MMC_ERR_NONE)
+ goto free_card;
+
+ /*
+ * Compute bus speed.
+ */
+ max_dtr = (unsigned int)-1;
+
+ if (mmc_card_highspeed(card)) {
+ if (max_dtr > card->sw_caps.hs_max_dtr)
+ max_dtr = card->sw_caps.hs_max_dtr;
+ } else if (max_dtr > card->csd.max_dtr) {
+ max_dtr = card->csd.max_dtr;
+ }
+
+ mmc_set_clock(host, max_dtr);
+
+ /*
+ * Switch to wider bus (if supported).
+ */
+ if ((host->caps && MMC_CAP_4_BIT_DATA) &&
+ (card->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) {
+ err = mmc_app_set_bus_width(card, MMC_BUS_WIDTH_4);
+ if (err != MMC_ERR_NONE)
+ goto free_card;
+
+ mmc_set_bus_width(host, MMC_BUS_WIDTH_4);
+ }
+
+ host->card = card;
+
+ mmc_release_host(host);
+
+ err = mmc_register_card(card);
+ if (err)
+ goto reclaim_host;
+
+ return 0;
+
+reclaim_host:
+ mmc_claim_host(host);
+free_card:
+ mmc_remove_card(card);
+ host->card = NULL;
+err:
+ mmc_detach_bus(host);
+ mmc_release_host(host);
+
+ return 0;
+}
+
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 43bf6a5..efae87b 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -131,6 +131,8 @@ struct mmc_host {
unsigned int max_blk_count; /* maximum number of blocks in one req */
/* private data */
+ spinlock_t lock; /* lock for claim and bus ops */
+
struct mmc_ios ios; /* current io bus settings */
u32 ocr; /* the current OCR setting */
@@ -141,7 +143,6 @@ struct mmc_host {
struct mmc_card *card; /* device attached to this host */
wait_queue_head_t wq;
- spinlock_t lock; /* claimed lock */
unsigned int claimed:1; /* host exclusively claimed */
struct delayed_work detect;
@@ -149,6 +150,10 @@ struct mmc_host {
unsigned int removed:1; /* host is being removed */
#endif
+ const struct mmc_bus_ops *bus_ops; /* current bus driver */
+ unsigned int bus_refs; /* reference counter */
+ unsigned int bus_dead:1; /* bus has been released */
+
unsigned long private[0] ____cacheline_aligned;
};
OpenPOWER on IntegriCloud