summaryrefslogtreecommitdiffstats
path: root/drivers/mmc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mmc')
-rw-r--r--drivers/mmc/card/block.c21
-rw-r--r--drivers/mmc/card/queue.c6
-rw-r--r--drivers/mmc/card/sdio_uart.c9
-rw-r--r--drivers/mmc/core/core.c48
-rw-r--r--drivers/mmc/core/host.c96
-rw-r--r--drivers/mmc/core/mmc.c263
-rw-r--r--drivers/mmc/core/mmc_ops.c24
-rw-r--r--drivers/mmc/core/mmc_ops.h1
-rw-r--r--drivers/mmc/core/sd.c41
-rw-r--r--drivers/mmc/core/sdio.c19
-rw-r--r--drivers/mmc/core/sdio_bus.c4
-rw-r--r--drivers/mmc/core/sdio_irq.c11
-rw-r--r--drivers/mmc/core/slot-gpio.c70
-rw-r--r--drivers/mmc/host/Kconfig23
-rw-r--r--drivers/mmc/host/Makefile2
-rw-r--r--drivers/mmc/host/atmel-mci.c55
-rw-r--r--drivers/mmc/host/au1xmmc.c5
-rw-r--r--drivers/mmc/host/dw_mmc-pci.c3
-rw-r--r--drivers/mmc/host/dw_mmc-pltfm.c10
-rw-r--r--drivers/mmc/host/dw_mmc-rockchip.c136
-rw-r--r--drivers/mmc/host/dw_mmc.c297
-rw-r--r--drivers/mmc/host/dw_mmc.h5
-rw-r--r--drivers/mmc/host/jz4740_mmc.c269
-rw-r--r--drivers/mmc/host/mmc_spi.c1
-rw-r--r--drivers/mmc/host/mmci.c115
-rw-r--r--drivers/mmc/host/mmci_qcom_dml.c177
-rw-r--r--drivers/mmc/host/mmci_qcom_dml.h31
-rw-r--r--drivers/mmc/host/moxart-mmc.c1
-rw-r--r--drivers/mmc/host/mxcmmc.c1
-rw-r--r--drivers/mmc/host/mxs-mmc.c1
-rw-r--r--drivers/mmc/host/omap.c1
-rw-r--r--drivers/mmc/host/omap_hsmmc.c15
-rw-r--r--drivers/mmc/host/pxamci.c5
-rw-r--r--drivers/mmc/host/rtsx_pci_sdmmc.c9
-rw-r--r--drivers/mmc/host/rtsx_usb_sdmmc.c9
-rw-r--r--drivers/mmc/host/s3cmci.c4
-rw-r--r--drivers/mmc/host/sdhci-acpi.c111
-rw-r--r--drivers/mmc/host/sdhci-bcm-kona.c3
-rw-r--r--drivers/mmc/host/sdhci-bcm2835.c1
-rw-r--r--drivers/mmc/host/sdhci-cns3xxx.c1
-rw-r--r--drivers/mmc/host/sdhci-dove.c1
-rw-r--r--drivers/mmc/host/sdhci-esdhc-imx.c21
-rw-r--r--drivers/mmc/host/sdhci-msm.c27
-rw-r--r--drivers/mmc/host/sdhci-of-arasan.c1
-rw-r--r--drivers/mmc/host/sdhci-of-esdhc.c1
-rw-r--r--drivers/mmc/host/sdhci-of-hlwd.c1
-rw-r--r--drivers/mmc/host/sdhci-pci.c70
-rw-r--r--drivers/mmc/host/sdhci-pci.h7
-rw-r--r--drivers/mmc/host/sdhci-pltfm.c10
-rw-r--r--drivers/mmc/host/sdhci-pxav2.c1
-rw-r--r--drivers/mmc/host/sdhci-pxav3.c8
-rw-r--r--drivers/mmc/host/sdhci-s3c.c5
-rw-r--r--drivers/mmc/host/sdhci-sirf.c26
-rw-r--r--drivers/mmc/host/sdhci-spear.c1
-rw-r--r--drivers/mmc/host/sdhci-tegra.c1
-rw-r--r--drivers/mmc/host/sdhci.c155
-rw-r--r--drivers/mmc/host/sdhci.h4
-rw-r--r--drivers/mmc/host/sh_mmcif.c1
-rw-r--r--drivers/mmc/host/sh_mobile_sdhi.c53
-rw-r--r--drivers/mmc/host/sunxi-mmc.c4
-rw-r--r--drivers/mmc/host/tifm_sd.c4
-rw-r--r--drivers/mmc/host/tmio_mmc.c7
-rw-r--r--drivers/mmc/host/tmio_mmc.h31
-rw-r--r--drivers/mmc/host/tmio_mmc_dma.c8
-rw-r--r--drivers/mmc/host/tmio_mmc_pio.c294
-rw-r--r--drivers/mmc/host/wbsd.c21
66 files changed, 1934 insertions, 733 deletions
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index ede41f05c392..1fa4c80ff886 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -977,7 +977,7 @@ static int mmc_blk_cmd_recovery(struct mmc_card *card, struct request *req,
return ERR_CONTINUE;
/* Now for stop errors. These aren't fatal to the transfer. */
- pr_err("%s: error %d sending stop command, original cmd response %#x, card status %#x\n",
+ pr_info("%s: error %d sending stop command, original cmd response %#x, card status %#x\n",
req->rq_disk->disk_name, brq->stop.error,
brq->cmd.resp[0], status);
@@ -1398,10 +1398,15 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,
if (disable_multi)
brq->data.blocks = 1;
- /* Some controllers can't do multiblock reads due to hw bugs */
- if (card->host->caps2 & MMC_CAP2_NO_MULTI_READ &&
- rq_data_dir(req) == READ)
- brq->data.blocks = 1;
+ /*
+ * Some controllers have HW issues while operating
+ * in multiple I/O mode
+ */
+ if (card->host->ops->multi_io_quirk)
+ brq->data.blocks = card->host->ops->multi_io_quirk(card,
+ (rq_data_dir(req) == READ) ?
+ MMC_DATA_READ : MMC_DATA_WRITE,
+ brq->data.blocks);
}
if (brq->data.blocks > 1 || do_rel_wr) {
@@ -1923,8 +1928,8 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
case MMC_BLK_ECC_ERR:
if (brq->data.blocks > 1) {
/* Redo read one sector at a time */
- pr_warning("%s: retrying using single block read\n",
- req->rq_disk->disk_name);
+ pr_warn("%s: retrying using single block read\n",
+ req->rq_disk->disk_name);
disable_multi = 1;
break;
}
@@ -2131,7 +2136,7 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card,
md->disk->queue = md->queue.queue;
md->disk->driverfs_dev = parent;
set_disk_ro(md->disk, md->read_only || default_ro);
- if (area_type & MMC_BLK_DATA_AREA_RPMB)
+ if (area_type & (MMC_BLK_DATA_AREA_RPMB | MMC_BLK_DATA_AREA_BOOT))
md->disk->flags |= GENHD_FL_NO_PART_SCAN;
/*
diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
index 3e049c13429c..feea926e32f8 100644
--- a/drivers/mmc/card/queue.c
+++ b/drivers/mmc/card/queue.c
@@ -229,14 +229,12 @@ 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) {
- pr_warning("%s: unable to "
- "allocate bounce cur buffer\n",
+ pr_warn("%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) {
- pr_warning("%s: unable to "
- "allocate bounce prev buffer\n",
+ pr_warn("%s: unable to allocate bounce prev buffer\n",
mmc_card_name(card));
kfree(mqrq_cur->bounce_buf);
mqrq_cur->bounce_buf = NULL;
diff --git a/drivers/mmc/card/sdio_uart.c b/drivers/mmc/card/sdio_uart.c
index f093cea0d060..d2de5925b73e 100644
--- a/drivers/mmc/card/sdio_uart.c
+++ b/drivers/mmc/card/sdio_uart.c
@@ -1063,8 +1063,8 @@ static int sdio_uart_probe(struct sdio_func *func,
return -ENOMEM;
if (func->class == SDIO_CLASS_UART) {
- pr_warning("%s: need info on UART class basic setup\n",
- sdio_func_id(func));
+ pr_warn("%s: need info on UART class basic setup\n",
+ sdio_func_id(func));
kfree(port);
return -ENOSYS;
} else if (func->class == SDIO_CLASS_GPS) {
@@ -1082,9 +1082,8 @@ static int sdio_uart_probe(struct sdio_func *func,
break;
}
if (!tpl) {
- pr_warning(
- "%s: can't find tuple 0x91 subtuple 0 (SUBTPL_SIOREG) for GPS class\n",
- sdio_func_id(func));
+ pr_warn("%s: can't find tuple 0x91 subtuple 0 (SUBTPL_SIOREG) for GPS class\n",
+ sdio_func_id(func));
kfree(port);
return -EINVAL;
}
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index d03a080fb9cd..f26a5f1d926d 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -433,8 +433,8 @@ static void mmc_wait_for_req_done(struct mmc_host *host,
*/
if (cmd->sanitize_busy && cmd->error == -ETIMEDOUT) {
if (!mmc_interrupt_hpi(host->card)) {
- pr_warning("%s: %s: Interrupted sanitize\n",
- mmc_hostname(host), __func__);
+ pr_warn("%s: %s: Interrupted sanitize\n",
+ mmc_hostname(host), __func__);
cmd->error = 0;
break;
} else {
@@ -995,7 +995,7 @@ void mmc_set_chip_select(struct mmc_host *host, int mode)
*/
static void __mmc_set_clock(struct mmc_host *host, unsigned int hz)
{
- WARN_ON(hz < host->f_min);
+ WARN_ON(hz && hz < host->f_min);
if (hz > host->f_max)
hz = host->f_max;
@@ -1221,15 +1221,14 @@ int mmc_regulator_get_ocrmask(struct regulator *supply)
int result = 0;
int count;
int i;
+ int vdd_uV;
+ int vdd_mV;
count = regulator_count_voltages(supply);
if (count < 0)
return count;
for (i = 0; i < count; i++) {
- int vdd_uV;
- int vdd_mV;
-
vdd_uV = regulator_list_voltage(supply, i);
if (vdd_uV <= 0)
continue;
@@ -1238,6 +1237,15 @@ int mmc_regulator_get_ocrmask(struct regulator *supply)
result |= mmc_vddrange_to_ocrmask(vdd_mV, vdd_mV);
}
+ if (!result) {
+ vdd_uV = regulator_get_voltage(supply);
+ if (vdd_uV <= 0)
+ return vdd_uV;
+
+ vdd_mV = vdd_uV / 1000;
+ result = mmc_vddrange_to_ocrmask(vdd_mV, vdd_mV);
+ }
+
return result;
}
EXPORT_SYMBOL_GPL(mmc_regulator_get_ocrmask);
@@ -1263,7 +1271,6 @@ int mmc_regulator_set_ocr(struct mmc_host *mmc,
if (vdd_bit) {
int tmp;
- int voltage;
/*
* REVISIT mmc_vddrange_to_ocrmask() may have set some
@@ -1280,22 +1287,7 @@ int mmc_regulator_set_ocr(struct mmc_host *mmc,
max_uV = min_uV + 100 * 1000;
}
- /*
- * If we're using a fixed/static regulator, don't call
- * regulator_set_voltage; it would fail.
- */
- voltage = regulator_get_voltage(supply);
-
- if (!regulator_can_change_voltage(supply))
- min_uV = max_uV = voltage;
-
- if (voltage < 0)
- result = voltage;
- else if (voltage < min_uV || voltage > max_uV)
- result = regulator_set_voltage(supply, min_uV, max_uV);
- else
- result = 0;
-
+ result = regulator_set_voltage(supply, min_uV, max_uV);
if (result == 0 && !mmc->regulator_enabled) {
result = regulator_enable(supply);
if (!result)
@@ -1425,8 +1417,8 @@ int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage, u32 ocr)
if (!host->ops->start_signal_voltage_switch)
return -EPERM;
if (!host->ops->card_busy)
- pr_warning("%s: cannot verify signal voltage switch\n",
- mmc_hostname(host));
+ pr_warn("%s: cannot verify signal voltage switch\n",
+ mmc_hostname(host));
cmd.opcode = SD_SWITCH_VOLTAGE;
cmd.arg = 0;
@@ -1761,7 +1753,7 @@ void mmc_init_erase(struct mmc_card *card)
card->erase_shift = ffs(card->ssr.au) - 1;
} else if (card->ext_csd.hc_erase_size) {
card->pref_erase = card->ext_csd.hc_erase_size;
- } else {
+ } else if (card->erase_size) {
sz = (card->csd.capacity << (card->csd.read_blkbits - 9)) >> 11;
if (sz < 128)
card->pref_erase = 512 * 1024 / 512;
@@ -1778,7 +1770,8 @@ void mmc_init_erase(struct mmc_card *card)
if (sz)
card->pref_erase += card->erase_size - sz;
}
- }
+ } else
+ card->pref_erase = 0;
}
static unsigned int mmc_mmc_erase_timeout(struct mmc_card *card,
@@ -2489,6 +2482,7 @@ void mmc_start_host(struct mmc_host *host)
{
host->f_init = max(freqs[0], host->f_min);
host->rescan_disable = 0;
+ host->ios.power_mode = MMC_POWER_UNDEFINED;
if (host->caps2 & MMC_CAP2_NO_PRESCAN_POWERUP)
mmc_power_off(host);
else
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index 95cceae96944..03c53b72a2d6 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -310,9 +310,8 @@ int mmc_of_parse(struct mmc_host *host)
{
struct device_node *np;
u32 bus_width;
- bool explicit_inv_wp, gpio_inv_wp = false;
- enum of_gpio_flags flags;
- int len, ret, gpio;
+ int len, ret;
+ bool cap_invert, gpio_invert;
if (!host->parent || !host->parent->of_node)
return 0;
@@ -360,59 +359,62 @@ int mmc_of_parse(struct mmc_host *host)
if (of_find_property(np, "non-removable", &len)) {
host->caps |= MMC_CAP_NONREMOVABLE;
} else {
- bool explicit_inv_cd, gpio_inv_cd = false;
-
- explicit_inv_cd = of_property_read_bool(np, "cd-inverted");
+ if (of_property_read_bool(np, "cd-inverted"))
+ cap_invert = true;
+ else
+ cap_invert = false;
if (of_find_property(np, "broken-cd", &len))
host->caps |= MMC_CAP_NEEDS_POLL;
- gpio = of_get_named_gpio_flags(np, "cd-gpios", 0, &flags);
- if (gpio == -EPROBE_DEFER)
- return gpio;
- if (gpio_is_valid(gpio)) {
- if (!(flags & OF_GPIO_ACTIVE_LOW))
- gpio_inv_cd = true;
-
- ret = mmc_gpio_request_cd(host, gpio, 0);
- if (ret < 0) {
- dev_err(host->parent,
- "Failed to request CD GPIO #%d: %d!\n",
- gpio, ret);
+ ret = mmc_gpiod_request_cd(host, "cd", 0, true,
+ 0, &gpio_invert);
+ if (ret) {
+ if (ret == -EPROBE_DEFER)
return ret;
- } else {
- dev_info(host->parent, "Got CD GPIO #%d.\n",
- gpio);
+ if (ret != -ENOENT) {
+ dev_err(host->parent,
+ "Failed to request CD GPIO: %d\n",
+ ret);
}
- }
-
- if (explicit_inv_cd ^ gpio_inv_cd)
+ } else
+ dev_info(host->parent, "Got CD GPIO\n");
+
+ /*
+ * There are two ways to flag that the CD line is inverted:
+ * through the cd-inverted flag and by the GPIO line itself
+ * being inverted from the GPIO subsystem. This is a leftover
+ * from the times when the GPIO subsystem did not make it
+ * possible to flag a line as inverted.
+ *
+ * If the capability on the host AND the GPIO line are
+ * both inverted, the end result is that the CD line is
+ * not inverted.
+ */
+ if (cap_invert ^ gpio_invert)
host->caps2 |= MMC_CAP2_CD_ACTIVE_HIGH;
}
/* Parse Write Protection */
- explicit_inv_wp = of_property_read_bool(np, "wp-inverted");
-
- gpio = of_get_named_gpio_flags(np, "wp-gpios", 0, &flags);
- if (gpio == -EPROBE_DEFER) {
- ret = -EPROBE_DEFER;
- goto out;
- }
- if (gpio_is_valid(gpio)) {
- if (!(flags & OF_GPIO_ACTIVE_LOW))
- gpio_inv_wp = true;
+ if (of_property_read_bool(np, "wp-inverted"))
+ cap_invert = true;
+ else
+ cap_invert = false;
- ret = mmc_gpio_request_ro(host, gpio);
- if (ret < 0) {
- dev_err(host->parent,
- "Failed to request WP GPIO: %d!\n", ret);
+ ret = mmc_gpiod_request_ro(host, "wp", 0, false, 0, &gpio_invert);
+ if (ret) {
+ if (ret == -EPROBE_DEFER)
goto out;
- } else {
- dev_info(host->parent, "Got WP GPIO #%d.\n",
- gpio);
+ if (ret != -ENOENT) {
+ dev_err(host->parent,
+ "Failed to request WP GPIO: %d\n",
+ ret);
}
- }
- if (explicit_inv_wp ^ gpio_inv_wp)
+ } else
+ dev_info(host->parent, "Got WP GPIO\n");
+
+ /* See the comment on CD inversion above */
+ if (cap_invert ^ gpio_invert)
host->caps2 |= MMC_CAP2_RO_ACTIVE_HIGH;
if (of_find_property(np, "cap-sd-highspeed", &len))
@@ -452,6 +454,14 @@ int mmc_of_parse(struct mmc_host *host)
if (of_find_property(np, "mmc-hs400-1_2v", &len))
host->caps2 |= MMC_CAP2_HS400_1_2V | MMC_CAP2_HS200_1_2V_SDR;
+ host->dsr_req = !of_property_read_u32(np, "dsr", &host->dsr);
+ if (host->dsr_req && (host->dsr & ~0xffff)) {
+ dev_err(host->parent,
+ "device tree specified broken value for DSR: 0x%x, ignoring\n",
+ host->dsr);
+ host->dsr_req = 0;
+ }
+
return 0;
out:
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 1eda8dd8c867..a301a78a2bd1 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -162,6 +162,7 @@ static int mmc_decode_csd(struct mmc_card *card)
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->dsr_imp = UNSTUFF_BITS(resp, 76, 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);
@@ -225,9 +226,7 @@ static int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd)
"Card will be ignored.\n",
mmc_hostname(card->host));
} else {
- pr_warning("%s: unable to read "
- "EXT_CSD, performance might "
- "suffer.\n",
+ pr_warn("%s: unable to read EXT_CSD, performance might suffer\n",
mmc_hostname(card->host));
err = 0;
}
@@ -298,6 +297,97 @@ static void mmc_select_card_type(struct mmc_card *card)
card->mmc_avail_type = avail_type;
}
+static void mmc_manage_enhanced_area(struct mmc_card *card, u8 *ext_csd)
+{
+ u8 hc_erase_grp_sz, hc_wp_grp_sz;
+
+ /*
+ * Disable these attributes by default
+ */
+ card->ext_csd.enhanced_area_offset = -EINVAL;
+ card->ext_csd.enhanced_area_size = -EINVAL;
+
+ /*
+ * Enhanced area feature support -- check whether the eMMC
+ * card has the Enhanced area enabled. If so, export enhanced
+ * area offset and size to user by adding sysfs interface.
+ */
+ if ((ext_csd[EXT_CSD_PARTITION_SUPPORT] & 0x2) &&
+ (ext_csd[EXT_CSD_PARTITION_ATTRIBUTE] & 0x1)) {
+ if (card->ext_csd.partition_setting_completed) {
+ hc_erase_grp_sz =
+ ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
+ hc_wp_grp_sz =
+ ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
+
+ /*
+ * calculate the enhanced data area offset, in bytes
+ */
+ card->ext_csd.enhanced_area_offset =
+ (ext_csd[139] << 24) + (ext_csd[138] << 16) +
+ (ext_csd[137] << 8) + ext_csd[136];
+ if (mmc_card_blockaddr(card))
+ card->ext_csd.enhanced_area_offset <<= 9;
+ /*
+ * calculate the enhanced data area size, in kilobytes
+ */
+ card->ext_csd.enhanced_area_size =
+ (ext_csd[142] << 16) + (ext_csd[141] << 8) +
+ ext_csd[140];
+ card->ext_csd.enhanced_area_size *=
+ (size_t)(hc_erase_grp_sz * hc_wp_grp_sz);
+ card->ext_csd.enhanced_area_size <<= 9;
+ } else {
+ pr_warn("%s: defines enhanced area without partition setting complete\n",
+ mmc_hostname(card->host));
+ }
+ }
+}
+
+static void mmc_manage_gp_partitions(struct mmc_card *card, u8 *ext_csd)
+{
+ int idx;
+ u8 hc_erase_grp_sz, hc_wp_grp_sz;
+ unsigned int part_size;
+
+ /*
+ * 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) {
+ hc_erase_grp_sz =
+ ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
+ hc_wp_grp_sz =
+ ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
+
+ 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;
+ if (card->ext_csd.partition_setting_completed == 0) {
+ pr_warn("%s: has partition size defined without partition complete\n",
+ mmc_hostname(card->host));
+ break;
+ }
+ 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,
+ MMC_BLK_DATA_AREA_GP);
+ }
+ }
+}
+
/*
* Decode extended CSD.
*/
@@ -305,7 +395,6 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
{
int err = 0, idx;
unsigned int part_size;
- u8 hc_erase_grp_sz = 0, hc_wp_grp_sz = 0;
BUG_ON(!card);
@@ -402,80 +491,16 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
ext_csd[EXT_CSD_TRIM_MULT];
card->ext_csd.raw_partition_support = ext_csd[EXT_CSD_PARTITION_SUPPORT];
if (card->ext_csd.rev >= 4) {
- /*
- * Enhanced area feature support -- check whether the eMMC
- * card has the Enhanced area enabled. If so, export enhanced
- * area offset and size to user by adding sysfs interface.
- */
- if ((ext_csd[EXT_CSD_PARTITION_SUPPORT] & 0x2) &&
- (ext_csd[EXT_CSD_PARTITION_ATTRIBUTE] & 0x1)) {
- hc_erase_grp_sz =
- ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
- hc_wp_grp_sz =
- ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
+ if (ext_csd[EXT_CSD_PARTITION_SETTING_COMPLETED] &
+ EXT_CSD_PART_SETTING_COMPLETED)
+ card->ext_csd.partition_setting_completed = 1;
+ else
+ card->ext_csd.partition_setting_completed = 0;
- card->ext_csd.enhanced_area_en = 1;
- /*
- * calculate the enhanced data area offset, in bytes
- */
- card->ext_csd.enhanced_area_offset =
- (ext_csd[139] << 24) + (ext_csd[138] << 16) +
- (ext_csd[137] << 8) + ext_csd[136];
- if (mmc_card_blockaddr(card))
- card->ext_csd.enhanced_area_offset <<= 9;
- /*
- * calculate the enhanced data area size, in kilobytes
- */
- card->ext_csd.enhanced_area_size =
- (ext_csd[142] << 16) + (ext_csd[141] << 8) +
- ext_csd[140];
- card->ext_csd.enhanced_area_size *=
- (size_t)(hc_erase_grp_sz * hc_wp_grp_sz);
- card->ext_csd.enhanced_area_size <<= 9;
- } else {
- /*
- * If the enhanced area is not enabled, disable these
- * device attributes.
- */
- card->ext_csd.enhanced_area_offset = -EINVAL;
- card->ext_csd.enhanced_area_size = -EINVAL;
- }
+ mmc_manage_enhanced_area(card, ext_csd);
- /*
- * 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;
- }
+ mmc_manage_gp_partitions(card, ext_csd);
- 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,
- MMC_BLK_DATA_AREA_GP);
- }
- }
card->ext_csd.sec_trim_mult =
ext_csd[EXT_CSD_SEC_TRIM_MULT];
card->ext_csd.sec_erase_mult =
@@ -789,8 +814,8 @@ static int __mmc_select_powerclass(struct mmc_card *card,
ext_csd->raw_pwr_cl_200_360;
break;
default:
- pr_warning("%s: Voltage range not supported "
- "for power class.\n", mmc_hostname(host));
+ pr_warn("%s: Voltage range not supported for power class\n",
+ mmc_hostname(host));
return -EINVAL;