You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
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: (83 commits) mmc: fix compile error when CONFIG_BLOCK is not enabled mmc: core: Cleanup eMMC4.5 conditionals mmc: omap_hsmmc: if multiblock reads are broken, disable them mmc: core: add workaround for controllers with broken multiblock reads mmc: core: Prevent too long response times for suspend mmc: recognise SDIO cards with SDIO_CCCR_REV 3.00 mmc: sd: Handle SD3.0 cards not supporting UHS-I bus speed mode mmc: core: support HPI send command mmc: core: Add cache control for eMMC4.5 device mmc: core: Modify the timeout value for writing power class mmc: core: new discard feature support at eMMC v4.5 mmc: core: mmc sanitize feature support for v4.5 mmc: dw_mmc: modify DATA register offset mmc: sdhci-pci: add flag for devices that can support runtime PM mmc: omap_hsmmc: ensure pbias configuration is always done mmc: core: Add Power Off Notify Feature eMMC 4.5 mmc: sdhci-s3c: fix potential NULL dereference mmc: replace printk with appropriate display macro mmc: core: Add default timeout value for CMD6 mmc: sdhci-pci: add runtime pm support ...
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
* NVIDIA Tegra Secure Digital Host Controller
|
||||
|
||||
This controller on Tegra family SoCs provides an interface for MMC, SD,
|
||||
and SDIO types of memory cards.
|
||||
|
||||
Required properties:
|
||||
- compatible : Should be "nvidia,<chip>-sdhci"
|
||||
- reg : Should contain SD/MMC registers location and length
|
||||
- interrupts : Should contain SD/MMC interrupt
|
||||
|
||||
Optional properties:
|
||||
- cd-gpios : Specify GPIOs for card detection
|
||||
- wp-gpios : Specify GPIOs for write protection
|
||||
- power-gpios : Specify GPIOs for power control
|
||||
- support-8bit : Boolean, indicates if 8-bit mode should be used.
|
||||
|
||||
Example:
|
||||
|
||||
sdhci@c8000200 {
|
||||
compatible = "nvidia,tegra20-sdhci";
|
||||
reg = <0xc8000200 0x200>;
|
||||
interrupts = <47>;
|
||||
cd-gpios = <&gpio 69 0>; /* gpio PI5 */
|
||||
wp-gpios = <&gpio 57 0>; /* gpio PH1 */
|
||||
power-gpios = <&gpio 155 0>; /* gpio PT3 */
|
||||
support-8bit;
|
||||
};
|
||||
@@ -21,6 +21,11 @@ o fail_make_request
|
||||
/sys/block/<device>/make-it-fail or
|
||||
/sys/block/<device>/<partition>/make-it-fail. (generic_make_request())
|
||||
|
||||
o fail_mmc_request
|
||||
|
||||
injects MMC data errors on devices permitted by setting
|
||||
debugfs entries under /sys/kernel/debug/mmc0/fail_mmc_request
|
||||
|
||||
Configure fault-injection capabilities behavior
|
||||
-----------------------------------------------
|
||||
|
||||
@@ -115,7 +120,8 @@ use the boot option:
|
||||
|
||||
failslab=
|
||||
fail_page_alloc=
|
||||
fail_make_request=<interval>,<probability>,<space>,<times>
|
||||
fail_make_request=
|
||||
mmc_core.fail_request=<interval>,<probability>,<space>,<times>
|
||||
|
||||
How to add new fault injection capability
|
||||
-----------------------------------------
|
||||
|
||||
@@ -319,7 +319,7 @@ void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data)
|
||||
if (!data)
|
||||
return;
|
||||
|
||||
for (i = 0; i < ATMEL_MCI_MAX_NR_SLOTS; i++) {
|
||||
for (i = 0; i < ATMCI_MAX_NR_SLOTS; i++) {
|
||||
if (data->slot[i].bus_width) {
|
||||
/* input/irq */
|
||||
if (data->slot[i].detect_pin) {
|
||||
|
||||
@@ -175,12 +175,6 @@ static struct resource resources_sdc1[] = {
|
||||
.flags = IORESOURCE_IRQ,
|
||||
.name = "cmd_irq",
|
||||
},
|
||||
{
|
||||
.start = INT_SDC1_1,
|
||||
.end = INT_SDC1_1,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
.name = "pio_irq",
|
||||
},
|
||||
{
|
||||
.flags = IORESOURCE_IRQ | IORESOURCE_DISABLED,
|
||||
.name = "status_irq"
|
||||
@@ -203,12 +197,6 @@ static struct resource resources_sdc2[] = {
|
||||
.end = INT_SDC2_0,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
.name = "cmd_irq",
|
||||
},
|
||||
{
|
||||
.start = INT_SDC2_1,
|
||||
.end = INT_SDC2_1,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
.name = "pio_irq",
|
||||
},
|
||||
{
|
||||
.flags = IORESOURCE_IRQ | IORESOURCE_DISABLED,
|
||||
@@ -232,12 +220,6 @@ static struct resource resources_sdc3[] = {
|
||||
.end = INT_SDC3_0,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
.name = "cmd_irq",
|
||||
},
|
||||
{
|
||||
.start = INT_SDC3_1,
|
||||
.end = INT_SDC3_1,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
.name = "pio_irq",
|
||||
},
|
||||
{
|
||||
.flags = IORESOURCE_IRQ | IORESOURCE_DISABLED,
|
||||
@@ -261,12 +243,6 @@ static struct resource resources_sdc4[] = {
|
||||
.end = INT_SDC4_0,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
.name = "cmd_irq",
|
||||
},
|
||||
{
|
||||
.start = INT_SDC4_1,
|
||||
.end = INT_SDC4_1,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
.name = "pio_irq",
|
||||
},
|
||||
{
|
||||
.flags = IORESOURCE_IRQ | IORESOURCE_DISABLED,
|
||||
|
||||
@@ -139,12 +139,6 @@ static struct resource resources_sdc1[] = {
|
||||
.flags = IORESOURCE_IRQ,
|
||||
.name = "cmd_irq",
|
||||
},
|
||||
{
|
||||
.start = INT_SDC1_1,
|
||||
.end = INT_SDC1_1,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
.name = "pio_irq",
|
||||
},
|
||||
{
|
||||
.flags = IORESOURCE_IRQ | IORESOURCE_DISABLED,
|
||||
.name = "status_irq"
|
||||
@@ -167,12 +161,6 @@ static struct resource resources_sdc2[] = {
|
||||
.end = INT_SDC2_0,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
.name = "cmd_irq",
|
||||
},
|
||||
{
|
||||
.start = INT_SDC2_1,
|
||||
.end = INT_SDC2_1,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
.name = "pio_irq",
|
||||
},
|
||||
{
|
||||
.flags = IORESOURCE_IRQ | IORESOURCE_DISABLED,
|
||||
@@ -196,12 +184,6 @@ static struct resource resources_sdc3[] = {
|
||||
.end = INT_SDC3_0,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
.name = "cmd_irq",
|
||||
},
|
||||
{
|
||||
.start = INT_SDC3_1,
|
||||
.end = INT_SDC3_1,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
.name = "pio_irq",
|
||||
},
|
||||
{
|
||||
.flags = IORESOURCE_IRQ | IORESOURCE_DISABLED,
|
||||
@@ -225,12 +207,6 @@ static struct resource resources_sdc4[] = {
|
||||
.end = INT_SDC4_0,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
.name = "cmd_irq",
|
||||
},
|
||||
{
|
||||
.start = INT_SDC4_1,
|
||||
.end = INT_SDC4_1,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
.name = "pio_irq",
|
||||
},
|
||||
{
|
||||
.flags = IORESOURCE_IRQ | IORESOURCE_DISABLED,
|
||||
|
||||
@@ -8,13 +8,6 @@
|
||||
#include <linux/mmc/card.h>
|
||||
#include <linux/mmc/sdio_func.h>
|
||||
|
||||
struct embedded_sdio_data {
|
||||
struct sdio_cis cis;
|
||||
struct sdio_cccr cccr;
|
||||
struct sdio_embedded_func *funcs;
|
||||
int num_funcs;
|
||||
};
|
||||
|
||||
struct msm_mmc_gpio {
|
||||
unsigned no;
|
||||
const char *name;
|
||||
@@ -29,9 +22,9 @@ struct msm_mmc_platform_data {
|
||||
unsigned int ocr_mask; /* available voltages */
|
||||
u32 (*translate_vdd)(struct device *, unsigned int);
|
||||
unsigned int (*status)(struct device *);
|
||||
struct embedded_sdio_data *embedded_sdio;
|
||||
int (*register_status_notify)(void (*callback)(int card_present, void *dev_id), void *dev_id);
|
||||
struct msm_mmc_gpio_data *gpio_data;
|
||||
void (*init_card)(struct mmc_card *card);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -355,14 +355,17 @@ static struct resource sdhi0_resources[] = {
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
[1] = {
|
||||
.name = SH_MOBILE_SDHI_IRQ_CARD_DETECT,
|
||||
.start = gic_spi(83),
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
[2] = {
|
||||
.name = SH_MOBILE_SDHI_IRQ_SDCARD,
|
||||
.start = gic_spi(84),
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
[3] = {
|
||||
.name = SH_MOBILE_SDHI_IRQ_SDIO,
|
||||
.start = gic_spi(85),
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
@@ -398,14 +401,17 @@ static struct resource sdhi1_resources[] = {
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
[1] = {
|
||||
.name = SH_MOBILE_SDHI_IRQ_CARD_DETECT,
|
||||
.start = gic_spi(87),
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
[2] = {
|
||||
.name = SH_MOBILE_SDHI_IRQ_SDCARD,
|
||||
.start = gic_spi(88),
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
[3] = {
|
||||
.name = SH_MOBILE_SDHI_IRQ_SDIO,
|
||||
.start = gic_spi(89),
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
|
||||
@@ -1072,14 +1072,17 @@ static struct resource sdhi1_resources[] = {
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
[1] = {
|
||||
.name = SH_MOBILE_SDHI_IRQ_CARD_DETECT,
|
||||
.start = evt2irq(0x0e80), /* SDHI1_SDHI1I0 */
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
[2] = {
|
||||
.name = SH_MOBILE_SDHI_IRQ_SDCARD,
|
||||
.start = evt2irq(0x0ea0), /* SDHI1_SDHI1I1 */
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
[3] = {
|
||||
.name = SH_MOBILE_SDHI_IRQ_SDIO,
|
||||
.start = evt2irq(0x0ec0), /* SDHI1_SDHI1I2 */
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
@@ -1123,14 +1126,17 @@ static struct resource sdhi2_resources[] = {
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
[1] = {
|
||||
.name = SH_MOBILE_SDHI_IRQ_CARD_DETECT,
|
||||
.start = evt2irq(0x1200), /* SDHI2_SDHI2I0 */
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
[2] = {
|
||||
.name = SH_MOBILE_SDHI_IRQ_SDCARD,
|
||||
.start = evt2irq(0x1220), /* SDHI2_SDHI2I1 */
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
[3] = {
|
||||
.name = SH_MOBILE_SDHI_IRQ_SDIO,
|
||||
.start = evt2irq(0x1240), /* SDHI2_SDHI2I2 */
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
|
||||
@@ -31,7 +31,24 @@
|
||||
|
||||
#define OMAP_MMC_MAX_SLOTS 2
|
||||
|
||||
#define OMAP_HSMMC_SUPPORTS_DUAL_VOLT BIT(1)
|
||||
/*
|
||||
* struct omap_mmc_dev_attr.flags possibilities
|
||||
*
|
||||
* OMAP_HSMMC_SUPPORTS_DUAL_VOLT: Some HSMMC controller instances can
|
||||
* operate with either 1.8Vdc or 3.0Vdc card voltages; this flag
|
||||
* should be set if this is the case. See for example Section 22.5.3
|
||||
* "MMC/SD/SDIO1 Bus Voltage Selection" of the OMAP34xx Multimedia
|
||||
* Device Silicon Revision 3.1.x Revision ZR (July 2011) (SWPU223R).
|
||||
*
|
||||
* OMAP_HSMMC_BROKEN_MULTIBLOCK_READ: Multiple-block read transfers
|
||||
* don't work correctly on some MMC controller instances on some
|
||||
* OMAP3 SoCs; this flag should be set if this is the case. See
|
||||
* for example Advisory 2.1.1.128 "MMC: Multiple Block Read
|
||||
* Operation Issue" in _OMAP3530/3525/3515/3503 Silicon Errata_
|
||||
* Revision F (October 2010) (SPRZ278F).
|
||||
*/
|
||||
#define OMAP_HSMMC_SUPPORTS_DUAL_VOLT BIT(0)
|
||||
#define OMAP_HSMMC_BROKEN_MULTIBLOCK_READ BIT(1)
|
||||
|
||||
struct omap_mmc_dev_attr {
|
||||
u8 flags;
|
||||
|
||||
+212
-98
File diff suppressed because it is too large
Load Diff
+48
-17
@@ -22,6 +22,7 @@
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#define RESULT_OK 0
|
||||
#define RESULT_FAIL 1
|
||||
@@ -250,7 +251,7 @@ static int mmc_test_wait_busy(struct mmc_test_card *test)
|
||||
if (!busy && mmc_test_busy(&cmd)) {
|
||||
busy = 1;
|
||||
if (test->card->host->caps & MMC_CAP_WAIT_WHILE_BUSY)
|
||||
printk(KERN_INFO "%s: Warning: Host did not "
|
||||
pr_info("%s: Warning: Host did not "
|
||||
"wait for busy state to end.\n",
|
||||
mmc_hostname(test->card->host));
|
||||
}
|
||||
@@ -552,7 +553,7 @@ static void mmc_test_print_rate(struct mmc_test_card *test, uint64_t bytes,
|
||||
rate = mmc_test_rate(bytes, &ts);
|
||||
iops = mmc_test_rate(100, &ts); /* I/O ops per sec x 100 */
|
||||
|
||||
printk(KERN_INFO "%s: Transfer of %u sectors (%u%s KiB) took %lu.%09lu "
|
||||
pr_info("%s: Transfer of %u sectors (%u%s KiB) took %lu.%09lu "
|
||||
"seconds (%u kB/s, %u KiB/s, %u.%02u IOPS)\n",
|
||||
mmc_hostname(test->card->host), sectors, sectors >> 1,
|
||||
(sectors & 1 ? ".5" : ""), (unsigned long)ts.tv_sec,
|
||||
@@ -578,7 +579,7 @@ static void mmc_test_print_avg_rate(struct mmc_test_card *test, uint64_t bytes,
|
||||
rate = mmc_test_rate(tot, &ts);
|
||||
iops = mmc_test_rate(count * 100, &ts); /* I/O ops per sec x 100 */
|
||||
|
||||
printk(KERN_INFO "%s: Transfer of %u x %u sectors (%u x %u%s KiB) took "
|
||||
pr_info("%s: Transfer of %u x %u sectors (%u x %u%s KiB) took "
|
||||
"%lu.%09lu seconds (%u kB/s, %u KiB/s, "
|
||||
"%u.%02u IOPS, sg_len %d)\n",
|
||||
mmc_hostname(test->card->host), count, sectors, count,
|
||||
@@ -1408,7 +1409,7 @@ static int mmc_test_multi_read_high(struct mmc_test_card *test)
|
||||
|
||||
static int mmc_test_no_highmem(struct mmc_test_card *test)
|
||||
{
|
||||
printk(KERN_INFO "%s: Highmem not configured - test skipped\n",
|
||||
pr_info("%s: Highmem not configured - test skipped\n",
|
||||
mmc_hostname(test->card->host));
|
||||
return 0;
|
||||
}
|
||||
@@ -1435,7 +1436,7 @@ static int mmc_test_area_map(struct mmc_test_card *test, unsigned long sz,
|
||||
t->max_seg_sz, &t->sg_len, min_sg_len);
|
||||
}
|
||||
if (err)
|
||||
printk(KERN_INFO "%s: Failed to map sg list\n",
|
||||
pr_info("%s: Failed to map sg list\n",
|
||||
mmc_hostname(test->card->host));
|
||||
return err;
|
||||
}
|
||||
@@ -2135,7 +2136,7 @@ static int mmc_test_rw_multiple(struct mmc_test_card *test,
|
||||
|
||||
return ret;
|
||||
err:
|
||||
printk(KERN_INFO "[%s] error\n", __func__);
|
||||
pr_info("[%s] error\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -2149,7 +2150,7 @@ static int mmc_test_rw_multiple_size(struct mmc_test_card *test,
|
||||
|
||||
if (rw->do_nonblock_req &&
|
||||
((!pre_req && post_req) || (pre_req && !post_req))) {
|
||||
printk(KERN_INFO "error: only one of pre/post is defined\n");
|
||||
pr_info("error: only one of pre/post is defined\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -2328,6 +2329,31 @@ static int mmc_test_profile_sglen_r_nonblock_perf(struct mmc_test_card *test)
|
||||
return mmc_test_rw_multiple_sg_len(test, &test_data);
|
||||
}
|
||||
|
||||
/*
|
||||
* eMMC hardware reset.
|
||||
*/
|
||||
static int mmc_test_hw_reset(struct mmc_test_card *test)
|
||||
{
|
||||
struct mmc_card *card = test->card;
|
||||
struct mmc_host *host = card->host;
|
||||
int err;
|
||||
|
||||
err = mmc_hw_reset_check(host);
|
||||
if (!err)
|
||||
return RESULT_OK;
|
||||
|
||||
if (err == -ENOSYS)
|
||||
return RESULT_FAIL;
|
||||
|
||||
if (err != -EOPNOTSUPP)
|
||||
return err;
|
||||
|
||||
if (!mmc_can_reset(card))
|
||||
return RESULT_UNSUP_CARD;
|
||||
|
||||
return RESULT_UNSUP_HOST;
|
||||
}
|
||||
|
||||
static const struct mmc_test_case mmc_test_cases[] = {
|
||||
{
|
||||
.name = "Basic write (no data verification)",
|
||||
@@ -2650,6 +2676,11 @@ static const struct mmc_test_case mmc_test_cases[] = {
|
||||
.run = mmc_test_profile_sglen_r_nonblock_perf,
|
||||
.cleanup = mmc_test_area_cleanup,
|
||||
},
|
||||
|
||||
{
|
||||
.name = "eMMC hardware reset",
|
||||
.run = mmc_test_hw_reset,
|
||||
},
|
||||
};
|
||||
|
||||
static DEFINE_MUTEX(mmc_test_lock);
|
||||
@@ -2660,7 +2691,7 @@ static void mmc_test_run(struct mmc_test_card *test, int testcase)
|
||||
{
|
||||
int i, ret;
|
||||
|
||||
printk(KERN_INFO "%s: Starting tests of card %s...\n",
|
||||
pr_info("%s: Starting tests of card %s...\n",
|
||||
mmc_hostname(test->card->host), mmc_card_id(test->card));
|
||||
|
||||
mmc_claim_host(test->card->host);
|
||||
@@ -2671,14 +2702,14 @@ static void mmc_test_run(struct mmc_test_card *test, int testcase)
|
||||
if (testcase && ((i + 1) != testcase))
|
||||
continue;
|
||||
|
||||
printk(KERN_INFO "%s: Test case %d. %s...\n",
|
||||
pr_info("%s: Test case %d. %s...\n",
|
||||
mmc_hostname(test->card->host), i + 1,
|
||||
mmc_test_cases[i].name);
|
||||
|
||||
if (mmc_test_cases[i].prepare) {
|
||||
ret = mmc_test_cases[i].prepare(test);
|
||||
if (ret) {
|
||||
printk(KERN_INFO "%s: Result: Prepare "
|
||||
pr_info("%s: Result: Prepare "
|
||||
"stage failed! (%d)\n",
|
||||
mmc_hostname(test->card->host),
|
||||
ret);
|
||||
@@ -2708,25 +2739,25 @@ static void mmc_test_run(struct mmc_test_card *test, int testcase)
|
||||
ret = mmc_test_cases[i].run(test);
|
||||
switch (ret) {
|
||||
case RESULT_OK:
|
||||
printk(KERN_INFO "%s: Result: OK\n",
|
||||
pr_info("%s: Result: OK\n",
|
||||
mmc_hostname(test->card->host));
|
||||
break;
|
||||
case RESULT_FAIL:
|
||||
printk(KERN_INFO "%s: Result: FAILED\n",
|
||||
pr_info("%s: Result: FAILED\n",
|
||||
mmc_hostname(test->card->host));
|
||||
break;
|
||||
case RESULT_UNSUP_HOST:
|
||||
printk(KERN_INFO "%s: Result: UNSUPPORTED "
|
||||
pr_info("%s: Result: UNSUPPORTED "
|
||||
"(by host)\n",
|
||||
mmc_hostname(test->card->host));
|
||||
break;
|
||||
case RESULT_UNSUP_CARD:
|
||||
printk(KERN_INFO "%s: Result: UNSUPPORTED "
|
||||
pr_info("%s: Result: UNSUPPORTED "
|
||||
"(by card)\n",
|
||||
mmc_hostname(test->card->host));
|
||||
break;
|
||||
default:
|
||||
printk(KERN_INFO "%s: Result: ERROR (%d)\n",
|
||||
pr_info("%s: Result: ERROR (%d)\n",
|
||||
mmc_hostname(test->card->host), ret);
|
||||
}
|
||||
|
||||
@@ -2737,7 +2768,7 @@ static void mmc_test_run(struct mmc_test_card *test, int testcase)
|
||||
if (mmc_test_cases[i].cleanup) {
|
||||
ret = mmc_test_cases[i].cleanup(test);
|
||||
if (ret) {
|
||||
printk(KERN_INFO "%s: Warning: Cleanup "
|
||||
pr_info("%s: Warning: Cleanup "
|
||||
"stage failed! (%d)\n",
|
||||
mmc_hostname(test->card->host),
|
||||
ret);
|
||||
@@ -2747,7 +2778,7 @@ static void mmc_test_run(struct mmc_test_card *test, int testcase)
|
||||
|
||||
mmc_release_host(test->card->host);
|
||||
|
||||
printk(KERN_INFO "%s: Tests completed.\n",
|
||||
pr_info("%s: Tests completed.\n",
|
||||
mmc_hostname(test->card->host));
|
||||
}
|
||||
|
||||
|
||||
@@ -108,7 +108,7 @@ static void mmc_request(struct request_queue *q)
|
||||
wake_up_process(mq->thread);
|
||||
}
|
||||
|
||||
struct scatterlist *mmc_alloc_sg(int sg_len, int *err)
|
||||
static struct scatterlist *mmc_alloc_sg(int sg_len, int *err)
|
||||
{
|
||||
struct scatterlist *sg;
|
||||
|
||||
@@ -140,7 +140,7 @@ static void mmc_queue_setup_discard(struct request_queue *q,
|
||||
/* granularity must not be greater than max. discard */
|
||||
if (card->pref_erase > max_discard)
|
||||
q->limits.discard_granularity = 0;
|
||||
if (mmc_can_secure_erase_trim(card))
|
||||
if (mmc_can_secure_erase_trim(card) || mmc_can_sanitize(card))
|
||||
queue_flag_set_unlocked(QUEUE_FLAG_SECDISCARD, q);
|
||||
}
|
||||
|
||||
@@ -197,13 +197,13 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card,
|
||||
if (bouncesz > 512) {
|
||||
mqrq_cur->bounce_buf = kmalloc(bouncesz, GFP_KERNEL);
|
||||
if (!mqrq_cur->bounce_buf) {
|
||||
printk(KERN_WARNING "%s: unable to "
|
||||
pr_warning("%s: unable to "
|
||||
"allocate bounce cur buffer\n",
|
||||
mmc_card_name(card));
|
||||
}
|
||||
mqrq_prev->bounce_buf = kmalloc(bouncesz, GFP_KERNEL);
|
||||
if (!mqrq_prev->bounce_buf) {
|
||||
printk(KERN_WARNING "%s: unable to "
|
||||
pr_warning("%s: unable to "
|
||||
"allocate bounce prev buffer\n",
|
||||
mmc_card_name(card));
|
||||
kfree(mqrq_cur->bounce_buf);
|
||||
|
||||
@@ -1082,7 +1082,7 @@ static int sdio_uart_probe(struct sdio_func *func,
|
||||
return -ENOMEM;
|
||||
|
||||
if (func->class == SDIO_CLASS_UART) {
|
||||
printk(KERN_WARNING "%s: need info on UART class basic setup\n",
|
||||
pr_warning("%s: need info on UART class basic setup\n",
|
||||
sdio_func_id(func));
|
||||
kfree(port);
|
||||
return -ENOSYS;
|
||||
@@ -1101,23 +1101,23 @@ static int sdio_uart_probe(struct sdio_func *func,
|
||||
break;
|
||||
}
|
||||
if (!tpl) {
|
||||
printk(KERN_WARNING
|
||||
pr_warning(
|
||||
"%s: can't find tuple 0x91 subtuple 0 (SUBTPL_SIOREG) for GPS class\n",
|
||||
sdio_func_id(func));
|
||||
kfree(port);
|
||||
return -EINVAL;
|
||||
}
|
||||
printk(KERN_DEBUG "%s: Register ID = 0x%02x, Exp ID = 0x%02x\n",
|
||||
pr_debug("%s: Register ID = 0x%02x, Exp ID = 0x%02x\n",
|
||||
sdio_func_id(func), tpl->data[2], tpl->data[3]);
|
||||
port->regs_offset = (tpl->data[4] << 0) |
|
||||
(tpl->data[5] << 8) |
|
||||
(tpl->data[6] << 16);
|
||||
printk(KERN_DEBUG "%s: regs offset = 0x%x\n",
|
||||
pr_debug("%s: regs offset = 0x%x\n",
|
||||
sdio_func_id(func), port->regs_offset);
|
||||
port->uartclk = tpl->data[7] * 115200;
|
||||
if (port->uartclk == 0)
|
||||
port->uartclk = 115200;
|
||||
printk(KERN_DEBUG "%s: clk %d baudcode %u 4800-div %u\n",
|
||||
pr_debug("%s: clk %d baudcode %u 4800-div %u\n",
|
||||
sdio_func_id(func), port->uartclk,
|
||||
tpl->data[7], tpl->data[8] | (tpl->data[9] << 8));
|
||||
} else {
|
||||
|
||||
@@ -295,7 +295,7 @@ int mmc_add_card(struct mmc_card *card)
|
||||
}
|
||||
|
||||
if (mmc_host_is_spi(card->host)) {
|
||||
printk(KERN_INFO "%s: new %s%s%s card on SPI\n",
|
||||
pr_info("%s: new %s%s%s card on SPI\n",
|
||||
mmc_hostname(card->host),
|
||||
mmc_card_highspeed(card) ? "high speed " : "",
|
||||
mmc_card_ddr_mode(card) ? "DDR " : "",
|
||||
@@ -334,10 +334,10 @@ void mmc_remove_card(struct mmc_card *card)
|
||||
|
||||
if (mmc_card_present(card)) {
|
||||
if (mmc_host_is_spi(card->host)) {
|
||||
printk(KERN_INFO "%s: SPI card removed\n",
|
||||
pr_info("%s: SPI card removed\n",
|
||||
mmc_hostname(card->host));
|
||||
} else {
|
||||
printk(KERN_INFO "%s: card %04x removed\n",
|
||||
pr_info("%s: card %04x removed\n",
|
||||
mmc_hostname(card->host), card->rca);
|
||||
}
|
||||
device_del(&card->dev);
|
||||
|
||||
+387
-39
File diff suppressed because it is too large
Load Diff
@@ -43,6 +43,7 @@ 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);
|
||||
void mmc_power_off(struct mmc_host *host);
|
||||
|
||||
static inline void mmc_delay(unsigned int ms)
|
||||
{
|
||||
|
||||
@@ -7,11 +7,13 @@
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/stat.h>
|
||||
#include <linux/fault-inject.h>
|
||||
|
||||
#include <linux/mmc/card.h>
|
||||
#include <linux/mmc/host.h>
|
||||
@@ -19,6 +21,14 @@
|
||||
#include "core.h"
|
||||
#include "mmc_ops.h"
|
||||
|
||||
#ifdef CONFIG_FAIL_MMC_REQUEST
|
||||
|
||||
static DECLARE_FAULT_ATTR(fail_default_attr);
|
||||
static char *fail_request;
|
||||
module_param(fail_request, charp, 0);
|
||||
|
||||
#endif /* CONFIG_FAIL_MMC_REQUEST */
|
||||
|
||||
/* The debugfs functions are optimized away when CONFIG_DEBUG_FS isn't set. */
|
||||
static int mmc_ios_show(struct seq_file *s, void *data)
|
||||
{
|
||||
@@ -113,6 +123,15 @@ static int mmc_ios_show(struct seq_file *s, void *data)
|
||||
case MMC_TIMING_SD_HS:
|
||||
str = "sd high-speed";
|
||||
break;
|
||||
case MMC_TIMING_UHS_SDR50:
|
||||
str = "sd uhs SDR50";
|
||||
break;
|
||||
case MMC_TIMING_UHS_SDR104:
|
||||
str = "sd uhs SDR104";
|
||||
break;
|
||||
case MMC_TIMING_UHS_DDR50:
|
||||
str = "sd uhs DDR50";
|
||||
break;
|
||||
default:
|
||||
str = "invalid";
|
||||
break;
|
||||
@@ -187,6 +206,15 @@ void mmc_add_host_debugfs(struct mmc_host *host)
|
||||
if (!debugfs_create_u32("clk_delay", (S_IRUSR | S_IWUSR),
|
||||
root, &host->clk_delay))
|
||||
goto err_node;
|
||||
#endif
|
||||
#ifdef CONFIG_FAIL_MMC_REQUEST
|
||||
if (fail_request)
|
||||
setup_fault_attr(&fail_default_attr, fail_request);
|
||||
host->fail_mmc_request = fail_default_attr;
|
||||
if (IS_ERR(fault_create_debugfs_attr("fail_mmc_request",
|
||||
root,
|
||||
&host->fail_mmc_request)))
|
||||
goto err_node;
|
||||
#endif
|
||||
return;
|
||||
|
||||
|
||||
@@ -301,6 +301,17 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
|
||||
host->max_blk_size = 512;
|
||||
host->max_blk_count = PAGE_CACHE_SIZE / 512;
|
||||
|
||||
/*
|
||||
* Enable runtime power management by default. This flag was added due
|
||||
* to runtime power management causing disruption for some users, but
|
||||
* the power on/off code has been improved since then.
|
||||
*
|
||||
* We'll enable this flag by default as an experiment, and if no
|
||||
* problems are reported, we will follow up later and remove the flag
|
||||
* altogether.
|
||||
*/
|
||||
host->caps = MMC_CAP_POWER_OFF_CARD;
|
||||
|
||||
return host;
|
||||
|
||||
free:
|
||||
|
||||
+265
-24
@@ -101,7 +101,7 @@ static int mmc_decode_cid(struct mmc_card *card)
|
||||
break;
|
||||
|
||||
default:
|
||||
printk(KERN_ERR "%s: card has unknown MMCA version %d\n",
|
||||
pr_err("%s: card has unknown MMCA version %d\n",
|
||||
mmc_hostname(card->host), card->csd.mmca_vsn);
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -135,7 +135,7 @@ static int mmc_decode_csd(struct mmc_card *card)
|
||||
*/
|
||||
csd->structure = UNSTUFF_BITS(resp, 126, 2);
|
||||
if (csd->structure == 0) {
|
||||
printk(KERN_ERR "%s: unrecognised CSD structure version %d\n",
|
||||
pr_err("%s: unrecognised CSD structure version %d\n",
|
||||
mmc_hostname(card->host), csd->structure);
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -195,7 +195,7 @@ static int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd)
|
||||
*/
|
||||
ext_csd = kmalloc(512, GFP_KERNEL);
|
||||
if (!ext_csd) {
|
||||
printk(KERN_ERR "%s: could not allocate a buffer to "
|
||||
pr_err("%s: could not allocate a buffer to "
|
||||
"receive the ext_csd.\n", mmc_hostname(card->host));
|
||||
return -ENOMEM;
|
||||
}
|
||||
@@ -217,12 +217,12 @@ static int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd)
|
||||
* stored in their CSD.
|
||||
*/
|
||||
if (card->csd.capacity == (4096 * 512)) {
|
||||
printk(KERN_ERR "%s: unable to read EXT_CSD "
|
||||
pr_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 "
|
||||
pr_warning("%s: unable to read "
|
||||
"EXT_CSD, performance might "
|
||||
"suffer.\n",
|
||||
mmc_hostname(card->host));
|
||||
@@ -239,7 +239,9 @@ static int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd)
|
||||
*/
|
||||
static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
|
||||
{
|
||||
int err = 0;
|
||||
int err = 0, idx;
|
||||
unsigned int part_size;
|
||||
u8 hc_erase_grp_sz = 0, hc_wp_grp_sz = 0;
|
||||
|
||||
BUG_ON(!card);
|
||||
|
||||
@@ -250,7 +252,7 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
|
||||
card->ext_csd.raw_ext_csd_structure = ext_csd[EXT_CSD_STRUCTURE];
|
||||
if (card->csd.structure == 3) {
|
||||
if (card->ext_csd.raw_ext_csd_structure > 2) {
|
||||
printk(KERN_ERR "%s: unrecognised EXT_CSD structure "
|
||||
pr_err("%s: unrecognised EXT_CSD structure "
|
||||
"version %d\n", mmc_hostname(card->host),
|
||||
card->ext_csd.raw_ext_csd_structure);
|
||||
err = -EINVAL;
|
||||
@@ -260,7 +262,7 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
|
||||
|
||||
card->ext_csd.rev = ext_csd[EXT_CSD_REV];
|
||||
if (card->ext_csd.rev > 6) {
|
||||
printk(KERN_ERR "%s: unrecognised EXT_CSD revision %d\n",
|
||||
pr_err("%s: unrecognised EXT_CSD revision %d\n",
|
||||
mmc_hostname(card->host), card->ext_csd.rev);
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
@@ -306,7 +308,7 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
|
||||
break;
|
||||
default:
|
||||
/* MMC v4 spec says this cannot happen */
|
||||
printk(KERN_WARNING "%s: card is mmc v4 but doesn't "
|
||||
pr_warning("%s: card is mmc v4 but doesn't "
|
||||
"support any high-speed modes.\n",
|
||||
mmc_hostname(card->host));
|
||||
}
|
||||
@@ -340,7 +342,14 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
|
||||
* 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 (ext_csd[EXT_CSD_BOOT_MULT] && mmc_boot_partition_access(card->host)) {
|
||||
for (idx = 0; idx < MMC_NUM_BOOT_PARTITION; idx++) {
|
||||
part_size = ext_csd[EXT_CSD_BOOT_MULT] << 17;
|
||||
mmc_part_add(card, part_size,
|
||||
EXT_CSD_PART_CONFIG_ACC_BOOT0 + idx,
|
||||
"boot%d", idx, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
card->ext_csd.raw_hc_erase_gap_size =
|
||||
@@ -359,11 +368,12 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
|
||||
* card has the Enhanced area enabled. If so, export enhanced
|
||||
* area offset and size to user by adding sysfs interface.
|
||||
*/
|
||||
card->ext_csd.raw_partition_support = ext_csd[EXT_CSD_PARTITION_SUPPORT];
|
||||
if ((ext_csd[EXT_CSD_PARTITION_SUPPORT] & 0x2) &&
|
||||
(ext_csd[EXT_CSD_PARTITION_ATTRIBUTE] & 0x1)) {
|
||||
u8 hc_erase_grp_sz =
|
||||
hc_erase_grp_sz =
|
||||
ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
|
||||
u8 hc_wp_grp_sz =
|
||||
hc_wp_grp_sz =
|
||||
ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
|
||||
|
||||
card->ext_csd.enhanced_area_en = 1;
|
||||
@@ -392,6 +402,41 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
|
||||
card->ext_csd.enhanced_area_offset = -EINVAL;
|
||||
card->ext_csd.enhanced_area_size = -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* General purpose partition feature support --
|
||||
* If ext_csd has the size of general purpose partitions,
|
||||
* set size, part_cfg, partition name in mmc_part.
|
||||
*/
|
||||
if (ext_csd[EXT_CSD_PARTITION_SUPPORT] &
|
||||
EXT_CSD_PART_SUPPORT_PART_EN) {
|
||||
if (card->ext_csd.enhanced_area_en != 1) {
|
||||
hc_erase_grp_sz =
|
||||
ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
|
||||
hc_wp_grp_sz =
|
||||
ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
|
||||
|
||||
card->ext_csd.enhanced_area_en = 1;
|
||||
}
|
||||
|
||||
for (idx = 0; idx < MMC_NUM_GP_PARTITION; idx++) {
|
||||
if (!ext_csd[EXT_CSD_GP_SIZE_MULT + idx * 3] &&
|
||||
!ext_csd[EXT_CSD_GP_SIZE_MULT + idx * 3 + 1] &&
|
||||
!ext_csd[EXT_CSD_GP_SIZE_MULT + idx * 3 + 2])
|
||||
continue;
|
||||
part_size =
|
||||
(ext_csd[EXT_CSD_GP_SIZE_MULT + idx * 3 + 2]
|
||||
<< 16) +
|
||||
(ext_csd[EXT_CSD_GP_SIZE_MULT + idx * 3 + 1]
|
||||
<< 8) +
|
||||
ext_csd[EXT_CSD_GP_SIZE_MULT + idx * 3];
|
||||
part_size *= (size_t)(hc_erase_grp_sz *
|
||||
hc_wp_grp_sz);
|
||||
mmc_part_add(card, part_size << 19,
|
||||
EXT_CSD_PART_CONFIG_ACC_GP0 + idx,
|
||||
"gp%d", idx, false);
|
||||
}
|
||||
}
|
||||
card->ext_csd.sec_trim_mult =
|
||||
ext_csd[EXT_CSD_SEC_TRIM_MULT];
|
||||
card->ext_csd.sec_erase_mult =
|
||||
@@ -402,14 +447,48 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
|
||||
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 (card->ext_csd.rev >= 5) {
|
||||
/* check whether the eMMC card supports HPI */
|
||||
if (ext_csd[EXT_CSD_HPI_FEATURES] & 0x1) {
|
||||
card->ext_csd.hpi = 1;
|
||||
if (ext_csd[EXT_CSD_HPI_FEATURES] & 0x2)
|
||||
card->ext_csd.hpi_cmd = MMC_STOP_TRANSMISSION;
|
||||
else
|
||||
card->ext_csd.hpi_cmd = MMC_SEND_STATUS;
|
||||
/*
|
||||
* Indicate the maximum timeout to close
|
||||
* a command interrupted by HPI
|
||||
*/
|
||||
card->ext_csd.out_of_int_time =
|
||||
ext_csd[EXT_CSD_OUT_OF_INTERRUPT_TIME] * 10;
|
||||
}
|
||||
|
||||
card->ext_csd.rel_param = ext_csd[EXT_CSD_WR_REL_PARAM];
|
||||
card->ext_csd.rst_n_function = ext_csd[EXT_CSD_RST_N_FUNCTION];
|
||||
}
|
||||
|
||||
card->ext_csd.raw_erased_mem_count = ext_csd[EXT_CSD_ERASED_MEM_CONT];
|
||||
if (ext_csd[EXT_CSD_ERASED_MEM_CONT])
|
||||
card->erased_byte = 0xFF;
|
||||
else
|
||||
card->erased_byte = 0x0;
|
||||
|
||||
/* eMMC v4.5 or later */
|
||||
if (card->ext_csd.rev >= 6) {
|
||||
card->ext_csd.feature_support |= MMC_DISCARD_FEATURE;
|
||||
|
||||
card->ext_csd.generic_cmd6_time = 10 *
|
||||
ext_csd[EXT_CSD_GENERIC_CMD6_TIME];
|
||||
card->ext_csd.power_off_longtime = 10 *
|
||||
ext_csd[EXT_CSD_POWER_OFF_LONG_TIME];
|
||||
|
||||
card->ext_csd.cache_size =
|
||||
ext_csd[EXT_CSD_CACHE_SIZE + 0] << 0 |
|
||||
ext_csd[EXT_CSD_CACHE_SIZE + 1] << 8 |
|
||||
ext_csd[EXT_CSD_CACHE_SIZE + 2] << 16 |
|
||||
ext_csd[EXT_CSD_CACHE_SIZE + 3] << 24;
|
||||
}
|
||||
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
@@ -529,6 +608,86 @@ static struct device_type mmc_type = {
|
||||
.groups = mmc_attr_groups,
|
||||
};
|
||||
|
||||
/*
|
||||
* Select the PowerClass for the current bus width
|
||||
* If power class is defined for 4/8 bit bus in the
|
||||
* extended CSD register, select it by executing the
|
||||
* mmc_switch command.
|
||||
*/
|
||||
static int mmc_select_powerclass(struct mmc_card *card,
|
||||
unsigned int bus_width, u8 *ext_csd)
|
||||
{
|
||||
int err = 0;
|
||||
unsigned int pwrclass_val;
|
||||
unsigned int index = 0;
|
||||
struct mmc_host *host;
|
||||
|
||||
BUG_ON(!card);
|
||||
|
||||
host = card->host;
|
||||
BUG_ON(!host);
|
||||
|
||||
if (ext_csd == NULL)
|
||||
return 0;
|
||||
|
||||
/* Power class selection is supported for versions >= 4.0 */
|
||||
if (card->csd.mmca_vsn < CSD_SPEC_VER_4)
|
||||
return 0;
|
||||
|
||||
/* Power class values are defined only for 4/8 bit bus */
|
||||
if (bus_width == EXT_CSD_BUS_WIDTH_1)
|
||||
return 0;
|
||||
|
||||
switch (1 << host->ios.vdd) {
|
||||
case MMC_VDD_165_195:
|
||||
if (host->ios.clock <= 26000000)
|
||||
index = EXT_CSD_PWR_CL_26_195;
|
||||
else if (host->ios.clock <= 52000000)
|
||||
index = (bus_width <= EXT_CSD_BUS_WIDTH_8) ?
|
||||
EXT_CSD_PWR_CL_52_195 :
|
||||
EXT_CSD_PWR_CL_DDR_52_195;
|
||||
else if (host->ios.clock <= 200000000)
|
||||
index = EXT_CSD_PWR_CL_200_195;
|
||||
break;
|
||||
case MMC_VDD_32_33:
|
||||
case MMC_VDD_33_34:
|
||||
case MMC_VDD_34_35:
|
||||
case MMC_VDD_35_36:
|
||||
if (host->ios.clock <= 26000000)
|
||||
index = EXT_CSD_PWR_CL_26_360;
|
||||
else if (host->ios.clock <= 52000000)
|
||||
index = (bus_width <= EXT_CSD_BUS_WIDTH_8) ?
|
||||
EXT_CSD_PWR_CL_52_360 :
|
||||
EXT_CSD_PWR_CL_DDR_52_360;
|
||||
else if (host->ios.clock <= 200000000)
|
||||
index = EXT_CSD_PWR_CL_200_360;
|
||||
break;
|
||||
default:
|
||||
pr_warning("%s: Voltage range not supported "
|
||||
"for power class.\n", mmc_hostname(host));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
pwrclass_val = ext_csd[index];
|
||||
|
||||
if (bus_width & (EXT_CSD_BUS_WIDTH_8 | EXT_CSD_DDR_BUS_WIDTH_8))
|
||||
pwrclass_val = (pwrclass_val & EXT_CSD_PWR_CL_8BIT_MASK) >>
|
||||
EXT_CSD_PWR_CL_8BIT_SHIFT;
|
||||
else
|
||||
pwrclass_val = (pwrclass_val & EXT_CSD_PWR_CL_4BIT_MASK) >>
|
||||
EXT_CSD_PWR_CL_4BIT_SHIFT;
|
||||
|
||||
/* If the power class is different from the default value */
|
||||
if (pwrclass_val > 0) {
|
||||
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
|
||||
EXT_CSD_POWER_CLASS,
|
||||
pwrclass_val,
|
||||
card->ext_csd.generic_cmd6_time);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle the detection and initialisation of a card.
|
||||
*
|
||||
@@ -548,11 +707,16 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
|
||||
BUG_ON(!host);
|
||||
WARN_ON(!host->claimed);
|
||||
|
||||
/* Set correct bus mode for MMC before attempting init */
|
||||
if (!mmc_host_is_spi(host))
|
||||
mmc_set_bus_mode(host, MMC_BUSMODE_OPENDRAIN);
|
||||
|
||||
/*
|
||||
* 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 is needed for eMMC that are asleep
|
||||
*/
|
||||
mmc_go_idle(host);
|
||||
|
||||
@@ -668,7 +832,8 @@ 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, 0);
|
||||
EXT_CSD_ERASE_GROUP_DEF, 1,
|
||||
card->ext_csd.generic_cmd6_time);
|
||||
|
||||
if (err && err != -EBADMSG)
|
||||
goto free_card;
|
||||
@@ -705,18 +870,36 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
|
||||
goto free_card;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the host supports the power_off_notify capability then
|
||||
* set the notification byte in the ext_csd register of device
|
||||
*/
|
||||
if ((host->caps2 & MMC_CAP2_POWEROFF_NOTIFY) &&
|
||||
(card->poweroff_notify_state == MMC_NO_POWER_NOTIFICATION)) {
|
||||
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
|
||||
EXT_CSD_POWER_OFF_NOTIFICATION,
|
||||
EXT_CSD_POWER_ON,
|
||||
card->ext_csd.generic_cmd6_time);
|
||||
if (err && err != -EBADMSG)
|
||||
goto free_card;
|
||||
}
|
||||
|
||||
if (!err)
|
||||
card->poweroff_notify_state = MMC_POWERED_ON;
|
||||
|
||||
/*
|
||||
* 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, 0);
|
||||
EXT_CSD_HS_TIMING, 1,
|
||||
card->ext_csd.generic_cmd6_time);
|
||||
if (err && err != -EBADMSG)
|
||||
goto free_card;
|
||||
|
||||
if (err) {
|
||||
printk(KERN_WARNING "%s: switch to highspeed failed\n",
|
||||
pr_warning("%s: switch to highspeed failed\n",
|
||||
mmc_hostname(card->host));
|
||||
err = 0;
|
||||
} else {
|
||||
@@ -725,6 +908,22 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Enable HPI feature (if supported)
|
||||
*/
|
||||
if (card->ext_csd.hpi) {
|
||||
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
|
||||
EXT_CSD_HPI_MGMT, 1, 0);
|
||||
if (err && err != -EBADMSG)
|
||||
goto free_card;
|
||||
if (err) {
|
||||
pr_warning("%s: Enabling HPI failed\n",
|
||||
mmc_hostname(card->host));
|
||||
err = 0;
|
||||
} else
|
||||
card->ext_csd.hpi_en = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compute bus speed.
|
||||
*/
|
||||
@@ -780,10 +979,18 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
|
||||
bus_width = bus_widths[idx];
|
||||
if (bus_width == MMC_BUS_WIDTH_1)
|
||||
ddr = 0; /* no DDR for 1-bit width */
|
||||
err = mmc_select_powerclass(card, ext_csd_bits[idx][0],
|
||||
ext_csd);
|
||||
if (err)
|
||||
pr_err("%s: power class selection to "
|
||||
"bus width %d failed\n",
|
||||
mmc_hostname(card->host),
|
||||
1 << bus_width);
|
||||
|
||||
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
|
||||
EXT_CSD_BUS_WIDTH,
|
||||
ext_csd_bits[idx][0],
|
||||
0);
|
||||
card->ext_csd.generic_cmd6_time);
|
||||
if (!err) {
|
||||
mmc_set_bus_width(card->host, bus_width);
|
||||
|
||||
@@ -803,13 +1010,21 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
|
||||
}
|
||||
|
||||
if (!err && ddr) {
|
||||
err = mmc_select_powerclass(card, ext_csd_bits[idx][1],
|
||||
ext_csd);
|
||||
if (err)
|
||||
pr_err("%s: power class selection to "
|
||||
"bus width %d ddr %d failed\n",
|
||||
mmc_hostname(card->host),
|
||||
1 << bus_width, ddr);
|
||||
|
||||
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
|
||||
EXT_CSD_BUS_WIDTH,
|
||||
ext_csd_bits[idx][1],
|
||||
0);
|
||||
card->ext_csd.generic_cmd6_time);
|
||||
}
|
||||
if (err) {
|
||||
printk(KERN_WARNING "%s: switch to bus width %d ddr %d "
|
||||
pr_warning("%s: switch to bus width %d ddr %d "
|
||||
"failed\n", mmc_hostname(card->host),
|
||||
1 << bus_width, ddr);
|
||||
goto free_card;
|
||||
@@ -840,6 +1055,23 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If cache size is higher than 0, this indicates
|
||||
* the existence of cache and it can be turned on.
|
||||
*/
|
||||
if ((host->caps2 & MMC_CAP2_CACHE_CTRL) &&
|
||||
card->ext_csd.cache_size > 0) {
|
||||
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
|
||||
EXT_CSD_CACHE_CTRL, 1, 0);
|
||||
if (err && err != -EBADMSG)
|
||||
goto free_card;
|
||||
|
||||
/*
|
||||
* Only if no error, cache is turned on successfully.
|
||||
*/
|
||||
card->ext_csd.cache_ctrl = err ? 0 : 1;
|
||||
}
|
||||
|
||||
if (!oldcard)
|
||||
host->card = card;
|
||||
|
||||
@@ -891,6 +1123,7 @@ static void mmc_detect(struct mmc_host *host)
|
||||
|
||||
mmc_claim_host(host);
|
||||
mmc_detach_bus(host);
|
||||
mmc_power_off(host);
|
||||
mmc_release_host(host);
|
||||
}
|
||||
}
|
||||
@@ -900,16 +1133,20 @@ static void mmc_detect(struct mmc_host *host)
|
||||
*/
|
||||
static int mmc_suspend(struct mmc_host *host)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
BUG_ON(!host);
|
||||
BUG_ON(!host->card);
|
||||
|
||||
mmc_claim_host(host);
|
||||
if (!mmc_host_is_spi(host))
|
||||
if (mmc_card_can_sleep(host))
|
||||
err = mmc_card_sleep(host);
|
||||
else if (!mmc_host_is_spi(host))
|
||||
mmc_deselect_cards(host);
|
||||
host->card->state &= ~MMC_STATE_HIGHSPEED;
|
||||
mmc_release_host(host);
|
||||
|
||||
return 0;
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1016,6 +1253,10 @@ int mmc_attach_mmc(struct mmc_host *host)
|
||||
BUG_ON(!host);
|
||||
WARN_ON(!host->claimed);
|
||||
|
||||
/* Set correct bus mode for MMC before attempting attach */
|
||||
if (!mmc_host_is_spi(host))
|
||||
mmc_set_bus_mode(host, MMC_BUSMODE_OPENDRAIN);
|
||||
|
||||
err = mmc_send_op_cond(host, 0, &ocr);
|
||||
if (err)
|
||||
return err;
|
||||
@@ -1038,7 +1279,7 @@ int mmc_attach_mmc(struct mmc_host *host)
|
||||
* support.
|
||||
*/
|
||||
if (ocr & 0x7F) {
|
||||
printk(KERN_WARNING "%s: card claims to support voltages "
|
||||
pr_warning("%s: card claims to support voltages "
|
||||
"below the defined range. These will be ignored.\n",
|
||||
mmc_hostname(host));
|
||||
ocr &= ~0x7F;
|
||||
@@ -1077,7 +1318,7 @@ remove_card:
|
||||
err:
|
||||
mmc_detach_bus(host);
|
||||
|
||||
printk(KERN_ERR "%s: error %d whilst initialising MMC card\n",
|
||||
pr_err("%s: error %d whilst initialising MMC card\n",
|
||||
mmc_hostname(host), err);
|
||||
|
||||
return err;
|
||||
|
||||
@@ -233,7 +233,7 @@ static int
|
||||
mmc_send_cxd_data(struct mmc_card *card, struct mmc_host *host,
|
||||
u32 opcode, void *buf, unsigned len)
|
||||
{
|
||||
struct mmc_request mrq = {0};
|
||||
struct mmc_request mrq = {NULL};
|
||||
struct mmc_command cmd = {0};
|
||||
struct mmc_data data = {0};
|
||||
struct scatterlist sg;
|
||||
@@ -414,7 +414,7 @@ int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
|
||||
return -EBADMSG;
|
||||
} else {
|
||||
if (status & 0xFDFFA000)
|
||||
printk(KERN_WARNING "%s: unexpected status %#x after "
|
||||
pr_warning("%s: unexpected status %#x after "
|
||||
"switch", mmc_hostname(card->host), status);
|
||||
if (status & R1_SWITCH_ERROR)
|
||||
return -EBADMSG;
|
||||
@@ -454,7 +454,7 @@ static int
|
||||
mmc_send_bus_test(struct mmc_card *card, struct mmc_host *host, u8 opcode,
|
||||
u8 len)
|
||||
{
|
||||
struct mmc_request mrq = {0};
|
||||
struct mmc_request mrq = {NULL};
|
||||
struct mmc_command cmd = {0};
|
||||
struct mmc_data data = {0};
|
||||
struct scatterlist sg;
|
||||
@@ -476,7 +476,7 @@ mmc_send_bus_test(struct mmc_card *card, struct mmc_host *host, u8 opcode,
|
||||
else if (len == 4)
|
||||
test_buf = testdata_4bit;
|
||||
else {
|
||||
printk(KERN_ERR "%s: Invalid bus_width %d\n",
|
||||
pr_err("%s: Invalid bus_width %d\n",
|
||||
mmc_hostname(host), len);
|
||||
kfree(data_buf);
|
||||
return -EINVAL;
|
||||
@@ -547,3 +547,34 @@ int mmc_bus_test(struct mmc_card *card, u8 bus_width)
|
||||
err = mmc_send_bus_test(card, card->host, MMC_BUS_TEST_R, width);
|
||||
return err;
|
||||
}
|
||||
|
||||
int mmc_send_hpi_cmd(struct mmc_card *card, u32 *status)
|
||||
{
|
||||
struct mmc_command cmd = {0};
|
||||
unsigned int opcode;
|
||||
unsigned int flags;
|
||||
int err;
|
||||
|
||||
opcode = card->ext_csd.hpi_cmd;
|
||||
if (opcode == MMC_STOP_TRANSMISSION)
|
||||
flags = MMC_RSP_R1 | MMC_CMD_AC;
|
||||
else if (opcode == MMC_SEND_STATUS)
|
||||
flags = MMC_RSP_R1 | MMC_CMD_AC;
|
||||
|
||||
cmd.opcode = opcode;
|
||||
cmd.arg = card->rca << 16 | 1;
|
||||
cmd.flags = flags;
|
||||
cmd.cmd_timeout_ms = card->ext_csd.out_of_int_time;
|
||||
|
||||
err = mmc_wait_for_cmd(card->host, &cmd, 0);
|
||||
if (err) {
|
||||
pr_warn("%s: error %d interrupting operation. "
|
||||
"HPI command response %#x\n", mmc_hostname(card->host),
|
||||
err, cmd.resp[0]);
|
||||
return err;
|
||||
}
|
||||
if (status)
|
||||
*status = cmd.resp[0];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user