diff options
Diffstat (limited to 'drivers/mmc/core')
-rw-r--r-- | drivers/mmc/core/block.c | 11 | ||||
-rw-r--r-- | drivers/mmc/core/card.h | 6 | ||||
-rw-r--r-- | drivers/mmc/core/core.c | 56 | ||||
-rw-r--r-- | drivers/mmc/core/core.h | 4 | ||||
-rw-r--r-- | drivers/mmc/core/host.c | 13 | ||||
-rw-r--r-- | drivers/mmc/core/mmc.c | 12 | ||||
-rw-r--r-- | drivers/mmc/core/pwrseq_simple.c | 14 | ||||
-rw-r--r-- | drivers/mmc/core/quirks.h | 3 | ||||
-rw-r--r-- | drivers/mmc/core/sd.c | 12 | ||||
-rw-r--r-- | drivers/mmc/core/sdio.c | 70 | ||||
-rw-r--r-- | drivers/mmc/core/slot-gpio.c | 7 |
11 files changed, 152 insertions, 56 deletions
diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index 38a7586b00cc..2ebba2299138 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -2353,7 +2353,8 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card, set_disk_ro(md->disk, md->read_only || default_ro); md->disk->flags = GENHD_FL_EXT_DEVT; if (area_type & (MMC_BLK_DATA_AREA_RPMB | MMC_BLK_DATA_AREA_BOOT)) - md->disk->flags |= GENHD_FL_NO_PART_SCAN; + md->disk->flags |= GENHD_FL_NO_PART_SCAN + | GENHD_FL_SUPPRESS_PARTITION_INFO; /* * As discussed on lkml, GENHD_FL_REMOVABLE should: @@ -2967,9 +2968,11 @@ static void mmc_blk_remove(struct mmc_card *card) mmc_blk_remove_debugfs(card, md); mmc_blk_remove_parts(card, md); pm_runtime_get_sync(&card->dev); - mmc_claim_host(card->host); - mmc_blk_part_switch(card, md->part_type); - mmc_release_host(card->host); + if (md->part_curr != md->part_type) { + mmc_claim_host(card->host); + mmc_blk_part_switch(card, md->part_type); + mmc_release_host(card->host); + } if (card->type != MMC_TYPE_SD_COMBO) pm_runtime_disable(&card->dev); pm_runtime_put_noidle(&card->dev); diff --git a/drivers/mmc/core/card.h b/drivers/mmc/core/card.h index 9c821eedd156..1170feb8f969 100644 --- a/drivers/mmc/core/card.h +++ b/drivers/mmc/core/card.h @@ -149,6 +149,12 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data) card->quirks &= ~data; } +static inline void __maybe_unused add_limit_rate_quirk(struct mmc_card *card, + int data) +{ + card->quirk_max_rate = data; +} + /* * Quirk add/remove for MMC products. */ diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 121ce50b6d5e..9a769edbabe0 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -50,9 +50,6 @@ #include "sd_ops.h" #include "sdio_ops.h" -/* If the device is not responding */ -#define MMC_CORE_TIMEOUT_MS (10 * 60 * 1000) /* 10 minute timeout */ - /* The max erase timeout, used when host->max_busy_timeout isn't specified */ #define MMC_ERASE_TIMEOUT_MS (60 * 1000) /* 60 s */ @@ -1484,6 +1481,17 @@ int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage) } +void mmc_set_initial_signal_voltage(struct mmc_host *host) +{ + /* Try to set signal voltage to 3.3V but fall back to 1.8v or 1.2v */ + if (!mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330)) + dev_dbg(mmc_dev(host), "Initial signal voltage of 3.3v\n"); + else if (!mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180)) + dev_dbg(mmc_dev(host), "Initial signal voltage of 1.8v\n"); + else if (!mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120)) + dev_dbg(mmc_dev(host), "Initial signal voltage of 1.2v\n"); +} + int mmc_host_set_uhs_voltage(struct mmc_host *host) { u32 clock; @@ -1646,19 +1654,13 @@ void mmc_power_up(struct mmc_host *host, u32 ocr) /* Set initial state and call mmc_set_ios */ mmc_set_initial_state(host); - /* Try to set signal voltage to 3.3V but fall back to 1.8v or 1.2v */ - if (!mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330)) - dev_dbg(mmc_dev(host), "Initial signal voltage of 3.3v\n"); - else if (!mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180)) - dev_dbg(mmc_dev(host), "Initial signal voltage of 1.8v\n"); - else if (!mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120)) - dev_dbg(mmc_dev(host), "Initial signal voltage of 1.2v\n"); + mmc_set_initial_signal_voltage(host); /* * This delay should be sufficient to allow the power supply * to reach the minimum voltage. */ - mmc_delay(10); + mmc_delay(host->ios.power_delay_ms); mmc_pwrseq_post_power_on(host); @@ -1671,7 +1673,7 @@ void mmc_power_up(struct mmc_host *host, u32 ocr) * This delay must be at least 74 clock sizes, or 1 ms, or the * time required to reach a stable voltage. */ - mmc_delay(10); + mmc_delay(host->ios.power_delay_ms); } void mmc_power_off(struct mmc_host *host) @@ -2435,22 +2437,46 @@ int mmc_hw_reset(struct mmc_host *host) return -EINVAL; mmc_bus_get(host); - if (!host->bus_ops || host->bus_dead || !host->bus_ops->reset) { + if (!host->bus_ops || host->bus_dead || !host->bus_ops->hw_reset) { mmc_bus_put(host); return -EOPNOTSUPP; } - ret = host->bus_ops->reset(host); + ret = host->bus_ops->hw_reset(host); mmc_bus_put(host); if (ret) - pr_warn("%s: tried to reset card, got error %d\n", + pr_warn("%s: tried to HW reset card, got error %d\n", mmc_hostname(host), ret); return ret; } EXPORT_SYMBOL(mmc_hw_reset); +int mmc_sw_reset(struct mmc_host *host) +{ + int ret; + + if (!host->card) + return -EINVAL; + + mmc_bus_get(host); + if (!host->bus_ops || host->bus_dead || !host->bus_ops->sw_reset) { + mmc_bus_put(host); + return -EOPNOTSUPP; + } + + ret = host->bus_ops->sw_reset(host); + mmc_bus_put(host); + + if (ret) + pr_warn("%s: tried to SW reset card, got error %d\n", + mmc_hostname(host), ret); + + return ret; +} +EXPORT_SYMBOL(mmc_sw_reset); + static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq) { host->f_init = freq; diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h index d6303d69071b..9d8f09ac0821 100644 --- a/drivers/mmc/core/core.h +++ b/drivers/mmc/core/core.h @@ -32,7 +32,8 @@ struct mmc_bus_ops { int (*power_restore)(struct mmc_host *); int (*alive)(struct mmc_host *); int (*shutdown)(struct mmc_host *); - int (*reset)(struct mmc_host *); + int (*hw_reset)(struct mmc_host *); + int (*sw_reset)(struct mmc_host *); }; void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops); @@ -51,6 +52,7 @@ u32 mmc_select_voltage(struct mmc_host *host, u32 ocr); int mmc_set_uhs_voltage(struct mmc_host *host, u32 ocr); int mmc_host_set_uhs_voltage(struct mmc_host *host); int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage); +void mmc_set_initial_signal_voltage(struct mmc_host *host); void mmc_set_timing(struct mmc_host *host, unsigned int timing); void mmc_set_driver_type(struct mmc_host *host, unsigned int drv_type); int mmc_select_drive_strength(struct mmc_card *card, unsigned int max_dtr, diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index 64b03d6eaf18..c57ffff18e37 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -179,7 +179,7 @@ static void mmc_retune_timer(struct timer_list *t) int mmc_of_parse(struct mmc_host *host) { struct device *dev = host->parent; - u32 bus_width, drv_type; + u32 bus_width, drv_type, cd_debounce_delay_ms; int ret; bool cd_cap_invert, cd_gpio_invert = false; bool ro_cap_invert, ro_gpio_invert = false; @@ -230,11 +230,16 @@ int mmc_of_parse(struct mmc_host *host) } else { cd_cap_invert = device_property_read_bool(dev, "cd-inverted"); + if (device_property_read_u32(dev, "cd-debounce-delay-ms", + &cd_debounce_delay_ms)) + cd_debounce_delay_ms = 200; + if (device_property_read_bool(dev, "broken-cd")) host->caps |= MMC_CAP_NEEDS_POLL; ret = mmc_gpiod_request_cd(host, "cd", 0, true, - 0, &cd_gpio_invert); + cd_debounce_delay_ms, + &cd_gpio_invert); if (!ret) dev_info(host->parent, "Got CD GPIO\n"); else if (ret != -ENOENT && ret != -ENOSYS) @@ -338,6 +343,9 @@ int mmc_of_parse(struct mmc_host *host) host->dsr_req = 0; } + device_property_read_u32(dev, "post-power-on-delay-ms", + &host->ios.power_delay_ms); + return mmc_pwrseq_alloc(host); } @@ -403,6 +411,7 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev) host->max_blk_count = PAGE_SIZE / 512; host->fixed_drv_type = -EINVAL; + host->ios.power_delay_ms = 10; return host; } diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 6f8ebd6caa4c..57a8bd39cdde 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -1830,6 +1830,14 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, } } + if (host->caps2 & MMC_CAP2_AVOID_3_3V && + host->ios.signal_voltage == MMC_SIGNAL_VOLTAGE_330) { + pr_err("%s: Host failed to negotiate down from 3.3V\n", + mmc_hostname(host)); + err = -EINVAL; + goto free_card; + } + if (!oldcard) host->card = card; @@ -2117,7 +2125,7 @@ static int mmc_can_reset(struct mmc_card *card) return 1; } -static int mmc_reset(struct mmc_host *host) +static int _mmc_hw_reset(struct mmc_host *host) { struct mmc_card *card = host->card; @@ -2151,7 +2159,7 @@ static const struct mmc_bus_ops mmc_ops = { .runtime_resume = mmc_runtime_resume, .alive = mmc_alive, .shutdown = mmc_shutdown, - .reset = mmc_reset, + .hw_reset = _mmc_hw_reset, }; /* diff --git a/drivers/mmc/core/pwrseq_simple.c b/drivers/mmc/core/pwrseq_simple.c index 13ef162cf066..a8b9fee4d62a 100644 --- a/drivers/mmc/core/pwrseq_simple.c +++ b/drivers/mmc/core/pwrseq_simple.c @@ -40,14 +40,18 @@ static void mmc_pwrseq_simple_set_gpios_value(struct mmc_pwrseq_simple *pwrseq, struct gpio_descs *reset_gpios = pwrseq->reset_gpios; if (!IS_ERR(reset_gpios)) { - int i; - int values[reset_gpios->ndescs]; + int i, *values; + int nvalues = reset_gpios->ndescs; - for (i = 0; i < reset_gpios->ndescs; i++) + values = kmalloc_array(nvalues, sizeof(int), GFP_KERNEL); + if (!values) + return; + + for (i = 0; i < nvalues; i++) values[i] = value; - gpiod_set_array_value_cansleep( - reset_gpios->ndescs, reset_gpios->desc, values); + gpiod_set_array_value_cansleep(nvalues, reset_gpios->desc, values); + kfree(values); } } diff --git a/drivers/mmc/core/quirks.h b/drivers/mmc/core/quirks.h index 5153577754f0..dd2f73af8f2c 100644 --- a/drivers/mmc/core/quirks.h +++ b/drivers/mmc/core/quirks.h @@ -132,6 +132,9 @@ static const struct mmc_fixup sdio_fixup_methods[] = { SDIO_FIXUP(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8797_F0, add_quirk, MMC_QUIRK_BROKEN_IRQ_POLLING), + SDIO_FIXUP(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8887WLAN, + add_limit_rate_quirk, 150000000), + END_FIXUP }; diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index baf3d5da4ccb..d0d9f90e7cdf 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -1058,6 +1058,14 @@ retry: mmc_set_bus_width(host, MMC_BUS_WIDTH_4); } } + + if (host->caps2 & MMC_CAP2_AVOID_3_3V && + host->ios.signal_voltage == MMC_SIGNAL_VOLTAGE_330) { + pr_err("%s: Host failed to negotiate down from 3.3V\n", + mmc_hostname(host)); + err = -EINVAL; + goto free_card; + } done: host->card = card; return 0; @@ -1214,7 +1222,7 @@ static int mmc_sd_runtime_resume(struct mmc_host *host) return 0; } -static int mmc_sd_reset(struct mmc_host *host) +static int mmc_sd_hw_reset(struct mmc_host *host) { mmc_power_cycle(host, host->card->ocr); return mmc_sd_init_card(host, host->card->ocr, host->card); @@ -1229,7 +1237,7 @@ static const struct mmc_bus_ops mmc_sd_ops = { .resume = mmc_sd_resume, .alive = mmc_sd_alive, .shutdown = mmc_sd_suspend, - .reset = mmc_sd_reset, + .hw_reset = mmc_sd_hw_reset, }; /* diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index c599a628a387..a86490dbca70 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -444,6 +444,7 @@ static int sdio_set_bus_speed_mode(struct mmc_card *card) unsigned int bus_speed, timing; int err; unsigned char speed; + unsigned int max_rate; /* * If the host doesn't support any of the UHS-I modes, fallback on @@ -500,9 +501,12 @@ static int sdio_set_bus_speed_mode(struct mmc_card *card) if (err) return err; + max_rate = min_not_zero(card->quirk_max_rate, + card->sw_caps.uhs_max_dtr); + if (bus_speed) { mmc_set_timing(card->host, timing); - mmc_set_clock(card->host, card->sw_caps.uhs_max_dtr); + mmc_set_clock(card->host, max_rate); } return 0; @@ -788,6 +792,14 @@ try_again: if (err) goto remove; } + + if (host->caps2 & MMC_CAP2_AVOID_3_3V && + host->ios.signal_voltage == MMC_SIGNAL_VOLTAGE_330) { + pr_err("%s: Host failed to negotiate down from 3.3V\n", + mmc_hostname(host)); + err = -EINVAL; + goto remove; + } finish: if (!oldcard) host->card = card; @@ -801,6 +813,22 @@ err: return err; } +static int mmc_sdio_reinit_card(struct mmc_host *host, bool powered_resume) +{ + int ret; + + sdio_reset(host); + mmc_go_idle(host); + mmc_send_if_cond(host, host->card->ocr); + + ret = mmc_send_io_op_cond(host, 0, NULL); + if (ret) + return ret; + + return mmc_sdio_init_card(host, host->card->ocr, host->card, + powered_resume); +} + /* * Host is being removed. Free up the current card. */ @@ -948,14 +976,7 @@ static int mmc_sdio_resume(struct mmc_host *host) /* No need to reinitialize powered-resumed nonremovable cards */ if (mmc_card_is_removable(host) || !mmc_card_keep_power(host)) { - sdio_reset(host); - mmc_go_idle(host); - mmc_send_if_cond(host, host->card->ocr); - err = mmc_send_io_op_cond(host, 0, NULL); - if (!err) - err = mmc_sdio_init_card(host, host->card->ocr, - host->card, - mmc_card_keep_power(host)); + err = mmc_sdio_reinit_card(host, mmc_card_keep_power(host)); } else if (mmc_card_keep_power(host) && mmc_card_wake_sdio_irq(host)) { /* We may have switched to 1-bit mode during suspend */ err = sdio_enable_4bit_bus(host->card); @@ -978,8 +999,6 @@ static int mmc_sdio_power_restore(struct mmc_host *host) { int ret; - mmc_claim_host(host); - /* * Reset the card by performing the same steps that are taken by * mmc_rescan_try_freq() and mmc_attach_sdio() during a "normal" probe. @@ -997,20 +1016,12 @@ static int mmc_sdio_power_restore(struct mmc_host *host) * */ - sdio_reset(host); - mmc_go_idle(host); - mmc_send_if_cond(host, host->card->ocr); - - ret = mmc_send_io_op_cond(host, 0, NULL); - if (ret) - goto out; + mmc_claim_host(host); - ret = mmc_sdio_init_card(host, host->card->ocr, host->card, - mmc_card_keep_power(host)); + ret = mmc_sdio_reinit_card(host, mmc_card_keep_power(host)); if (!ret && host->sdio_irqs) mmc_signal_sdio_irq(host); -out: mmc_release_host(host); return ret; @@ -1039,12 +1050,24 @@ static int mmc_sdio_runtime_resume(struct mmc_host *host) return ret; } -static int mmc_sdio_reset(struct mmc_host *host) +static int mmc_sdio_hw_reset(struct mmc_host *host) { mmc_power_cycle(host, host->card->ocr); return mmc_sdio_power_restore(host); } +static int mmc_sdio_sw_reset(struct mmc_host *host) +{ + mmc_set_clock(host, host->f_init); + sdio_reset(host); + mmc_go_idle(host); + + mmc_set_initial_state(host); + mmc_set_initial_signal_voltage(host); + + return mmc_sdio_reinit_card(host, 0); +} + static const struct mmc_bus_ops mmc_sdio_ops = { .remove = mmc_sdio_remove, .detect = mmc_sdio_detect, @@ -1055,7 +1078,8 @@ static const struct mmc_bus_ops mmc_sdio_ops = { .runtime_resume = mmc_sdio_runtime_resume, .power_restore = mmc_sdio_power_restore, .alive = mmc_sdio_alive, - .reset = mmc_sdio_reset, + .hw_reset = mmc_sdio_hw_reset, + .sw_reset = mmc_sdio_sw_reset, }; diff --git a/drivers/mmc/core/slot-gpio.c b/drivers/mmc/core/slot-gpio.c index 31f7dbb15668..56559351d2e1 100644 --- a/drivers/mmc/core/slot-gpio.c +++ b/drivers/mmc/core/slot-gpio.c @@ -28,15 +28,17 @@ struct mmc_gpio { irqreturn_t (*cd_gpio_isr)(int irq, void *dev_id); char *ro_label; char cd_label[0]; + u32 cd_debounce_delay_ms; }; static irqreturn_t mmc_gpio_cd_irqt(int irq, void *dev_id) { /* Schedule a card detection after a debounce timeout */ struct mmc_host *host = dev_id; + struct mmc_gpio *ctx = host->slot.handler_priv; host->trigger_card_event = true; - mmc_detect_change(host, msecs_to_jiffies(200)); + mmc_detect_change(host, msecs_to_jiffies(ctx->cd_debounce_delay_ms)); return IRQ_HANDLED; } @@ -49,6 +51,7 @@ int mmc_gpio_alloc(struct mmc_host *host) if (ctx) { ctx->ro_label = ctx->cd_label + len; + ctx->cd_debounce_delay_ms = 200; snprintf(ctx->cd_label, len, "%s cd", dev_name(host->parent)); snprintf(ctx->ro_label, len, "%s ro", dev_name(host->parent)); host->slot.handler_priv = ctx; @@ -261,7 +264,7 @@ int mmc_gpiod_request_cd(struct mmc_host *host, const char *con_id, if (debounce) { ret = gpiod_set_debounce(desc, debounce); if (ret < 0) - return ret; + ctx->cd_debounce_delay_ms = debounce; } if (gpio_invert) |