diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-05-25 16:55:55 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-05-25 16:55:55 -0700 |
commit | 8c1c77ff9be27137fa7cbbf51efedef1a2ae915b (patch) | |
tree | cdbd09cac5f5d1c6eb5ec4257dc478c6acca70c5 /drivers/mmc/core | |
parent | f3ae1c75203535f65448517e46c8dd70a56b6c71 (diff) | |
parent | 08ee80cc397ac1a306ca689a22ede954d92d0db1 (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc: (75 commits)
mmc: core: eMMC bus width may not work on all platforms
mmc: sdhci: Auto-CMD23 fixes.
mmc: sdhci: Auto-CMD23 support.
mmc: core: Block CMD23 support for UHS104/SDXC cards.
mmc: sdhci: Implement MMC_CAP_CMD23 for SDHCI.
mmc: core: Use CMD23 for multiblock transfers when we can.
mmc: quirks: Add/remove quirks conditional support.
mmc: Add new VUB300 USB-to-SD/SDIO/MMC driver
mmc: sdhci-pxa: Add quirks for DMA/ADMA to match h/w
mmc: core: duplicated trial with same freq in mmc_rescan_try_freq()
mmc: core: add support for eMMC Dual Data Rate
mmc: core: eMMC signal voltage does not use CMD11
mmc: sdhci-pxa: add platform code for UHS signaling
mmc: sdhci: add hooks for setting UHS in platform specific code
mmc: core: clear MMC_PM_KEEP_POWER flag on resume
mmc: dw_mmc: fixed wrong regulator_enable in suspend/resume
mmc: sdhi: allow powering down controller with no card inserted
mmc: tmio: runtime suspend the controller, where possible
mmc: sdhi: support up to 3 interrupt sources
mmc: sdhi: print physical base address and clock rate
...
Diffstat (limited to 'drivers/mmc/core')
-rw-r--r-- | drivers/mmc/core/bus.c | 11 | ||||
-rw-r--r-- | drivers/mmc/core/core.c | 111 | ||||
-rw-r--r-- | drivers/mmc/core/core.h | 7 | ||||
-rw-r--r-- | drivers/mmc/core/host.c | 4 | ||||
-rw-r--r-- | drivers/mmc/core/mmc.c | 186 | ||||
-rw-r--r-- | drivers/mmc/core/mmc_ops.c | 80 | ||||
-rw-r--r-- | drivers/mmc/core/mmc_ops.h | 1 | ||||
-rw-r--r-- | drivers/mmc/core/quirks.c | 89 | ||||
-rw-r--r-- | drivers/mmc/core/sd.c | 405 | ||||
-rw-r--r-- | drivers/mmc/core/sd.h | 2 | ||||
-rw-r--r-- | drivers/mmc/core/sd_ops.c | 51 | ||||
-rw-r--r-- | drivers/mmc/core/sdio.c | 24 | ||||
-rw-r--r-- | drivers/mmc/core/sdio_irq.c | 33 | ||||
-rw-r--r-- | drivers/mmc/core/sdio_ops.c | 18 |
14 files changed, 764 insertions, 258 deletions
diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c index d6d62fd07ee..393d817ed04 100644 --- a/drivers/mmc/core/bus.c +++ b/drivers/mmc/core/bus.c @@ -274,8 +274,12 @@ int mmc_add_card(struct mmc_card *card) break; case MMC_TYPE_SD: type = "SD"; - if (mmc_card_blockaddr(card)) - type = "SDHC"; + if (mmc_card_blockaddr(card)) { + if (mmc_card_ext_capacity(card)) + type = "SDXC"; + else + type = "SDHC"; + } break; case MMC_TYPE_SDIO: type = "SDIO"; @@ -299,7 +303,8 @@ int mmc_add_card(struct mmc_card *card) } else { printk(KERN_INFO "%s: new %s%s%s card at address %04x\n", mmc_hostname(card->host), - mmc_card_highspeed(card) ? "high speed " : "", + mmc_sd_card_uhs(card) ? "ultra high speed " : + (mmc_card_highspeed(card) ? "high speed " : ""), mmc_card_ddr_mode(card) ? "DDR " : "", type, card->rca); } diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 1f453acc868..68091dda3f3 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -236,12 +236,10 @@ EXPORT_SYMBOL(mmc_wait_for_req); */ int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, int retries) { - struct mmc_request mrq; + struct mmc_request mrq = {0}; WARN_ON(!host->claimed); - memset(&mrq, 0, sizeof(struct mmc_request)); - memset(cmd->resp, 0, sizeof(cmd->resp)); cmd->retries = retries; @@ -720,22 +718,12 @@ void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode) } /* - * Change data bus width and DDR mode of a host. - */ -void mmc_set_bus_width_ddr(struct mmc_host *host, unsigned int width, - unsigned int ddr) -{ - host->ios.bus_width = width; - host->ios.ddr = ddr; - mmc_set_ios(host); -} - -/* * Change data bus width of a host. */ void mmc_set_bus_width(struct mmc_host *host, unsigned int width) { - mmc_set_bus_width_ddr(host, width, MMC_SDR_MODE); + host->ios.bus_width = width; + mmc_set_ios(host); } /** @@ -944,6 +932,38 @@ u32 mmc_select_voltage(struct mmc_host *host, u32 ocr) return ocr; } +int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage, bool cmd11) +{ + struct mmc_command cmd = {0}; + int err = 0; + + BUG_ON(!host); + + /* + * Send CMD11 only if the request is to switch the card to + * 1.8V signalling. + */ + if ((signal_voltage != MMC_SIGNAL_VOLTAGE_330) && cmd11) { + cmd.opcode = SD_SWITCH_VOLTAGE; + cmd.arg = 0; + cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; + + err = mmc_wait_for_cmd(host, &cmd, 0); + if (err) + return err; + + if (!mmc_host_is_spi(host) && (cmd.resp[0] & R1_ERROR)) + return -EIO; + } + + host->ios.signal_voltage = signal_voltage; + + if (host->ops->start_signal_voltage_switch) + err = host->ops->start_signal_voltage_switch(host, &host->ios); + + return err; +} + /* * Select timing parameters for host. */ @@ -954,6 +974,15 @@ void mmc_set_timing(struct mmc_host *host, unsigned int timing) } /* + * Select appropriate driver type for host. + */ +void mmc_set_driver_type(struct mmc_host *host, unsigned int drv_type) +{ + host->ios.drv_type = drv_type; + mmc_set_ios(host); +} + +/* * Apply power to the MMC stack. This is a two-stage process. * First, we enable power to the card without the clock running. * We then wait a bit for the power to stabilise. Finally, @@ -1187,9 +1216,8 @@ void mmc_init_erase(struct mmc_card *card) } } -static void mmc_set_mmc_erase_timeout(struct mmc_card *card, - struct mmc_command *cmd, - unsigned int arg, unsigned int qty) +static unsigned int mmc_mmc_erase_timeout(struct mmc_card *card, + unsigned int arg, unsigned int qty) { unsigned int erase_timeout; @@ -1246,44 +1274,48 @@ static void mmc_set_mmc_erase_timeout(struct mmc_card *card, if (mmc_host_is_spi(card->host) && erase_timeout < 1000) erase_timeout = 1000; - cmd->erase_timeout = erase_timeout; + return erase_timeout; } -static void mmc_set_sd_erase_timeout(struct mmc_card *card, - struct mmc_command *cmd, unsigned int arg, - unsigned int qty) +static unsigned int mmc_sd_erase_timeout(struct mmc_card *card, + unsigned int arg, + unsigned int qty) { + unsigned int erase_timeout; + if (card->ssr.erase_timeout) { /* Erase timeout specified in SD Status Register (SSR) */ - cmd->erase_timeout = card->ssr.erase_timeout * qty + - card->ssr.erase_offset; + erase_timeout = card->ssr.erase_timeout * qty + + card->ssr.erase_offset; } else { /* * Erase timeout not specified in SD Status Register (SSR) so * use 250ms per write block. */ - cmd->erase_timeout = 250 * qty; + erase_timeout = 250 * qty; } /* Must not be less than 1 second */ - if (cmd->erase_timeout < 1000) - cmd->erase_timeout = 1000; + if (erase_timeout < 1000) + erase_timeout = 1000; + + return erase_timeout; } -static void mmc_set_erase_timeout(struct mmc_card *card, - struct mmc_command *cmd, unsigned int arg, - unsigned int qty) +static unsigned int mmc_erase_timeout(struct mmc_card *card, + unsigned int arg, + unsigned int qty) { if (mmc_card_sd(card)) - mmc_set_sd_erase_timeout(card, cmd, arg, qty); + return mmc_sd_erase_timeout(card, arg, qty); else - mmc_set_mmc_erase_timeout(card, cmd, arg, qty); + return mmc_mmc_erase_timeout(card, arg, qty); } static int mmc_do_erase(struct mmc_card *card, unsigned int from, unsigned int to, unsigned int arg) { - struct mmc_command cmd; + struct mmc_command cmd = {0}; unsigned int qty = 0; int err; @@ -1317,7 +1349,6 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from, to <<= 9; } - memset(&cmd, 0, sizeof(struct mmc_command)); if (mmc_card_sd(card)) cmd.opcode = SD_ERASE_WR_BLK_START; else @@ -1351,7 +1382,7 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from, cmd.opcode = MMC_ERASE; cmd.arg = arg; cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC; - mmc_set_erase_timeout(card, &cmd, arg, qty); + cmd.cmd_timeout_ms = mmc_erase_timeout(card, arg, qty); err = mmc_wait_for_cmd(card->host, &cmd, 0); if (err) { printk(KERN_ERR "mmc_erase: erase error %d, status %#x\n", @@ -1487,12 +1518,11 @@ EXPORT_SYMBOL(mmc_erase_group_aligned); int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen) { - struct mmc_command cmd; + struct mmc_command cmd = {0}; if (mmc_card_blockaddr(card) || mmc_card_ddr_mode(card)) return 0; - memset(&cmd, 0, sizeof(struct mmc_command)); cmd.opcode = MMC_SET_BLOCKLEN; cmd.arg = blocklen; cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC; @@ -1578,7 +1608,7 @@ void mmc_rescan(struct work_struct *work) for (i = 0; i < ARRAY_SIZE(freqs); i++) { if (!mmc_rescan_try_freq(host, max(freqs[i], host->f_min))) break; - if (freqs[i] < host->f_min) + if (freqs[i] <= host->f_min) break; } mmc_release_host(host); @@ -1746,7 +1776,7 @@ int mmc_suspend_host(struct mmc_host *host) } mmc_bus_put(host); - if (!err && !(host->pm_flags & MMC_PM_KEEP_POWER)) + if (!err && !mmc_card_keep_power(host)) mmc_power_off(host); return err; @@ -1764,7 +1794,7 @@ int mmc_resume_host(struct mmc_host *host) mmc_bus_get(host); if (host->bus_ops && !host->bus_dead) { - if (!(host->pm_flags & MMC_PM_KEEP_POWER)) { + if (!mmc_card_keep_power(host)) { mmc_power_up(host); mmc_select_voltage(host, host->ocr); /* @@ -1789,6 +1819,7 @@ int mmc_resume_host(struct mmc_host *host) err = 0; } } + host->pm_flags &= ~MMC_PM_KEEP_POWER; mmc_bus_put(host); return err; diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h index 20b1c0831ea..d9411ed2a39 100644 --- a/drivers/mmc/core/core.h +++ b/drivers/mmc/core/core.h @@ -38,10 +38,11 @@ void mmc_ungate_clock(struct mmc_host *host); void mmc_set_ungated(struct mmc_host *host); void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode); void mmc_set_bus_width(struct mmc_host *host, unsigned int width); -void mmc_set_bus_width_ddr(struct mmc_host *host, unsigned int width, - unsigned int ddr); u32 mmc_select_voltage(struct mmc_host *host, u32 ocr); +int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage, + bool cmd11); void mmc_set_timing(struct mmc_host *host, unsigned int timing); +void mmc_set_driver_type(struct mmc_host *host, unsigned int drv_type); static inline void mmc_delay(unsigned int ms) { @@ -61,8 +62,6 @@ int mmc_attach_mmc(struct mmc_host *host); int mmc_attach_sd(struct mmc_host *host); int mmc_attach_sdio(struct mmc_host *host); -void mmc_fixup_device(struct mmc_card *card); - /* Module parameters */ extern int use_spi_crc; diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index 461e6a17fb9..b29d3e8fd3a 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -325,12 +325,12 @@ int mmc_add_host(struct mmc_host *host) WARN_ON((host->caps & MMC_CAP_SDIO_IRQ) && !host->ops->enable_sdio_irq); - led_trigger_register_simple(dev_name(&host->class_dev), &host->led); - err = device_add(&host->class_dev); if (err) return err; + led_trigger_register_simple(dev_name(&host->class_dev), &host->led); + #ifdef CONFIG_DEBUG_FS mmc_add_host_debugfs(host); #endif diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 772d0d0a541..2a7e43bc796 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -20,6 +20,7 @@ #include "core.h" #include "bus.h" #include "mmc_ops.h" +#include "sd_ops.h" static const unsigned int tran_exp[] = { 10000, 100000, 1000000, 10000000, @@ -173,14 +174,17 @@ static int mmc_decode_csd(struct mmc_card *card) } /* - * Read and decode extended CSD. + * Read extended CSD. */ -static int mmc_read_ext_csd(struct mmc_card *card) +static int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd) { int err; u8 *ext_csd; BUG_ON(!card); + BUG_ON(!new_ext_csd); + + *new_ext_csd = NULL; if (card->csd.mmca_vsn < CSD_SPEC_VER_4) return 0; @@ -198,12 +202,15 @@ static int mmc_read_ext_csd(struct mmc_card *card) err = mmc_send_ext_csd(card, ext_csd); if (err) { + kfree(ext_csd); + *new_ext_csd = NULL; + /* If the host or the card can't do the switch, * fail more gracefully. */ if ((err != -EINVAL) && (err != -ENOSYS) && (err != -EFAULT)) - goto out; + return err; /* * High capacity cards should have this "magic" size @@ -221,9 +228,23 @@ static int mmc_read_ext_csd(struct mmc_card *card) mmc_hostname(card->host)); err = 0; } + } else + *new_ext_csd = ext_csd; - goto out; - } + return err; +} + +/* + * Decode extended CSD. + */ +static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) +{ + int err = 0; + + BUG_ON(!card); + + if (!ext_csd) + return 0; /* Version is coded in the CSD_STRUCTURE byte in the EXT_CSD register */ if (card->csd.structure == 3) { @@ -288,6 +309,10 @@ static int mmc_read_ext_csd(struct mmc_card *card) if (card->ext_csd.rev >= 3) { u8 sa_shift = ext_csd[EXT_CSD_S_A_TIMEOUT]; + card->ext_csd.part_config = ext_csd[EXT_CSD_PART_CONFIG]; + + /* EXT_CSD value is in units of 10ms, but we store in ms */ + card->ext_csd.part_time = 10 * ext_csd[EXT_CSD_PART_SWITCH_TIME]; /* Sleep / awake timeout in 100ns units */ if (sa_shift > 0 && sa_shift <= 0x17) @@ -299,6 +324,14 @@ static int mmc_read_ext_csd(struct mmc_card *card) ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT]; card->ext_csd.hc_erase_size = ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] << 10; + + card->ext_csd.rel_sectors = ext_csd[EXT_CSD_REL_WR_SEC_C]; + + /* + * There are two boot regions of equal size, defined in + * multiples of 128K. + */ + card->ext_csd.boot_size = ext_csd[EXT_CSD_BOOT_MULT] << 17; } if (card->ext_csd.rev >= 4) { @@ -350,14 +383,78 @@ static int mmc_read_ext_csd(struct mmc_card *card) ext_csd[EXT_CSD_TRIM_MULT]; } + if (card->ext_csd.rev >= 5) + card->ext_csd.rel_param = ext_csd[EXT_CSD_WR_REL_PARAM]; + if (ext_csd[EXT_CSD_ERASED_MEM_CONT]) card->erased_byte = 0xFF; else card->erased_byte = 0x0; out: + return err; +} + +static inline void mmc_free_ext_csd(u8 *ext_csd) +{ kfree(ext_csd); +} + + +static int mmc_compare_ext_csds(struct mmc_card *card, u8 *ext_csd, + unsigned bus_width) +{ + u8 *bw_ext_csd; + int err; + + err = mmc_get_ext_csd(card, &bw_ext_csd); + if (err) + return err; + + if ((ext_csd == NULL || bw_ext_csd == NULL)) { + if (bus_width != MMC_BUS_WIDTH_1) + err = -EINVAL; + goto out; + } + if (bus_width == MMC_BUS_WIDTH_1) + goto out; + + /* only compare read only fields */ + err = (!(ext_csd[EXT_CSD_PARTITION_SUPPORT] == + bw_ext_csd[EXT_CSD_PARTITION_SUPPORT]) && + (ext_csd[EXT_CSD_ERASED_MEM_CONT] == + bw_ext_csd[EXT_CSD_ERASED_MEM_CONT]) && + (ext_csd[EXT_CSD_REV] == + bw_ext_csd[EXT_CSD_REV]) && + (ext_csd[EXT_CSD_STRUCTURE] == + bw_ext_csd[EXT_CSD_STRUCTURE]) && + (ext_csd[EXT_CSD_CARD_TYPE] == + bw_ext_csd[EXT_CSD_CARD_TYPE]) && + (ext_csd[EXT_CSD_S_A_TIMEOUT] == + bw_ext_csd[EXT_CSD_S_A_TIMEOUT]) && + (ext_csd[EXT_CSD_HC_WP_GRP_SIZE] == + bw_ext_csd[EXT_CSD_HC_WP_GRP_SIZE]) && + (ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT] == + bw_ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT]) && + (ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] == + bw_ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]) && + (ext_csd[EXT_CSD_SEC_TRIM_MULT] == + bw_ext_csd[EXT_CSD_SEC_TRIM_MULT]) && + (ext_csd[EXT_CSD_SEC_ERASE_MULT] == + bw_ext_csd[EXT_CSD_SEC_ERASE_MULT]) && + (ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT] == + bw_ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT]) && + (ext_csd[EXT_CSD_TRIM_MULT] == + bw_ext_csd[EXT_CSD_TRIM_MULT]) && + memcmp(&ext_csd[EXT_CSD_SEC_CNT], + &bw_ext_csd[EXT_CSD_SEC_CNT], + 4) != 0); + if (err) + err = -EINVAL; + +out: + mmc_free_ext_csd(bw_ext_csd); return err; } @@ -422,6 +519,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, u32 cid[4]; unsigned int max_dtr; u32 rocr; + u8 *ext_csd = NULL; BUG_ON(!host); WARN_ON(!host->claimed); @@ -520,7 +618,11 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, /* * Fetch and process extended CSD. */ - err = mmc_read_ext_csd(card); + + err = mmc_get_ext_csd(card, &ext_csd); + if (err) + goto free_card; + err = mmc_read_ext_csd(card, ext_csd); if (err) goto free_card; @@ -542,7 +644,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, */ if (card->ext_csd.enhanced_area_en) { err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, - EXT_CSD_ERASE_GROUP_DEF, 1); + EXT_CSD_ERASE_GROUP_DEF, 1, 0); if (err && err != -EBADMSG) goto free_card; @@ -568,12 +670,24 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, } /* + * Ensure eMMC user default partition is enabled + */ + if (card->ext_csd.part_config & EXT_CSD_PART_CONFIG_ACC_MASK) { + card->ext_csd.part_config &= ~EXT_CSD_PART_CONFIG_ACC_MASK; + err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONFIG, + card->ext_csd.part_config, + card->ext_csd.part_time); + if (err && err != -EBADMSG) + goto free_card; + } + + /* * Activate high speed (if supported) */ if ((card->ext_csd.hs_max_dtr != 0) && (host->caps & MMC_CAP_MMC_HIGHSPEED)) { err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, - EXT_CSD_HS_TIMING, 1); + EXT_CSD_HS_TIMING, 1, 0); if (err && err != -EBADMSG) goto free_card; @@ -606,10 +720,14 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, */ if (mmc_card_highspeed(card)) { if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_8V) - && (host->caps & (MMC_CAP_1_8V_DDR))) + && ((host->caps & (MMC_CAP_1_8V_DDR | + MMC_CAP_UHS_DDR50)) + == (MMC_CAP_1_8V_DDR | MMC_CAP_UHS_DDR50))) ddr = MMC_1_8V_DDR_MODE; else if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_2V) - && (host->caps & (MMC_CAP_1_2V_DDR))) + && ((host->caps & (MMC_CAP_1_2V_DDR | + MMC_CAP_UHS_DDR50)) + == (MMC_CAP_1_2V_DDR | MMC_CAP_UHS_DDR50))) ddr = MMC_1_2V_DDR_MODE; } @@ -640,18 +758,22 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, ddr = 0; /* no DDR for 1-bit width */ err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH, - ext_csd_bits[idx][0]); + ext_csd_bits[idx][0], + 0); if (!err) { - mmc_set_bus_width_ddr(card->host, - bus_width, MMC_SDR_MODE); + mmc_set_bus_width(card->host, bus_width); + /* * If controller can't handle bus width test, - * use the highest bus width to maintain - * compatibility with previous MMC behavior. + * compare ext_csd previously read in 1 bit mode + * against ext_csd at new bus width */ if (!(host->caps & MMC_CAP_BUS_WIDTH_TEST)) - break; - err = mmc_bus_test(card, bus_width); + err = mmc_compare_ext_csds(card, + ext_csd, + bus_width); + else + err = mmc_bus_test(card, bus_width); if (!err) break; } @@ -659,8 +781,9 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, if (!err && ddr) { err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, - EXT_CSD_BUS_WIDTH, - ext_csd_bits[idx][1]); + EXT_CSD_BUS_WIDTH, + ext_csd_bits[idx][1], + 0); } if (err) { printk(KERN_WARNING "%s: switch to bus width %d ddr %d " @@ -668,20 +791,43 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, 1 << bus_width, ddr); goto free_card; } else if (ddr) { + /* + * eMMC cards can support 3.3V to 1.2V i/o (vccq) + * signaling. + * + * EXT_CSD_CARD_TYPE_DDR_1_8V means 3.3V or 1.8V vccq. + * + * 1.8V vccq at 3.3V core voltage (vcc) is not required + * in the JEDEC spec for DDR. + * + * Do not force change in vccq since we are obviously + * working and no change to vccq is needed. + * + * WARNING: eMMC rules are NOT the same as SD DDR + */ + if (ddr == EXT_CSD_CARD_TYPE_DDR_1_2V) { + err = mmc_set_signal_voltage(host, + MMC_SIGNAL_VOLTAGE_120, 0); + if (err) + goto err; + } mmc_card_set_ddr_mode(card); - mmc_set_bus_width_ddr(card->host, bus_width, ddr); + mmc_set_timing(card->host, MMC_TIMING_UHS_DDR50); + mmc_set_bus_width(card->host, bus_width); } } if (!oldcard) host->card = card; + mmc_free_ext_csd(ext_csd); return 0; free_card: if (!oldcard) mmc_remove_card(card); err: + mmc_free_ext_csd(ext_csd); return err; } diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c index f3b22bf89cc..845ce7c533b 100644 --- a/drivers/mmc/core/mmc_ops.c +++ b/drivers/mmc/core/mmc_ops.c @@ -23,12 +23,10 @@ static int _mmc_select_card(struct mmc_host *host, struct mmc_card *card) { int err; - struct mmc_command cmd; + struct mmc_command cmd = {0}; BUG_ON(!host); - memset(&cmd, 0, sizeof(struct mmc_command)); - cmd.opcode = MMC_SELECT_CARD; if (card) { @@ -60,15 +58,13 @@ int mmc_deselect_cards(struct mmc_host *host) int mmc_card_sleepawake(struct mmc_host *host, int sleep) { - struct mmc_command cmd; + struct mmc_command cmd = {0}; struct mmc_card *card = host->card; int err; if (sleep) mmc_deselect_cards(host); - memset(&cmd, 0, sizeof(struct mmc_command)); - cmd.opcode = MMC_SLEEP_AWAKE; cmd.arg = card->rca << 16; if (sleep) @@ -97,7 +93,7 @@ int mmc_card_sleepawake(struct mmc_host *host, int sleep) int mmc_go_idle(struct mmc_host *host) { int err; - struct mmc_command cmd; + struct mmc_command cmd = {0}; /* * Non-SPI hosts need to prevent chipselect going active during @@ -113,8 +109,6 @@ int mmc_go_idle(struct mmc_host *host) mmc_delay(1); } - memset(&cmd, 0, sizeof(struct mmc_command)); - cmd.opcode = MMC_GO_IDLE_STATE; cmd.arg = 0; cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_NONE | MMC_CMD_BC; @@ -135,13 +129,11 @@ int mmc_go_idle(struct mmc_host *host) int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) { - struct mmc_command cmd; + struct mmc_command cmd = {0}; int i, err = 0; BUG_ON(!host); - memset(&cmd, 0, sizeof(struct mmc_command)); - cmd.opcode = MMC_SEND_OP_COND; cmd.arg = mmc_host_is_spi(host) ? 0 : ocr; cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R3 | MMC_CMD_BCR; @@ -178,13 +170,11 @@ int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) int mmc_all_send_cid(struct mmc_host *host, u32 *cid) { int err; - struct mmc_command cmd; + struct mmc_command cmd = {0}; BUG_ON(!host); BUG_ON(!cid); - memset(&cmd, 0, sizeof(struct mmc_command)); - cmd.opcode = MMC_ALL_SEND_CID; cmd.arg = 0; cmd.flags = MMC_RSP_R2 | MMC_CMD_BCR; @@ -201,13 +191,11 @@ int mmc_all_send_cid(struct mmc_host *host, u32 *cid) int mmc_set_relative_addr(struct mmc_card *card) { int err; - struct mmc_command cmd; + struct mmc_command cmd = {0}; BUG_ON(!card); BUG_ON(!card->host); - memset(&cmd, 0, sizeof(struct mmc_command)); - cmd.opcode = MMC_SET_RELATIVE_ADDR; cmd.arg = card->rca << 16; cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; @@ -223,13 +211,11 @@ static int mmc_send_cxd_native(struct mmc_host *host, u32 arg, u32 *cxd, int opcode) { int err; - struct mmc_command cmd; + struct mmc_command cmd = {0}; BUG_ON(!host); BUG_ON(!cxd); - memset(&cmd, 0, sizeof(struct mmc_command)); - cmd.opcode = opcode; cmd.arg = arg; cmd.flags = MMC_RSP_R2 | MMC_CMD_AC; @@ -247,9 +233,9 @@ static int mmc_send_cxd_data(struct mmc_card *card, struct mmc_host *host, u32 opcode, void *buf, unsigned len) { - struct mmc_request mrq; - struct mmc_command cmd; - struct mmc_data data; + struct mmc_request mrq = {0}; + struct mmc_command cmd = {0}; + struct mmc_data data = {0}; struct scatterlist sg; void *data_buf; @@ -260,10 +246,6 @@ mmc_send_cxd_data(struct mmc_card *card, struct mmc_host *host, if (data_buf == NULL) return -ENOMEM; - memset(&mrq, 0, sizeof(struct mmc_request)); - memset(&cmd, 0, sizeof(struct mmc_command)); - memset(&data, 0, sizeof(struct mmc_data)); - mrq.cmd = &cmd; mrq.data = &data; @@ -355,11 +337,9 @@ int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd) int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp) { - struct mmc_command cmd; + struct mmc_command cmd = {0}; int err; - memset(&cmd, 0, sizeof(struct mmc_command)); - cmd.opcode = MMC_SPI_READ_OCR; cmd.arg = highcap ? (1 << 30) : 0; cmd.flags = MMC_RSP_SPI_R3; @@ -372,11 +352,9 @@ int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp) int mmc_spi_set_crc(struct mmc_host *host, int use_crc) { - struct mmc_command cmd; + struct mmc_command cmd = {0}; int err; - memset(&cmd, 0, sizeof(struct mmc_command)); - cmd.opcode = MMC_SPI_CRC_ON_OFF; cmd.flags = MMC_RSP_SPI_R1; cmd.arg = use_crc; @@ -387,23 +365,34 @@ int mmc_spi_set_crc(struct mmc_host *host, int use_crc) return err; } -int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value) +/** + * mmc_switch - modify EXT_CSD register + * @card: the MMC card associated with the data transfer + * @set: cmd set values + * @index: EXT_CSD register index + * @value: value to program into EXT_CSD register + * @timeout_ms: timeout (ms) for operation performed by register write, + * timeout of zero implies maximum possible timeout + * + * Modifies the EXT_CSD register for selected card. + */ +int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value, + unsigned int timeout_ms) { int err; - struct mmc_command cmd; + struct mmc_command cmd = {0}; u32 status; BUG_ON(!card); BUG_ON(!card->host); - memset(&cmd, 0, sizeof(struct mmc_command)); - cmd.opcode = MMC_SWITCH; cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | (index << 16) | (value << 8) | set; cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC; + cmd.cmd_timeout_ms = timeout_ms; err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES); if (err) @@ -433,17 +422,16 @@ int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value) return 0; } +EXPORT_SYMBOL_GPL(mmc_switch); int mmc_send_status(struct mmc_card *card, u32 *status) { int err; - struct mmc_command cmd; + struct mmc_command cmd = {0}; BUG_ON(!card); BUG_ON(!card->host); - memset(&cmd, 0, sizeof(struct mmc_command)); - cmd.opcode = MMC_SEND_STATUS; if (!mmc_host_is_spi(card->host)) cmd.arg = card->rca << 16; @@ -466,9 +454,9 @@ static int mmc_send_bus_test(struct mmc_card *card, struct mmc_host *host, u8 opcode, u8 len) { - struct mmc_request mrq; - struct mmc_command cmd; - struct mmc_data data; + struct mmc_request mrq = {0}; + struct mmc_command cmd = {0}; + struct mmc_data data = {0}; struct scatterlist sg; u8 *data_buf; u8 *test_buf; @@ -497,10 +485,6 @@ mmc_send_bus_test(struct mmc_card *card, struct mmc_host *host, u8 opcode, if (opcode == MMC_BUS_TEST_W) memcpy(data_buf, test_buf, len); - memset(&mrq, 0, sizeof(struct mmc_request)); - memset(&cmd, 0, sizeof(struct mmc_command)); - memset(&data, 0, sizeof(struct mmc_data)); - mrq.cmd = &cmd; mrq.data = &data; cmd.opcode = opcode; diff --git a/drivers/mmc/core/mmc_ops.h b/drivers/mmc/core/mmc_ops.h index e6d44b8a18d..9276946fa5b 100644 --- a/drivers/mmc/core/mmc_ops.h +++ b/drivers/mmc/core/mmc_ops.h @@ -20,7 +20,6 @@ int mmc_all_send_cid(struct mmc_host *host, u32 *cid); int mmc_set_relative_addr(struct mmc_card *card); int mmc_send_csd(struct mmc_card *card, u32 *csd); int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd); -int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value); int mmc_send_status(struct mmc_card *card, u32 *status); int mmc_send_cid(struct mmc_host *host, u32 *cid); int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp); diff --git a/drivers/mmc/core/quirks.c b/drivers/mmc/core/quirks.c index 11118b74eb2..3a596217029 100644 --- a/drivers/mmc/core/quirks.c +++ b/drivers/mmc/core/quirks.c @@ -1,7 +1,8 @@ /* - * This file contains work-arounds for many known sdio hardware - * bugs. + * This file contains work-arounds for many known SD/MMC + * and SDIO hardware bugs. * + * Copyright (c) 2011 Andrei Warkentin <andreiw@motorola.com> * Copyright (c) 2011 Pierre Tardy <tardyp@gmail.com> * Inspired from pci fixup code: * Copyright (c) 1999 Martin Mares <mj@ucw.cz> @@ -11,34 +12,14 @@ #include <linux/types.h> #include <linux/kernel.h> #include <linux/mmc/card.h> -#include <linux/mod_devicetable.h> -/* - * The world is not perfect and supplies us with broken mmc/sdio devices. - * For at least a part of these bugs we need a work-around - */ - -struct mmc_fixup { - u16 vendor, device; /* You can use SDIO_ANY_ID here of course */ - void (*vendor_fixup)(struct mmc_card *card, int data); - int data; -}; - -/* - * This hook just adds a quirk unconditionnally - */ -static void __maybe_unused add_quirk(struct mmc_card *card, int data) -{ - card->quirks |= data; -} +#ifndef SDIO_VENDOR_ID_TI +#define SDIO_VENDOR_ID_TI 0x0097 +#endif -/* - * This hook just removes a quirk unconditionnally - */ -static void __maybe_unused remove_quirk(struct mmc_card *card, int data) -{ - card->quirks &= ~data; -} +#ifndef SDIO_DEVICE_ID_TI_WL1271 +#define SDIO_DEVICE_ID_TI_WL1271 0x4076 +#endif /* * This hook just adds a quirk for all sdio devices @@ -49,33 +30,47 @@ static void add_quirk_for_sdio_devices(struct mmc_card *card, int data) card->quirks |= data; } -#ifndef SDIO_VENDOR_ID_TI -#define SDIO_VENDOR_ID_TI 0x0097 -#endif - -#ifndef SDIO_DEVICE_ID_TI_WL1271 -#define SDIO_DEVICE_ID_TI_WL1271 0x4076 -#endif - static const struct mmc_fixup mmc_fixup_methods[] = { /* by default sdio devices are considered CLK_GATING broken */ /* good cards will be whitelisted as they are tested */ - { SDIO_ANY_ID, SDIO_ANY_ID, - add_quirk_for_sdio_devices, MMC_QUIRK_BROKEN_CLK_GATING }, - { SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271 |