diff options
Diffstat (limited to 'drivers/mmc')
69 files changed, 2449 insertions, 1360 deletions
diff --git a/drivers/mmc/core/Makefile b/drivers/mmc/core/Makefile index abba078f7f49..95ffe008ebdf 100644 --- a/drivers/mmc/core/Makefile +++ b/drivers/mmc/core/Makefile @@ -8,7 +8,7 @@ mmc_core-y := core.o bus.o host.o \ mmc.o mmc_ops.o sd.o sd_ops.o \ sdio.o sdio_ops.o sdio_bus.o \ sdio_cis.o sdio_io.o sdio_irq.o \ - slot-gpio.o + slot-gpio.o regulator.o mmc_core-$(CONFIG_OF) += pwrseq.o obj-$(CONFIG_PWRSEQ_SIMPLE) += pwrseq_simple.o obj-$(CONFIG_PWRSEQ_SD8787) += pwrseq_sd8787.o diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index aef1185f383d..2c71a434c915 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -1124,7 +1124,7 @@ static void mmc_blk_issue_discard_rq(struct mmc_queue *mq, struct request *req) { struct mmc_blk_data *md = mq->blkdata; struct mmc_card *card = md->queue.card; - unsigned int from, nr, arg; + unsigned int from, nr; int err = 0, type = MMC_BLK_DISCARD; blk_status_t status = BLK_STS_OK; @@ -1136,24 +1136,18 @@ static void mmc_blk_issue_discard_rq(struct mmc_queue *mq, struct request *req) from = blk_rq_pos(req); nr = blk_rq_sectors(req); - if (mmc_can_discard(card)) - arg = MMC_DISCARD_ARG; - else if (mmc_can_trim(card)) - arg = MMC_TRIM_ARG; - else - arg = MMC_ERASE_ARG; do { err = 0; if (card->quirks & MMC_QUIRK_INAND_CMD38) { err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, INAND_CMD38_ARG_EXT_CSD, - arg == MMC_TRIM_ARG ? + card->erase_arg == MMC_TRIM_ARG ? INAND_CMD38_ARG_TRIM : INAND_CMD38_ARG_ERASE, 0); } if (!err) - err = mmc_erase(card, from, nr, arg); + err = mmc_erase(card, from, nr, card->erase_arg); } while (err == -EIO && !mmc_blk_reset(md, card->host, type)); if (err) status = BLK_STS_IOERR; @@ -2112,7 +2106,7 @@ static void mmc_blk_mq_req_done(struct mmc_request *mrq) if (waiting) wake_up(&mq->wait); else - kblockd_schedule_work(&mq->complete_work); + queue_work(mq->card->complete_wq, &mq->complete_work); return; } @@ -2380,12 +2374,6 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card, snprintf(md->disk->disk_name, sizeof(md->disk->disk_name), "mmcblk%u%s", card->host->index, subname ? subname : ""); - if (mmc_card_mmc(card)) - blk_queue_logical_block_size(md->queue.queue, - card->ext_csd.data_sector_size); - else - blk_queue_logical_block_size(md->queue.queue, 512); - set_capacity(md->disk, size); if (mmc_host_cmd23(card->host)) { @@ -2774,8 +2762,8 @@ static int mmc_dbg_card_status_get(void *data, u64 *val) return ret; } -DEFINE_SIMPLE_ATTRIBUTE(mmc_dbg_card_status_fops, mmc_dbg_card_status_get, - NULL, "%08llx\n"); +DEFINE_DEBUGFS_ATTRIBUTE(mmc_dbg_card_status_fops, mmc_dbg_card_status_get, + NULL, "%08llx\n"); /* That is two digits * 512 + 1 for newline */ #define EXT_CSD_STR_LEN 1025 @@ -2863,8 +2851,9 @@ static int mmc_blk_add_debugfs(struct mmc_card *card, struct mmc_blk_data *md) if (mmc_card_mmc(card) || mmc_card_sd(card)) { md->status_dentry = - debugfs_create_file("status", S_IRUSR, root, card, - &mmc_dbg_card_status_fops); + debugfs_create_file_unsafe("status", 0400, root, + card, + &mmc_dbg_card_status_fops); if (!md->status_dentry) return -EIO; } @@ -2924,6 +2913,13 @@ static int mmc_blk_probe(struct mmc_card *card) mmc_fixup_device(card, mmc_blk_fixups); + card->complete_wq = alloc_workqueue("mmc_complete", + WQ_MEM_RECLAIM | WQ_HIGHPRI, 0); + if (unlikely(!card->complete_wq)) { + pr_err("Failed to create mmc completion workqueue"); + return -ENOMEM; + } + md = mmc_blk_alloc(card); if (IS_ERR(md)) return PTR_ERR(md); @@ -2987,6 +2983,7 @@ static void mmc_blk_remove(struct mmc_card *card) pm_runtime_put_noidle(&card->dev); mmc_blk_remove_req(md); dev_set_drvdata(&card->dev, NULL); + destroy_workqueue(card->complete_wq); } static int _mmc_blk_suspend(struct mmc_card *card) diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 5bd58b95d318..6db36dc870b5 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -21,7 +21,6 @@ #include <linux/leds.h> #include <linux/scatterlist.h> #include <linux/log2.h> -#include <linux/regulator/consumer.h> #include <linux/pm_runtime.h> #include <linux/pm_wakeup.h> #include <linux/suspend.h> @@ -52,6 +51,7 @@ /* The max erase timeout, used when host->max_busy_timeout isn't specified */ #define MMC_ERASE_TIMEOUT_MS (60 * 1000) /* 60 s */ +#define SD_DISCARD_TIMEOUT_MS (250) static const unsigned freqs[] = { 400000, 300000, 200000, 100000 }; @@ -95,7 +95,7 @@ static void mmc_should_fail_request(struct mmc_host *host, if (!data) return; - if (cmd->error || data->error || + if ((cmd && cmd->error) || data->error || !should_fail(&host->fail_mmc_request, data->blksz * data->blocks)) return; @@ -758,33 +758,6 @@ void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card) } EXPORT_SYMBOL(mmc_set_data_timeout); -/** - * mmc_align_data_size - pads a transfer size to a more optimal value - * @card: the MMC card associated with the data transfer - * @sz: original transfer size - * - * Pads the original data size with a number of extra bytes in - * order to avoid controller bugs and/or performance hits - * (e.g. some controllers revert to PIO for certain sizes). - * - * Returns the improved size, which might be unmodified. - * - * Note that this function is only relevant when issuing a - * single scatter gather entry. - */ -unsigned int mmc_align_data_size(struct mmc_card *card, unsigned int sz) -{ - /* - * FIXME: We don't have a system for the controller to tell - * the core about its problems yet, so for now we just 32-bit - * align the size. - */ - sz = ((sz + 3) / 4) * 4; - - return sz; -} -EXPORT_SYMBOL(mmc_align_data_size); - /* * Allow claiming an already claimed host if the context is the same or there is * no context but the task is the same. @@ -1112,55 +1085,6 @@ u32 mmc_vddrange_to_ocrmask(int vdd_min, int vdd_max) return mask; } -EXPORT_SYMBOL(mmc_vddrange_to_ocrmask); - -#ifdef CONFIG_OF - -/** - * mmc_of_parse_voltage - return mask of supported voltages - * @np: The device node need to be parsed. - * @mask: mask of voltages available for MMC/SD/SDIO - * - * Parse the "voltage-ranges" DT property, returning zero if it is not - * found, negative errno if the voltage-range specification is invalid, - * or one if the voltage-range is specified and successfully parsed. - */ -int mmc_of_parse_voltage(struct device_node *np, u32 *mask) -{ - const u32 *voltage_ranges; - int num_ranges, i; - - voltage_ranges = of_get_property(np, "voltage-ranges", &num_ranges); - num_ranges = num_ranges / sizeof(*voltage_ranges) / 2; - if (!voltage_ranges) { - pr_debug("%pOF: voltage-ranges unspecified\n", np); - return 0; - } - if (!num_ranges) { - pr_err("%pOF: voltage-ranges empty\n", np); - return -EINVAL; - } - - for (i = 0; i < num_ranges; i++) { - const int j = i * 2; - u32 ocr_mask; - - ocr_mask = mmc_vddrange_to_ocrmask( - be32_to_cpu(voltage_ranges[j]), - be32_to_cpu(voltage_ranges[j + 1])); - if (!ocr_mask) { - pr_err("%pOF: voltage-range #%d is invalid\n", - np, i); - return -EINVAL; - } - *mask |= ocr_mask; - } - - return 1; -} -EXPORT_SYMBOL(mmc_of_parse_voltage); - -#endif /* CONFIG_OF */ static int mmc_of_get_func_num(struct device_node *node) { @@ -1190,246 +1114,6 @@ struct device_node *mmc_of_find_child_device(struct mmc_host *host, return NULL; } -#ifdef CONFIG_REGULATOR - -/** - * mmc_ocrbitnum_to_vdd - Convert a OCR bit number to its voltage - * @vdd_bit: OCR bit number - * @min_uV: minimum voltage value (mV) - * @max_uV: maximum voltage value (mV) - * - * This function returns the voltage range according to the provided OCR - * bit number. If conversion is not possible a negative errno value returned. - */ -static int mmc_ocrbitnum_to_vdd(int vdd_bit, int *min_uV, int *max_uV) -{ - int tmp; - - if (!vdd_bit) - return -EINVAL; - - /* - * REVISIT mmc_vddrange_to_ocrmask() may have set some - * bits this regulator doesn't quite support ... don't - * be too picky, most cards and regulators are OK with - * a 0.1V range goof (it's a small error percentage). - */ - tmp = vdd_bit - ilog2(MMC_VDD_165_195); - if (tmp == 0) { - *min_uV = 1650 * 1000; - *max_uV = 1950 * 1000; - } else { - *min_uV = 1900 * 1000 + tmp * 100 * 1000; - *max_uV = *min_uV + 100 * 1000; - } - - return 0; -} - -/** - * mmc_regulator_get_ocrmask - return mask of supported voltages - * @supply: regulator to use - * - * This returns either a negative errno, or a mask of voltages that - * can be provided to MMC/SD/SDIO devices using the specified voltage - * regulator. This would normally be called before registering the - * MMC host adapter. - */ -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++) { - vdd_uV = regulator_list_voltage(supply, i); - if (vdd_uV <= 0) - continue; - - vdd_mV = vdd_uV / 1000; - 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); - -/** - * mmc_regulator_set_ocr - set regulator to match host->ios voltage - * @mmc: the host to regulate - * @supply: regulator to use - * @vdd_bit: zero for power off, else a bit number (host->ios.vdd) - * - * Returns zero on success, else negative errno. - * - * MMC host drivers may use this to enable or disable a regulator using - * a particular supply voltage. This would normally be called from the - * set_ios() method. - */ -int mmc_regulator_set_ocr(struct mmc_host *mmc, - struct regulator *supply, - unsigned short vdd_bit) -{ - int result = 0; - int min_uV, max_uV; - - if (vdd_bit) { - mmc_ocrbitnum_to_vdd(vdd_bit, &min_uV, &max_uV); - - result = regulator_set_voltage(supply, min_uV, max_uV); - if (result == 0 && !mmc->regulator_enabled) { - result = regulator_enable(supply); - if (!result) - mmc->regulator_enabled = true; - } - } else if (mmc->regulator_enabled) { - result = regulator_disable(supply); - if (result == 0) - mmc->regulator_enabled = false; - } - - if (result) - dev_err(mmc_dev(mmc), - "could not set regulator OCR (%d)\n", result); - return result; -} -EXPORT_SYMBOL_GPL(mmc_regulator_set_ocr); - -static int mmc_regulator_set_voltage_if_supported(struct regulator *regulator, - int min_uV, int target_uV, - int max_uV) -{ - /* - * Check if supported first to avoid errors since we may try several - * signal levels during power up and don't want to show errors. - */ - if (!regulator_is_supported_voltage(regulator, min_uV, max_uV)) - return -EINVAL; - - return regulator_set_voltage_triplet(regulator, min_uV, target_uV, - max_uV); -} - -/** - * mmc_regulator_set_vqmmc - Set VQMMC as per the ios - * - * For 3.3V signaling, we try to match VQMMC to VMMC as closely as possible. - * That will match the behavior of old boards where VQMMC and VMMC were supplied - * by the same supply. The Bus Operating conditions for 3.3V signaling in the - * SD card spec also define VQMMC in terms of VMMC. - * If this is not possible we'll try the full 2.7-3.6V of the spec. - * - * For 1.2V and 1.8V signaling we'll try to get as close as possible to the - * requested voltage. This is definitely a good idea for UHS where there's a - * separate regulator on the card that's trying to make 1.8V and it's best if - * we match. - * - * This function is expected to be used by a controller's - * start_signal_voltage_switch() function. - */ -int mmc_regulator_set_vqmmc(struct mmc_host *mmc, struct mmc_ios *ios) -{ - struct device *dev = mmc_dev(mmc); - int ret, volt, min_uV, max_uV; - - /* If no vqmmc supply then we can't change the voltage */ - if (IS_ERR(mmc->supply.vqmmc)) - return -EINVAL; - - switch (ios->signal_voltage) { - case MMC_SIGNAL_VOLTAGE_120: - return mmc_regulator_set_voltage_if_supported(mmc->supply.vqmmc, - 1100000, 1200000, 1300000); - case MMC_SIGNAL_VOLTAGE_180: - return mmc_regulator_set_voltage_if_supported(mmc->supply.vqmmc, - 1700000, 1800000, 1950000); - case MMC_SIGNAL_VOLTAGE_330: - ret = mmc_ocrbitnum_to_vdd(mmc->ios.vdd, &volt, &max_uV); - if (ret < 0) - return ret; - - dev_dbg(dev, "%s: found vmmc voltage range of %d-%duV\n", - __func__, volt, max_uV); - - min_uV = max(volt - 300000, 2700000); - max_uV = min(max_uV + 200000, 3600000); - - /* - * Due to a limitation in the current implementation of - * regulator_set_voltage_triplet() which is taking the lowest - * voltage possible if below the target, search for a suitable - * voltage in two steps and try to stay close to vmmc - * with a 0.3V tolerance at first. - */ - if (!mmc_regulator_set_voltage_if_supported(mmc->supply.vqmmc, - min_uV, volt, max_uV)) - return 0; - - return mmc_regulator_set_voltage_if_supported(mmc->supply.vqmmc, - 2700000, volt, 3600000); - default: - return -EINVAL; - } -} -EXPORT_SYMBOL_GPL(mmc_regulator_set_vqmmc); - -#endif /* CONFIG_REGULATOR */ - -/** - * mmc_regulator_get_supply - try to get VMMC and VQMMC regulators for a host - * @mmc: the host to regulate - * - * Returns 0 or errno. errno should be handled, it is either a critical error - * or -EPROBE_DEFER. 0 means no critical error but it does not mean all - * regulators have been found because they all are optional. If you require - * certain regulators, you need to check separately in your driver if they got - * populated after calling this function. - */ -int mmc_regulator_get_supply(struct mmc_host *mmc) -{ - struct device *dev = mmc_dev(mmc); - int ret; - - mmc->supply.vmmc = devm_regulator_get_optional(dev, "vmmc"); - mmc->supply.vqmmc = devm_regulator_get_optional(dev, "vqmmc"); - - if (IS_ERR(mmc->supply.vmmc)) { - if (PTR_ERR(mmc->supply.vmmc) == -EPROBE_DEFER) - return -EPROBE_DEFER; - dev_dbg(dev, "No vmmc regulator found\n"); - } else { - ret = mmc_regulator_get_ocrmask(mmc->supply.vmmc); - if (ret > 0) - mmc->ocr_avail = ret; - else - dev_warn(dev, "Failed getting OCR mask: %d\n", ret); - } - - if (IS_ERR(mmc->supply.vqmmc)) { - if (PTR_ERR(mmc->supply.vqmmc) == -EPROBE_DEFER) - return -EPROBE_DEFER; - dev_dbg(dev, "No vqmmc regulator found\n"); - } - - return 0; -} -EXPORT_SYMBOL_GPL(mmc_regulator_get_supply); - /* * Mask off any voltages we don't support and select * the lowest voltage @@ -1936,6 +1620,12 @@ static unsigned int mmc_sd_erase_timeout(struct mmc_card *card, { unsigned int erase_timeout; + /* for DISCARD none of the below calculation applies. + * the busy timeout is 250msec per discard command. + */ + if (arg == SD_DISCARD_ARG) + return SD_DISCARD_TIMEOUT_MS; + if (card->ssr.erase_timeout) { /* Erase timeout specified in SD Status Register (SSR) */ erase_timeout = card->ssr.erase_timeout * qty + @@ -2164,7 +1854,7 @@ static unsigned int mmc_align_erase_size(struct mmc_card *card, * @card: card to erase * @from: first sector to erase * @nr: number of sectors to erase - * @arg: erase command argument (SD supports only %MMC_ERASE_ARG) + * @arg: erase command argument * * Caller must claim host before calling this function. */ @@ -2181,14 +1871,14 @@ int mmc_erase(struct mmc_card *card, unsigned int from, unsigned int nr, if (!card->erase_size) return -EOPNOTSUPP; - if (mmc_card_sd(card) && arg != MMC_ERASE_ARG) + if (mmc_card_sd(card) && arg != SD_ERASE_ARG && arg != SD_DISCARD_ARG) return -EOPNOTSUPP; - if ((arg & MMC_SECURE_ARGS) && + if (mmc_card_mmc(card) && (arg & MMC_SECURE_ARGS) && !(card->ext_csd.sec_feature_support & EXT_CSD_SEC_ER_EN)) return -EOPNOTSUPP; - if ((arg & MMC_TRIM_ARGS) && + if (mmc_card_mmc(card) && (arg & MMC_TRIM_ARGS) && !(card->ext_csd.sec_feature_support & EXT_CSD_SEC_GB_CL_EN)) return -EOPNOTSUPP; @@ -2381,9 +2071,9 @@ unsigned int mmc_calc_max_discard(struct mmc_card *card) return card->pref_erase; max_discard = mmc_do_calc_max_discard(card, MMC_ERASE_ARG); - if (max_discard && mmc_can_trim(card)) { + if (mmc_can_trim(card)) { max_trim = mmc_do_calc_max_discard(card, MMC_TRIM_ARG); - if (max_trim < max_discard) + if (max_trim < max_discard || max_discard == 0) max_discard = max_trim; } else if (max_discard < card->erase_size) { max_discard = 0; diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h index 8fb6bc37f808..b5083b13d594 100644 --- a/drivers/mmc/core/core.h +++ b/drivers/mmc/core/core.h @@ -59,6 +59,7 @@ void mmc_power_up(struct mmc_host *host, u32 ocr); void mmc_power_off(struct mmc_host *host); void mmc_power_cycle(struct mmc_host *host, u32 ocr); void mmc_set_initial_state(struct mmc_host *host); +u32 mmc_vddrange_to_ocrmask(int vdd_min, int vdd_max); static inline void mmc_delay(unsigned int ms) { diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index cf58ccaf22d5..6a51f7a06ce7 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -194,7 +194,7 @@ int mmc_of_parse(struct mmc_host *host) switch (bus_width) { case 8: host->caps |= MMC_CAP_8_BIT_DATA; - /* Hosts capable of 8-bit transfers can also do 4 bits */ + /* fall through - Hosts capable of 8-bit can also do 4 bits */ case 4: host->caps |= MMC_CAP_4_BIT_DATA; break; @@ -260,7 +260,7 @@ int mmc_of_parse(struct mmc_host *host) /* Parse Write Protection */ ro_cap_invert = device_property_read_bool(dev, "wp-inverted"); - ret = mmc_gpiod_request_ro(host, "wp", 0, false, 0, &ro_gpio_invert); + ret = mmc_gpiod_request_ro(host, "wp", 0, 0, &ro_gpio_invert); if (!ret) dev_info(host->parent, "Got WP GPIO\n"); else if (ret != -ENOENT && ret != -ENOSYS) @@ -349,6 +349,50 @@ int mmc_of_parse(struct mmc_host *host) EXPORT_SYMBOL(mmc_of_parse); /** + * mmc_of_parse_voltage - return mask of supported voltages + * @np: The device node need to be parsed. + * @mask: mask of voltages available for MMC/SD/SDIO + * + * Parse the "voltage-ranges" DT property, returning zero if it is not + * found, negative errno if the voltage-range specification is invalid, + * or one if the voltage-range is specified and successfully parsed. + */ +int mmc_of_parse_voltage(struct device_node *np, u32 *mask) +{ + const u32 *voltage_ranges; + int num_ranges, i; + + voltage_ranges = of_get_property(np, "voltage-ranges", &num_ranges); + if (!voltage_ranges) { + pr_debug("%pOF: voltage-ranges unspecified\n", np); + return 0; + } + num_ranges = num_ranges / sizeof(*voltage_ranges) / 2; + if (!num_ranges) { + pr_err("%pOF: voltage-ranges empty\n", np); + return -EINVAL; + } + + for (i = 0; i < num_ranges; i++) { + const int j = i * 2; + u32 ocr_mask; + + ocr_mask = mmc_vddrange_to_ocrmask( + be32_to_cpu(voltage_ranges[j]), + be32_to_cpu(voltage_ranges[j + 1])); + if (!ocr_mask) { + pr_err("%pOF: voltage-range #%d is invalid\n", + np, i); + return -EINVAL; + } + *mask |= ocr_mask; + } + + return 1; +} +EXPORT_SYMBOL(mmc_of_parse_voltage); + +/** * mmc_alloc_host - initialise the per-host structure. * @extra: sizeof private data structure * @dev: pointer to host device model structure @@ -385,8 +429,6 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev) if (mmc_gpio_alloc(host)) { put_device(&host->class_dev); - ida_simple_remove(&mmc_host_ida, host->index); - kfree(host); return NULL; } diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index da892a599524..3e786ba204c3 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -1594,6 +1594,8 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, if (oldcard) { if (memcmp(cid, oldcard->raw_cid, sizeof(cid)) != 0) { + pr_debug("%s: Perhaps the card was replaced\n", + mmc_hostname(host)); err = -ENOENT; goto err; } @@ -1743,6 +1745,14 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, card->ext_csd.power_off_notification = EXT_CSD_POWER_ON; } + /* set erase_arg */ + if (mmc_can_discard(card)) + card->erase_arg = MMC_DISCARD_ARG; + else if (mmc_can_trim(card)) + card->erase_arg = MMC_TRIM_ARG; + else + card->erase_arg = MMC_ERASE_ARG; + /* * Select timing interface */ diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c index 9054329fe903..a533cab8fccc 100644 --- a/drivers/mmc/core/mmc_ops.c +++ b/drivers/mmc/core/mmc_ops.c @@ -184,11 +184,7 @@ int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) if (err) break; - /* if we're just probing, do a single pass */ - if (ocr == 0) - break; - - /* otherwise wait until reset completes */ + /* wait until reset completes */ if (mmc_host_is_spi(host)) { if (!(cmd.resp[0] & R1_SPI_IDLE)) break; @@ -200,6 +196,16 @@ int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) err = -ETIMEDOUT; mmc_delay(10); + + /* + * According to eMMC specification v5.1 section 6.4.3, we + * should issue CMD1 repeatedly in the idle state until + * the eMMC is ready. Otherwise some eMMC devices seem to enter + * the inactive mode after mmc_init_card() issued CMD0 when + * the eMMC device is busy. + */ + if (!ocr && !mmc_host_is_spi(host)) + cmd.arg = cmd.resp[0] | BIT(30); } if (rocr && !mmc_host_is_spi(host)) @@ -562,7 +568,7 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value, if (index == EXT_CSD_SANITIZE_START) cmd.sanitize_busy = true; - err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES); + err = mmc_wait_for_cmd(host, &cmd, 0); if (err) goto out; diff --git a/drivers/mmc/core/pwrseq_emmc.c b/drivers/mmc/core/pwrseq_emmc.c index efb8a7965dd4..154f4204d58c 100644 --- a/drivers/mmc/core/pwrseq_emmc.c +++ b/drivers/mmc/core/pwrseq_emmc.c @@ -30,19 +30,14 @@ struct mmc_pwrseq_emmc { #define to_pwrseq_emmc(p) container_of(p, struct mmc_pwrseq_emmc, pwrseq) -static void __mmc_pwrseq_emmc_reset(struct mmc_pwrseq_emmc *pwrseq) -{ - gpiod_set_value(pwrseq->reset_gpio, 1); - udelay(1); - gpiod_set_value(pwrseq->reset_gpio, 0); - udelay(200); -} - static void mmc_pwrseq_emmc_reset(struct mmc_host *host) { struct mmc_pwrseq_emmc *pwrseq = to_pwrseq_emmc(host->pwrseq); - __mmc_pwrseq_emmc_reset(pwrseq); + gpiod_set_value_cansleep(pwrseq->reset_gpio, 1); + udelay(1); + gpiod_set_value_cansleep(pwrseq->reset_gpio, 0); + udelay(200); } static int mmc_pwrseq_emmc_reset_nb(struct notifier_block *this, @@ -50,8 +45,11 @@ static int mmc_pwrseq_emmc_reset_nb(struct notifier_block *this, { struct mmc_pwrseq_emmc *pwrseq = container_of(this, struct mmc_pwrseq_emmc, reset_nb); + gpiod_set_value(pwrseq->reset_gpio, 1); + udelay(1); + gpiod_set_value(pwrseq->reset_gpio, 0); + udelay(200); - __mmc_pwrseq_emmc_reset(pwrseq); return NOTIFY_DONE; } @@ -72,14 +70,18 @@ static int mmc_pwrseq_emmc_probe(struct platform_device *pdev) if (IS_ERR(pwrseq->reset_gpio)) return PTR_ERR(pwrseq->reset_gpio); - /* - * register reset handler to ensure emmc reset also from - * emergency_reboot(), priority 255 is the highest priority - * so it will be executed before any system reboot handler. - */ - pwrseq->reset_nb.notifier_call = mmc_pwrseq_emmc_reset_nb; - pwrseq->reset_nb.priority = 255; - register_restart_handler(&pwrseq->reset_nb); + if (!gpiod_cansleep(pwrseq->reset_gpio)) { + /* + * register reset handler to ensure emmc reset also from + * emergency_reboot(), priority 255 is the highest priority + * so it will be executed before any system reboot handler. + */ + pwrseq->reset_nb.notifier_call = mmc_pwrseq_emmc_reset_nb; + pwrseq->reset_nb.priority = 255; + register_restart_handler(&pwrseq->reset_nb); + } else { + dev_notice(dev, "EMMC reset pin tied to a sleepy GPIO driver; reset on emergency-reboot disabled\n"); + } pwrseq->pwrseq.ops = &mmc_pwrseq_emmc_ops; pwrseq->pwrseq.dev = dev; diff --git a/drivers/mmc/core/queue.c b/drivers/mmc/core/queue.c index 35cc138b096d..b5b9c6142f08 100644 --- a/drivers/mmc/core/queue.c +++ b/drivers/mmc/core/queue.c @@ -355,6 +355,7 @@ static void mmc_setup_queue(struct mmc_queue *mq, struct mmc_card *card) { struct mmc_host *host = card->host; u64 limit = BLK_BOUNCE_HIGH; + unsigned block_size = 512; if (mmc_dev(host)->dma_mask && *mmc_dev(host)->dma_mask) limit = (u64)dma_max_pfn(mmc_dev(host)) << PAGE_SHIFT; @@ -368,7 +369,13 @@ static void mmc_setup_queue(struct mmc_queue *mq, struct mmc_card *card) blk_queue_max_hw_sectors(mq->queue, min(host->max_blk_count, host->max_req_size / 512)); blk_queue_max_segments(mq->queue, host->max_segs); - blk_queue_max_segment_size(mq->queue, host->max_seg_size); + + if (mmc_card_mmc(card)) + block_size = card->ext_csd.data_sector_size; + + blk_queue_logical_block_size(mq->queue, block_size); + blk_queue_max_segment_size(mq->queue, + round_down(host->max_seg_size, block_size)); INIT_WORK(&mq->recovery_work, mmc_mq_recovery_handler); INIT_WORK(&mq->complete_work, mmc_blk_mq_complete_work); @@ -410,8 +417,7 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card) else mq->tag_set.queue_depth = MMC_QUEUE_DEPTH; mq->tag_set.numa_node = NUMA_NO_NODE; - mq->tag_set.flags = BLK_MQ_F_SHOULD_MERGE | BLK_MQ_F_SG_MERGE | - BLK_MQ_F_BLOCKING; + mq->tag_set.flags = BLK_MQ_F_SHOULD_MERGE | BLK_MQ_F_BLOCKING; mq->tag_set.nr_hw_queues = 1; mq->tag_set.cmd_size = sizeof(struct mmc_queue_req); mq->tag_set.driver_data = mq; @@ -466,6 +472,7 @@ void mmc_cleanup_queue(struct mmc_queue *mq) blk_mq_unquiesce_queue(q); blk_cleanup_queue(q); + blk_mq_free_tag_set(&mq->tag_set); /* * A request can be completed before the next request, potentially diff --git a/drivers/mmc/core/quirks.h b/drivers/mmc/core/quirks.h index dd2f73af8f2c..2d2d9ea8be4f 100644 --- a/drivers/mmc/core/quirks.h +++ b/drivers/mmc/core/quirks.h @@ -159,7 +159,7 @@ static inline void mmc_fixup_device(struct mmc_card *card, (f->ext_csd_rev == EXT_CSD_REV_ANY || f->ext_csd_rev == card->ext_csd.rev) && rev >= f->rev_start && rev <= f->rev_end) { - dev_dbg(&card->dev, "calling %pf\n", f->vendor_fixup); + dev_dbg(&card->dev, "calling %ps\n", f->vendor_fixup); f->vendor_fixup(card, f->data); } } diff --git a/drivers/mmc/core/regulator.c b/drivers/mmc/core/regulator.c new file mode 100644 index 000000000000..b6febbcf8978 --- /dev/null +++ b/drivers/mmc/core/regulator.c @@ -0,0 +1,260 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Helper functions for MMC regulators. + */ + +#include <linux/device.h> +#include <linux/err.h> +#include <linux/log2.h> +#include <linux/regulator/consumer.h> + +#include <linux/mmc/host.h> + +#include "core.h" +#include "host.h" + +#ifdef CONFIG_REGULATOR + +/** + * mmc_ocrbitnum_to_vdd - Convert a OCR bit number to its voltage + * @vdd_bit: OCR bit number + * @min_uV: minimum voltage value (mV) + * @max_uV: maximum voltage value (mV) + * + * This function returns the voltage range according to the provided OCR + * bit number. If conversion is not possible a negative errno value returned. + */ +static int mmc_ocrbitnum_to_vdd(int vdd_bit, int *min_uV, int *max_uV) +{ + int tmp; + + if (!vdd_bit) + return -EINVAL; + + /* + * REVISIT mmc_vddrange_to_ocrmask() may have set some + * bits this regulator doesn't quite support ... don't + * be too picky, most cards and regulators are OK with + * a 0.1V range goof (it's a small error percentage). + */ + tmp = vdd_bit - ilog2(MMC_VDD_165_195); + if (tmp == 0) { + *min_uV = 1650 * 1000; + *max_uV = 1950 * 1000; + } else { + *min_uV = 1900 * 1000 + tmp * 100 * 1000; + *max_uV = *min_uV + 100 * 1000; + } + + return 0; +} + +/** + * mmc_regulator_get_ocrmask - return mask of supported voltages + * @supply: regulator to use + * + * This returns either a negative errno, or a mask of voltages that + * can be provided to MMC/SD/SDIO devices using the specified voltage + * regulator. This would normally be called before registering the + * MMC host adapter. + */ +static 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++) { + vdd_uV = regulator_list_voltage(supply, i); + if (vdd_uV <= 0) + continue; + + vdd_mV = vdd_uV / 1000; + 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; +} + +/** + * mmc_regulator_set_ocr - set regulator to match host->ios voltage + * @mmc: the host to regulate + * @supply: regulator to use + * @vdd_bit: zero for power off, else a bit number (host->ios.vdd) + * + * Returns zero on success, else negative errno. + * + * MMC host drivers may use this to enable or disable a regulator using + * a particular supply voltage. This would normally be called from the + * set_ios() method. + */ +int mmc_regulator_set_ocr(struct mmc_host *mmc, + struct regulator *supply, + unsigned short vdd_bit) +{ + int result = 0; + int min_uV, max_uV; + + if (vdd_bit) { + mmc_ocrbitnum_to_vdd(vdd_bit, &min_uV, &max_uV); + + result = regulator_set_voltage(supply, min_uV, max_uV); + if (result == 0 && !mmc->regulator_enabled) { + result = regulator_enable(supply); + if (!result) + mmc->regulator_enabled = true; + } + } else if (mmc->regulator_enabled) { + result = regulator_disable(supply); + if (result == 0) + mmc->regulator_enabled = false; + } + + if (result) + dev_err(mmc_dev(mmc), + "could not set regulator OCR (%d)\n", result); + return result; +} +EXPORT_SYMBOL_GPL(mmc_regulator_set_ocr); + +static int mmc_regulator_set_voltage_if_supported(struct regulator *regulator, + int min_uV, int target_uV, + int max_uV) +{ + /* + * Check if supported first to avoid errors since we may try several + * signal levels during power up and don't want to show errors. + */ + if (!regulator_is_supported_voltage(regulator, min_uV, max_uV)) + return -EINVAL; + + return regulator_set_voltage_triplet(regulator, min_uV, target_uV, + max_uV); +} + +/** + * mmc_regulator_set_vqmmc - Set VQMMC as per the ios + * + * For 3.3V signaling, we try to match VQMMC to VMMC as closely as possible. + * That will match the behavior of old boards where VQMMC and VMMC were supplied + * by the same supply. The Bus Operating conditions for 3.3V signaling in the + * SD card spec also define VQMMC in terms of VMMC. + * If this is not possible we'll try the full 2.7-3.6V of the spec. + * + * For 1.2V and 1.8V signaling we'll try to get as close as possible to the + * requested voltage. This is definitely a good idea for UHS where there's a + * separate regulator on the card that's trying to make 1.8V and it's best if + * we match. + * + * This function is expected to be used by a controller's + * start_signal_voltage_switch() function. + */ +int mmc_regulator_set_vqmmc(struct mmc_host *mmc, struct mmc_ios *ios) +{ + struct device *dev = mmc_dev(mmc); + int ret, volt, min_uV, max_uV; + + /* If no vqmmc supply then we can't change the voltage */ + if (IS_ERR(mmc->supply.vqmmc)) + return -EINVAL; + + switch (ios->signal_voltage) { + case MMC_SIGNAL_VOLTAGE_120: + return mmc_regulator_set_voltage_if_supported(mmc->supply.vqmmc, + 1100000, 1200000, 1300000); + case MMC_SIGNAL_VOLTAGE_180: + return mmc_regulator_set_voltage_if_supported(mmc->supply.vqmmc, + 1700000, 1800000, 1950000); + case MMC_SIGNAL_VOLTAGE_330: + ret = mmc_ocrbitnum_to_vdd(mmc->ios.vdd, &volt, &max_uV); + if (ret < 0) + return ret; + + dev_dbg(dev, "%s: found vmmc voltage range of %d-%duV\n", + __func__, volt, max_uV); + + min_uV = max(volt - 300000, 2700000); + max_uV = min(max_uV + 200000, 3600000); + + /* + * Due to a limitation in the current implementation of + * regulator_set_voltage_triplet() which is taking the lowest + * voltage possible if below the target, search for a suitable + * voltage in two steps and try to stay close to vmmc + * with a 0.3V tolerance at first. + */ + if (!mmc_regulator_set_voltage_if_supported(mmc->supply.vqmmc, + min_uV, volt, max_uV)) + return 0; + + return mmc_regulator_set_voltage_if_supported(mmc->supply.vqmmc, + 2700000, volt, 3600000); + default: + return -EINVAL; + } +} +EXPORT_SYMBOL_GPL(mmc_regulator_set_vqmmc); + +#else + +static inline int mmc_regulator_get_ocrmask(struct regulator *supply) +{ + return 0; +} + +#endif /* CONFIG_REGULATOR */ + +/** + * mmc_regulator_get_supply - try to get VMMC and VQMMC regulators for a host + * @mmc: the host to regulate + * + * Returns 0 or errno. errno should be handled, it is either a critical error + * or -EPROBE_DEFER. 0 means no critical error but it does not mean all + * regulators have been found because they all are optional. If you require + * certain regulators, you need to check separately in your driver if they got + * populated after calling this function. + */ +int mmc_regulator_get_supply(struct mmc_host *mmc) +{ + struct device *dev = mmc_dev(mmc); + int ret; + + mmc->supply.vmmc = devm_regulator_get_optional(dev, "vmmc"); + mmc->supply.vqmmc = devm_regulator_get_optional(dev, "vqmmc"); + + if (IS_ERR(mmc->supply.vmmc)) { + if (PTR_ERR(mmc->supply.vmmc) == -EPROBE_DEFER) + return -EPROBE_DEFER; + dev_dbg(dev, "No vmmc regulator found\n"); + } else { + ret = mmc_regulator_get_ocrmask(mmc->supply.vmmc); + if (ret > 0) + mmc->ocr_avail = ret; + else + dev_warn(dev, "Failed getting OCR mask: %d\n", ret); + } + + if (IS_ERR(mmc->supply.vqmmc)) { + if (PTR_ERR(mmc->supply.vqmmc) == -EPROBE_DEFER) + return -EPROBE_DEFER; + dev_dbg(dev, "No vqmmc regulator found\n"); + } + + return 0; +} +EXPORT_SYMBOL_GPL(mmc_regulator_get_supply); diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index d0d9f90e7cdf..d3d32f9a2cb1 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -209,6 +209,11 @@ static int mmc_decode_scr(struct mmc_card *card) /* Check if Physical Layer Spec v3.0 is supported */ scr->sda_spec3 = UNSTUFF_BITS(resp, 47, 1); + if (scr->sda_spec3) { + scr->sda_spec4 = UNSTUFF_BITS(resp, 42, 1); + scr->sda_specx = UNSTUFF_BITS(resp, 38, 4); + } + if (UNSTUFF_BITS(resp, 55, 1)) card->erased_byte = 0xFF; else @@ -216,6 +221,14 @@ static int mmc_decode_scr(struct mmc_card *card) if (scr->sda_spec3) scr->cmds = UNSTUFF_BITS(resp, 32, 2); + + /* SD Spec says: any SD Card shall set at least bits 0 and 2 */ + if (!(scr->bus_widths & SD_SCR_BUS_WIDTH_1) || + !(scr->bus_widths & SD_SCR_BUS_WIDTH_4)) { + pr_err("%s: invalid bus width\n", mmc_hostname(card->host)); + return -EINVAL; + } + return 0; } @@ -226,6 +239,8 @@ static int mmc_read_ssr(struct mmc_card *card) { unsigned int au, es, et, eo; __be32 *raw_ssr; + u32 resp[4] = {}; + u8 discard_support; int i; if (!(card->csd.cmdclass & CCC_APP_SPEC)) { @@ -271,6 +286,14 @@ static int mmc_read_ssr(struct mmc_card *card) } } + /* + * starting SD5.1 discard is supported if DISCARD_SUPPORT (b313) is set + */ + resp[3] = card->raw_ssr[6]; + discard_support = UNSTUFF_BITS(resp, 313 - 288, 1); + card->erase_arg = (card->scr.sda_specx && discard_support) ? + SD_DISCARD_ARG : SD_ERASE_ARG; + return 0; } @@ -936,8 +959,11 @@ retry: return err; if (oldcard) { - if (memcmp(cid, oldcard->raw_cid, sizeof(cid)) != 0) + if (memcmp(cid, oldcard->raw_cid, sizeof(cid)) != 0) { + pr_debug("%s: Perhaps the card was replaced\n", + mmc_hostname(host)); return -ENOENT; + } card = oldcard; } else { diff --git a/drivers/mmc/core/sd_ops.c b/drivers/mmc/core/sd_ops.c index 47056d8d1bac..0bb0b8419016 100644 --- a/drivers/mmc/core/sd_ops.c +++ b/drivers/mmc/core/sd_ops.c @@ -52,36 +52,17 @@ int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card) } EXPORT_SYMBOL_GPL(mmc_app_cmd); -/** - * mmc_wait_for_app_cmd - start an application command and wait for - completion - * @host: MMC host to start command - * @card: Card to send MMC_APP_CMD to - * @cmd: MMC command to start - * @retries: maximum number of retries - * - * Sends a MMC_APP_CMD, checks the card response, sends the command - * in the parameter and waits for it to complete. Return any error - * that occurred while the command was executing. Do not attempt to - * parse the response. - */ -int mmc_wait_for_app_cmd(struct mmc_host *host, struct mmc_card *card, - struct mmc_command *cmd, int retries) +static int mmc_wait_for_app_cmd(struct mmc_host *host, struct mmc_card *card, + struct mmc_command *cmd) { struct mmc_request mrq = {}; - - int i, err; - - if (retries < 0) - retries = MMC_CMD_RETRIES; - - err = -EIO; + int i, err = -EIO; /* * We have to resend MMC_APP_CMD for each attempt so * we cannot use the retries field in mmc_command. */ - for (i = 0;i <= retries;i++) { + for (i = 0; i <= MMC_CMD_RETRIES; i++) { err = mmc_app_cmd(host, card); if (err) { /* no point in retrying; no APP commands allowed */ @@ -116,8 +97,6 @@ int mmc_wait_for_app_cmd(struct mmc_host *host, struct mmc_card *card, return err; } -EXPORT_SYMBOL(mmc_wait_for_app_cmd); - int mmc_app_set_bus_width(struct mmc_card *card, int width) { struct mmc_command cmd = {}; @@ -136,7 +115,7 @@ int mmc_app_set_bus_width(struct mmc_card *card, int width) return -EINVAL; } - return mmc_wait_for_app_cmd(card->host, card, &cmd, MMC_CMD_RETRIES); + return mmc_wait_for_app_cmd(card->host, card, &cmd); } int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) @@ -152,7 +131,7 @@ int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R3 | MMC_CMD_BCR; for (i = 100; i; i--) { - err = mmc_wait_for_app_cmd(host, NULL, &cmd, MMC_CMD_RETRIES); + err = mmc_wait_for_app_cmd(host, NULL, &cmd); if (err) break; diff --git a/drivers/mmc/core/sd_ops.h b/drivers/mmc/core/sd_ops.h index 0e6c3d51e66d..ffaed5cacc88 100644 --- a/drivers/mmc/core/sd_ops.h +++ b/drivers/mmc/core/sd_ops.h @@ -16,7 +16,6 @@ struct mmc_card; struct mmc_host; -struct mmc_command; int mmc_app_set_bus_width(struct mmc_card *card, int width); int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr); @@ -27,8 +26,6 @@ int mmc_sd_switch(struct mmc_card *card, int mode, int group, u8 value, u8 *resp); int mmc_app_sd_status(struct mmc_card *card, void *ssr); int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card); -int mmc_wait_for_app_cmd(struct mmc_host *host, struct mmc_card *card, - struct mmc_command *cmd, int retries); #endif diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index d8e17ea6126d..6718fc8bb40f 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -617,6 +617,8 @@ try_again: if (oldcard && (oldcard->type != MMC_TYPE_SD_COMBO || memcmp(card->raw_cid, oldcard->raw_cid, sizeof(card->raw_cid)) != 0)) { mmc_remove_card(card); + pr_debug("%s: Perhaps the card was replaced\n", + mmc_hostname(host)); return -ENOENT; } } else { @@ -624,6 +626,8 @@ try_again: if (oldcard && oldcard->type != MMC_TYPE_SDIO) { mmc_remove_card(card); + pr_debug("%s: Perhaps the card was replaced\n", + mmc_hostname(host)); return -ENOENT; } } @@ -736,8 +740,11 @@ try_again: int same = (card->cis.vendor == oldcard->cis.vendor && card->cis.device == oldcard->cis.device); mmc_remove_card(card); - if (!same) + if (!same) { + pr_debug("%s: Perhaps the card was replaced\n", + mmc_hostname(host)); return -ENOENT; + } card = oldcard; } diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c index b6d8203e46eb..62b0f5ecc7f7 100644 --- a/drivers/mmc/core/sdio_bus.c +++ b/drivers/mmc/core/sdio_bus.c @@ -179,7 +179,6 @@ static int sdio_bus_remove(struct device *dev) { struct sdio_driver *drv = to_sdio_driver(dev->driver); struct sdio_func *func = dev_to_sdio_func(dev); - int ret = 0; /* Make sure card is powered before invoking ->remove() */ if (func->card->host->caps & MMC_CAP_POWER_OFF_CARD) @@ -205,7 +204,7 @@ static int sdio_bus_remove(struct device *dev) dev_pm_domain_detach(dev, false); - return ret; + return 0; } static const struct dev_pm_ops sdio_bus_pm_ops = { diff --git a/drivers/mmc/core/sdio_io.c b/drivers/mmc/core/sdio_io.c index d40744bbafa9..3f67fbbe0d75 100644 --- a/drivers/mmc/core/sdio_io.c +++ b/drivers/mmc/core/sdio_io.c @@ -10,6 +10,7 @@ */ #include <linux/export.h> +#include <linux/kernel.h> #include <linux/mmc/host.h> #include <linux/mmc/card.h> #include <linux/mmc/sdio.h> @@ -203,6 +204,21 @@ static inline unsigned int sdio_max_byte_size(struct sdio_func *func) return min(mval, 512u); /* maximum size for byte mode */ } +/* + * This is legacy code, which needs to be re-worked some day. Basically we need + * to take into account the properties of the host, as to enable the SDIO func + * driver layer to allocate optimal buffers. + */ +static inline unsigned int _sdio_align_size(unsigned int sz) +{ + /* + * FIXME: We don't have a system for the controller to tell + * the core about its problems yet, so for now we just 32-bit + * align the size. + */ + return ALIGN(sz, 4); +} + /** * sdio_align_size - pads a transfer size to a more optimal value * @func: SDIO function @@ -230,7 +246,7 @@ unsigned int sdio_align_size(struct sdio_func *func, unsigned int sz) * wants to increase the size up to a point where it * might need more than one block. */ - sz = mmc_align_data_size(func->card, sz); + sz = _sdio_align_size(sz); /* * If we can still do this with just a byte transfer, then @@ -252,7 +268,7 @@ unsigned int sdio_align_size(struct sdio_func *func, unsigned int sz) */ blk_sz = ((sz + func->cur_blksize - 1) / func->cur_blksize) * func->cur_blksize; - blk_sz = mmc_align_data_size(func->card, blk_sz); + blk_sz = _sdio_align_size(blk_sz); /* * This value is only good if it is still just @@ -265,8 +281,7 @@ unsigned int sdio_align_size(struct sdio_func *func, unsigned int sz) * We failed to do one request, but at least try to * pad the remainder properly. */ - byte_sz = mmc_align_data_size(func->card, - sz % func->cur_blksize); + byte_sz = _sdio_align_size(sz % func->cur_blksize); if (byte_sz <= sdio_max_byte_size(func)) { blk_sz = sz / func->cur_blksize; return blk_sz * func->cur_blksize + byte_sz; @@ -276,16 +291,14 @@ unsigned int sdio_align_size(struct sdio_func *func, unsigned int sz) * We need multiple requests, so first check that the * controller can handle the chunk size; */ - chunk_sz = mmc_align_data_size(func->card, - sdio_max_byte_size(func)); + chunk_sz = _sdio_align_size(sdio_max_byte_size(func)); if (chunk_sz == sdio_max_byte_size(func)) { /* * Fix up the size of the remainder (if any) */ byte_sz = orig_sz % chunk_sz; if (byte_sz) { - byte_sz = mmc_align_data_size(func->card, - byte_sz); + byte_sz = _sdio_align_size(byte_sz); } return (orig_sz / chunk_sz) * chunk_sz + byte_sz; diff --git a/drivers/mmc/core/sdio_ops.h b/drivers/mmc/core/sdio_ops.h index 96945cafbf0b..1f6d0447ea0f 100644 --- a/drivers/mmc/core/sdio_ops.h +++ b/drivers/mmc/core/sdio_ops.h @@ -25,7 +25,6 @@ int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn, int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn, unsigned addr, int incr_addr, u8 *buf, unsigned blocks, unsigned blksz); int sdio_reset(struct mmc_host *host); -unsigned int mmc_align_data_size(struct mmc_card *card, unsigned int sz); void sdio_irq_work(struct work_struct *work); static inline bool sdio_is_io_busy(u32 opcode, u32 arg) diff --git a/drivers/mmc/core/slot-gpio.c b/drivers/mmc/core/slot-gpio.c index 319ccd93383d..4afc6b87b465 100644 --- a/drivers/mmc/core/slot-gpio.c +++ b/drivers/mmc/core/slot-gpio.c @@ -22,7 +22,6 @@ struct mmc_gpio { struct gpio_desc *ro_gpio; struct gpio_desc *cd_gpio; - bool override_ro_active_level; bool override_cd_active_level; irqreturn_t (*cd_gpio_isr)(int irq, void *dev_id); char *ro_label; @@ -71,10 +70,6 @@ int mmc_gpio_get_ro(struct mmc_host *host) if (!ctx || !ctx->ro_gpio) return -ENOSYS; - if (ctx->override_ro_active_level) - return !gpiod_get_raw_value_cansleep(ctx->ro_gpio) ^ - !!(host->caps2 & MMC_CAP2_RO_ACTIVE_HIGH); - return gpiod_get_value_cansleep(ctx->ro_gpio); } EXPORT_SYMBOL(mmc_gpio_get_ro); @@ -225,7 +220,6 @@ EXPORT_SYMBOL(mmc_can_gpio_cd); * @host: mmc host * @con_id: function within the GPIO consumer * @idx: index of the GPIO to obtain in the consumer - * @override_active_level: ignore %GPIO_ACTIVE_LOW flag * @debounce: debounce time in microseconds * @gpio_invert: will return whether the GPIO line is inverted or not, * set to NULL to ignore @@ -233,7 +227,7 @@ EXPORT_SYMBOL(mmc_can_gpio_cd); * Returns zero on success, else an error. */ int mmc_gpiod_request_ro(struct mmc_host *host, const char *con_id, - unsigned int idx, bool override_active_level, + unsigned int idx, unsigned int debounce, bool *gpio_invert) { struct mmc_gpio *ctx = host->slot.handler_priv; @@ -253,7 +247,6 @@ int mmc_gpiod_request_ro(struct mmc_host *host, const char *con_id, if (gpio_invert) *gpio_invert = !gpiod_is_active_low(desc); - ctx->override_ro_active_level = override_active_level; ctx->ro_gpio = desc; return 0; diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index a44ec8bb5418..0e86340536b6 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -92,6 +92,7 @@ config MMC_SDHCI_PCI tristate "SDHCI support on PCI bus" depends on MMC_SDHCI && PCI select MMC_CQHCI + select IOSF_MBI if X86 help This selects the PCI Secure Digital Host Controller Interface. Most controllers found today are PCI devices. @@ -224,6 +225,7 @@ config MMC_SDHCI_ESDHC_IMX depends on ARCH_MXC depends on MMC_SDHCI_PLTFM select MMC_SDHCI_IO_ACCESSORS + select MMC_CQHCI help This selects the Freescale eSDHC/uSDHC controller support found on i.MX25, i.MX35 i.MX5x and i.MX6x. @@ -250,6 +252,7 @@ config MMC_SDHCI_TEGRA depends on ARCH_TEGRA depends on MMC_SDHCI_PLTFM select MMC_SDHCI_IO_ACCESSORS + select MMC_CQHCI help This selects the Tegra SD/MMC controller. If you have a Tegra platform with SD or MMC devices, say Y or M here. @@ -435,7 +438,7 @@ config MMC_WBSD depends on ISA_DMA_API help This selects the Winbond(R) W83L51xD Secure digital and - Multimedia card Interface. + Multimedia card Interface. If you have a machine with a integrated W83L518D or W83L519D SD/MMC card reader, say Y or M here. @@ -513,7 +516,7 @@ config MMC_TIFM_SD 'Misc devices: TI Flash Media PCI74xx/PCI76xx host adapter support (TIFM_7XX1)'. - To compile this driver as a module, choose M here: the + To compile this driver as a module, choose M here: the module will be called tifm_sd. config MMC_MVSDIO @@ -529,12 +532,12 @@ config MMC_MVSDIO module will be called mvsdio. config MMC_DAVINCI - tristate "TI DAVINCI Multimedia Card Interface support" - depends on ARCH_DAVINCI - help - This selects the TI DAVINCI Multimedia card Interface. - If you have an DAVINCI board with a Multimedia Card slot, - say Y or M here. If unsure, say N. + tristate "TI DAVINCI Multimedia Card Interface support" + depends on ARCH_DAVINCI + help + This selects the TI DAVINCI Multimedia card Interface. + If you have an DAVINCI board with a Multimedia Card slot, + say Y or M here. If unsure, say N. config MMC_GOLDFISH tristate "goldfish qemu Multimedia Card Interface support" @@ -563,18 +566,18 @@ config MMC_S3C depends on S3C24XX_DMAC help This selects a driver for the MCI interface found in - Samsung's S3C2410, S3C2412, S3C2440, S3C2442 CPUs. + Samsung's S3C2410, S3C2412, S3C2440, S3C2442 CPUs. If you have a board based on one of those and a MMC/SD slot, say Y or M here. If unsure, say N. config MMC_S3C_HW_SDIO_IRQ - bool "Hardware support for SDIO IRQ" - depends on MMC_S3C - help - Enable the hardware support for SDIO interrupts instead of using - the generic polling code. + bool "Hardware support for SDIO IRQ" + depends on MMC_S3C + help + Enable the hardware support for SDIO interrupts instead of using + the generic polling code. choice prompt "Samsung S3C SD/MMC transfer code" @@ -939,6 +942,7 @@ config MMC_BCM2835 config MMC_MTK tristate "MediaTek SD/MMC Card Interface support" depends on HAS_DMA + select REGULATOR help This selects the MediaTek(R) Secure digital and Multimedia card Interface. If you have a machine with a integrated SD/MMC card reader, say Y or M here. @@ -946,15 +950,16 @@ config MMC_MTK If unsure, say N. config MMC_SDHCI_MICROCHIP_PIC32 - tristate "Microchip PIC32MZDA SDHCI support" - depends on MMC_SDHCI && PIC32MZDA && MMC_SDHCI_PLTFM - help - This selects the Secure Digital Host Controller Interface (SDHCI) - for PIC32MZDA platform. + tristate "Microchip PIC32MZDA SDHCI support" + depends on MMC_SDHCI && PIC32MZDA && MMC_SDHCI_PLTFM + help + This selects the Secure Digital Host Controller Interface (SDHCI) + for PIC32MZDA platform. + + If you have a controller with this interface, say Y or M here. - If you have a controller with this interface, say Y or M here. + If unsure, say N. - If unsure, say N. config MMC_SDHCI_BRCMSTB tristate "Broadcom SDIO/SD/MMC support" depends on ARCH_BRCMSTB || BMIPS_GENERIC @@ -991,6 +996,7 @@ config MMC_SDHCI_OMAP config MMC_SDHCI_AM654 tristate "Support for the SDHCI Controller in TI's AM654 SOCs" depends on MMC_SDHCI_PLTFM && OF + select MMC_SDHCI_IO_ACCESSORS help This selects the Secure Digital Host Controller Interface (SDHCI) support present in TI's AM654 SOCs. The controller supports diff --git a/drivers/mmc/host/alcor.c b/drivers/mmc/host/alcor.c index c712b7deb3a9..e481535cba2b 100644 --- a/drivers/mmc/host/alcor.c +++ b/drivers/mmc/host/alcor.c @@ -43,12 +43,10 @@ struct alcor_sdmmc_host { struct device *dev; struct alcor_pci_priv *alcor_pci; - struct mmc_host *mmc; struct mmc_request *mrq; struct mmc_command *cmd; struct mmc_data *data; unsigned int dma_on:1; - unsigned int early_data:1; struct mutex cmd_mutex; @@ -118,6 +116,9 @@ static void alcor_reset(struct alcor_sdmmc_host *host, u8 val) dev_err(host->dev, "%s: timeout\n", __func__); } +/* + * Perform DMA I/O of a single page. + */ static void alcor_data_set_dma(struct alcor_sdmmc_host *host) { struct alcor_pci_priv *priv = host->alcor_pci; @@ -144,8 +145,7 @@ static void alcor_data_set_dma(struct alcor_sdmmc_host *host) host->sg_count--; } -static void alcor_trigger_data_transfer(struct alcor_sdmmc_host *host, - bool early) +static void alcor_trigger_data_transfer(struct alcor_sdmmc_host *host) { struct alcor_pci_priv *priv = host->alcor_pci; struct mmc_data *data = host->data; @@ -155,19 +155,26 @@ static void alcor_trigger_data_transfer(struct alcor_sdmmc_host *host, ctrl |= AU6601_DATA_WRITE; if (data->host_cookie == COOKIE_MAPPED) { - if (host->early_data) { - host->early_data = false; - return; - } - - host->early_data = early; - + /* + * For DMA transfers, this function is called just once, + * at the start of the operation. The hardware can only + * perform DMA I/O on a single page at a time, so here + * we kick off the transfer with the first page, and expect + * subsequent pages to be transferred upon IRQ events + * indicating that the single-page DMA was completed. + */ alcor_data_set_dma(host); ctrl |= AU6601_DATA_DMA_MODE; host->dma_on = 1; alcor_write32(priv, data->sg_count * 0x1000, AU6601_REG_BLOCK_SIZE); } else { + /* + * For PIO transfers, we break down each operation + * into several sector-sized transfers. When one sector has + * complete, the IRQ handler will call this function again + * to kick off the transfer of the next sector. + */ alcor_write32(priv, data->blksz, AU6601_REG_BLOCK_SIZE); } @@ -231,6 +238,7 @@ static void alcor_prepare_sg_miter(struct alcor_sdmmc_host *host) static void alcor_prepare_data(struct alcor_sdmmc_host *host, struct mmc_command *cmd) { + struct alcor_pci_priv *priv = host->alcor_pci; struct mmc_data *data = cmd->data; if (!data) @@ -248,7 +256,7 @@ static void alcor_prepare_data(struct alcor_sdmmc_host *host, if (data->host_cookie != COOKIE_MAPPED) alcor_prepare_sg_miter(host); - alcor_trigger_data_transfer(host, true); + alcor_write8(priv, 0, AU6601_DATA_XFER_CTRL); } static void alcor_send_cmd(struct alcor_sdmmc_host *host, @@ -284,7 +292,7 @@ static void alcor_send_cmd(struct alcor_sdmmc_host *host, break; default: dev_err(host->dev, "%s: cmd->flag (0x%02x) is not valid\n", - mmc_hostname(host->mmc), mmc_resp_type(cmd)); + mmc_hostname(mmc_from_priv(host)), mmc_resp_type(cmd)); break; } @@ -325,7 +333,7 @@ static void alcor_request_complete(struct alcor_sdmmc_host *host, host->data = NULL; host->dma_on = 0; - mmc_request_done(host->mmc, mrq); + mmc_request_done(mmc_from_priv(host), mrq); } static void alcor_finish_data(struct alcor_sdmmc_host *host) @@ -435,7 +443,7 @@ static int alcor_cmd_irq_done(struct alcor_sdmmc_host *host, u32 intmask) if (!host->data) return false; - alcor_trigger_data_transfer(host, false); + alcor_trigger_data_transfer(host); host->cmd = NULL; return true; } @@ -456,7 +464,7 @@ static void alcor_cmd_irq_thread(struct alcor_sdmmc_host *host, u32 intmask) if (!host->data) alcor_request_complete(host, 1); else - alcor_trigger_data_transfer(host, false); + alcor_trigger_data_transfer(host); host->cmd = NULL; } @@ -487,15 +495,9 @@ static int alcor_data_irq_done(struct alcor_sdmmc_host *host, u32 intmask) break; case AU6601_INT_READ_BUF_RDY: alcor_trf_block_pio(host, true); - if (!host->blocks) - break; - alcor_trigger_data_transfer(host, false); return 1; case AU6601_INT_WRITE_BUF_RDY: alcor_trf_block_pio(host, false); - if (!host->blocks) - break; - alcor_trigger_data_transfer(host, false); return 1; case AU6601_INT_DMA_END: if (!host->sg_count) @@ -508,8 +510,14 @@ static int alcor_data_irq_done(struct alcor_sdmmc_host *host, u32 intmask) break; } - if (intmask & AU6601_INT_DATA_END) - return 0; + if (intmask & AU6601_INT_DATA_END) { + if (!host->dma_on && host->blocks) { + alcor_trigger_data_transfer(host); + return 1; + } else { + return 0; + } + } return 1; } @@ -555,7 +563,7 @@ static void alcor_cd_irq(struct alcor_sdmmc_host *host, u32 intmask) alcor_request_complete(host, 1); } - mmc_detect_change(host->mmc, msecs_to_jiffies(1)); + mmc_detect_change(mmc_from_priv(host), msecs_to_jiffies(1)); } static irqreturn_t alcor_irq_thread(int irq, void *d) @@ -779,12 +787,17 @@ static void alcor_pre_req(struct mmc_host *mmc, data->host_cookie = COOKIE_UNMAPPED; /* FIXME: looks like the DMA engine works only with CMD18 */ - if (cmd->opcode != 18) + if (cmd->opcode != MMC_READ_MULTIPLE_BLOCK + && cmd->opcode != MMC_WRITE_MULTIPLE_BLOCK) return; /* * We don't do DMA on "complex" transfers, i.e. with - * non-word-aligned buffers or lengths. Also, we don't bother - * with all the DMA setup overhead for short transfers. + * non-word-aligned buffers or lengths. A future improvement + * could be made to use temporary DMA bounce-buffers when these + * requirements are not met. + * + * Also, we don't bother with all the DMA setup overhead for + * short transfers. */ if (data->blocks * data->blksz < AU6601_MAX_DMA_BLOCK_SIZE) return; @@ -795,6 +808,8 @@ static void alcor_pre_req(struct mmc_host *mmc, for_each_sg(data->sg, sg, data->sg_len, i) { if (sg->length != AU6601_MAX_DMA_BLOCK_SIZE) return; + if (sg->offset != 0) + return; } /* This data might be unmapped at this time */ @@ -967,7 +982,6 @@ static void alcor_timeout_timer(struct work_struct *work) alcor_request_complete(host, 0); } - mmiowb(); mutex_unlock(&host->cmd_mutex); } @@ -1033,7 +1047,7 @@ static void alcor_hw_uninit(struct alcor_sdmmc_host *host) static void alcor_init_mmc(struct alcor_sdmmc_host *host) { - struct mmc_host *mmc = host->mmc; + struct mmc_host *mmc = mmc_from_priv(host); mmc->f_min = AU6601_MIN_CLOCK; mmc->f_max = AU6601_MAX_CLOCK; @@ -1044,14 +1058,22 @@ static void alcor_init_mmc(struct alcor_sdmmc_host *host) mmc->caps2 = MMC_CAP2_NO_SDIO; mmc->ops = &alcor_sdc_ops; - /* Hardware cannot do scatter lists */ + /* The hardware does DMA data transfer of 4096 bytes to/from a single + * buffer address. Scatterlists are not supported at the hardware + * level, however we can work with them at the driver level, + * provided that each segment is exactly 4096 bytes in size. + * Upon DMA completion of a single segment (signalled via IRQ), we + * immediately proceed to transfer the next segment from the + * scatterlist. + * + * The overall request is limited to 240 sectors, matching the + * original vendor driver. + */ mmc->max_segs = AU6601_MAX_DMA_SEGMENTS; mmc->max_seg_size = AU6601_MAX_DMA_BLOCK_SIZE; - - mmc->max_blk_size = mmc->max_seg_size; - mmc->max_blk_count = mmc->max_segs; - - mmc->max_req_size = mmc->max_seg_size * mmc->max_segs; + mmc->max_blk_count = 240; + mmc->max_req_size = mmc->max_blk_count * mmc->max_blk_size; + dma_set_max_seg_size(host->dev, mmc->max_seg_size); } static int alcor_pci_sdmmc_drv_probe(struct platform_device *pdev) @@ -1068,7 +1090,6 @@ static int alcor_pci_sdmmc_drv_probe(struct platform_device *pdev) } host = mmc_priv(mmc); - host->mmc = mmc; host->dev = &pdev->dev; host->cur_power_mode = MMC_POWER_UNDEFINED; host->alcor_pci = priv; @@ -1100,13 +1121,14 @@ static int alcor_pci_sdmmc_drv_probe(struct platform_device *pdev) static int alcor_pci_sdmmc_drv_remove(struct platform_device *pdev) { struct alcor_sdmmc_host *host = dev_get_drvdata(&pdev->dev); + struct mmc_host *mmc = mmc_from_priv(host); if (cancel_delayed_work_sync(&host->timeout_work)) alcor_request_complete(host, 0); alcor_hw_uninit(host); - mmc_remove_host(host->mmc); - mmc_free_host(host->mmc); + mmc_remove_host(mmc); + mmc_free_host(mmc); return 0; } diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c index 47189f9ed4e2..735aa5871358 100644 --- a/drivers/mmc/host/atmel-mci.c +++ b/drivers/mmc/host/atmel-mci.c @@ -1410,6 +1410,9 @@ static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) case MMC_BUS_WIDTH_4: slot->sdc_reg |= ATMCI_SDCBUS_4BIT; break; + case MMC_BUS_WIDTH_8: + slot->sdc_reg |= ATMCI_SDCBUS_8BIT; + break; } if (ios->clock) { @@ -2275,8 +2278,11 @@ static int atmci_init_slot(struct atmel_mci *host, * use only one bit for data to prevent fifo underruns and overruns * which will corrupt data. */ - if ((slot_data->bus_width >= 4) && host->caps.has_rwproof) + if ((slot_data->bus_width >= 4) && host->caps.has_rwproof) { mmc->caps |= MMC_CAP_4_BIT_DATA; + if (slot_data->bus_width >= 8) + mmc->caps |= MMC_CAP_8_BIT_DATA; + } if (atmci_get_version(host) < 0x200) { mmc->max_segs = 256; diff --git a/drivers/mmc/host/bcm2835.c b/drivers/mmc/host/bcm2835.c index c9e7aa50bb0a..7e0d3a49c06d 100644 --- a/drivers/mmc/host/bcm2835.c +++ b/drivers/mmc/host/bcm2835.c @@ -148,7 +148,6 @@ struct bcm2835_host { void __iomem *ioaddr; u32 phys_addr; - struct mmc_host *mmc; struct platform_device *pdev; int clock; /* Current clock speed */ @@ -618,7 +617,7 @@ static void bcm2835_finish_request(struct bcm2835_host *host) "failed to terminate DMA (%d)\n", err); } - mmc_request_done(host->mmc, mrq); + mmc_request_done(mmc_from_priv(host), mrq); } static @@ -837,7 +836,7 @@ static void bcm2835_timeout(struct work_struct *work) dev_err(dev, "timeout waiting for hardware interrupt.\n"); bcm2835_dumpregs(host); - bcm2835_reset(host->mmc); + bcm2835_reset(mmc_from_priv(host)); if (host->data) { host->data->error = -ETIMEDOUT; @@ -1100,6 +1099,7 @@ static void bcm2835_dma_complete_work(struct work_struct *work) static void bcm2835_set_clock(struct bcm2835_host *host, unsigned int clock) { + struct mmc_host *mmc = mmc_from_priv(host); int div; /* The SDCDIV register has 11 bits, and holds (div - 2). But @@ -1143,18 +1143,18 @@ static void bcm2835_set_clock(struct bcm2835_host *host, unsigned int clock) div = SDCDIV_MAX_CDIV; clock = host->max_clk / (div + 2); - host->mmc->actual_clock = clock; + mmc->actual_clock = clock; /* Calibrate some delays */ host->ns_per_fifo_word = (1000000000 / clock) * - ((host->mmc->caps & MMC_CAP_4_BIT_DATA) ? 8 : 32); + ((mmc->caps & MMC_CAP_4_BIT_DATA) ? 8 : 32); host->cdiv = div; writel(host->cdiv, host->ioaddr + SDCDIV); /* Set the timeout to 500ms */ - writel(host->mmc->actual_clock / 2, host->ioaddr + SDTOUT); + writel(mmc->actual_clock / 2, host->ioaddr + SDTOUT); } static void bcm2835_request(struct mmc_host *mmc, struct mmc_request *mrq) @@ -1264,7 +1264,7 @@ static const struct mmc_host_ops bcm2835_ops = { static int bcm2835_add_host(struct bcm2835_host *host) { - struct mmc_host *mmc = host->mmc; + struct mmc_host *mmc = mmc_from_priv(host); struct device *dev = &host->pdev->dev; char pio_limit_string[20]; int ret; @@ -1286,7 +1286,7 @@ static int bcm2835_add_host(struct bcm2835_host *host) spin_lock_init(&host->lock); mutex_init(&host->mutex); - if (IS_ERR_OR_NULL(host->dma_chan_rxtx)) { + if (!host->dma_chan_rxtx) { dev_warn(dev, "unable to initialise DMA channel. Falling back to PIO\n"); host->use_dma = false; } else { @@ -1370,7 +1370,6 @@ static int bcm2835_probe(struct platform_device *pdev) mmc->ops = &bcm2835_ops; host = mmc_priv(mmc); - host->mmc = mmc; host->pdev = pdev; spin_lock_init(&host->lock); @@ -1441,8 +1440,9 @@ err: static int bcm2835_remove(struct platform_device *pdev) { struct bcm2835_host *host = platform_get_drvdata(pdev); + struct mmc_host *mmc = mmc_from_priv(host); - mmc_remove_host(host->mmc); + mmc_remove_host(mmc); writel(SDVDD_POWER_OFF, host->ioaddr + SDVDD); @@ -1454,8 +1454,7 @@ static int bcm2835_remove(struct platform_device *pdev) if (host->dma_chan_rxtx) dma_release_channel(host->dma_chan_rxtx); - mmc_free_host(host->mmc); - platform_set_drvdata(pdev, NULL); + mmc_free_host(mmc); return 0; } diff --git a/drivers/mmc/host/cb710-mmc.c b/drivers/mmc/host/cb710-mmc.c index 1087b4c79cd6..4c477dcd2ada 100644 --- a/drivers/mmc/host/cb710-mmc.c +++ b/drivers/mmc/host/cb710-mmc.c @@ -566,30 +566,32 @@ static void cb710_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) cb710_mmc_select_clock_divider(mmc, ios->clock); - if (ios->power_mode != reader->last_power_mode) - switch (ios->power_mode) { - case MMC_POWER_ON: - err = cb710_mmc_powerup(slot); - if (err) { - dev_warn(cb710_slot_dev(slot), - "powerup failed (%d)- retrying\n", err); - cb710_mmc_powerdown(slot); - udelay(1); + if (ios->power_mode != reader->last_power_mode) { + switch (ios->power_mode) { + case MMC_POWER_ON: err = cb710_mmc_powerup(slot); - if (err) + if (err) { dev_warn(cb710_slot_dev(slot), - "powerup retry failed (%d) - expect errors\n", + "powerup failed (%d)- retrying\n", err); + cb710_mmc_powerdown(slot); + udelay(1); + err = cb710_mmc_powerup(slot); + if (err) + dev_warn(cb710_slot_dev(slot), + "powerup retry failed (%d) - expect errors\n", err); + } + reader->last_power_mode = MMC_POWER_ON; + break; + case MMC_POWER_OFF: + cb710_mmc_powerdown(slot); + reader->last_power_mode = MMC_POWER_OFF; + break; + case MMC_POWER_UP: + default: + /* ignore */ + break; } - reader->last_power_mode = MMC_POWER_ON; - break; - case MMC_POWER_OFF: - cb710_mmc_powerdown(slot); - reader->last_power_mode = MMC_POWER_OFF; - break; - case MMC_POWER_UP: - default: - /* ignore */; } cb710_mmc_enable_4bit_data(slot, ios->bus_width != MMC_BUS_WIDTH_1); diff --git a/drivers/mmc/host/cqhci.c b/drivers/mmc/host/cqhci.c index 159270e947cf..d59cb0a51964 100644 --- a/drivers/mmc/host/cqhci.c +++ b/drivers/mmc/host/cqhci.c @@ -201,7 +201,7 @@ static int cqhci_host_alloc_tdl(struct cqhci_host *cq_host) cq_host->desc_size = cq_host->slot_sz * cq_host->num_slots; cq_host->data_size = cq_host->trans_desc_len * cq_host->mmc->max_segs * - (cq_host->num_slots - 1); + cq_host->mmc->cqe_qdepth; pr_debug("%s: cqhci: desc_size: %zu data_sz: %zu slot-sz: %d\n", mmc_hostname(cq_host->mmc), cq_host->desc_size, cq_host->data_size, @@ -217,12 +217,21 @@ static int cqhci_host_alloc_tdl(struct cqhci_host *cq_host) cq_host->desc_size, &cq_host->desc_dma_base, GFP_KERNEL); + if (!cq_host->desc_base) + return -ENOMEM; + cq_host->trans_desc_base = dmam_alloc_coherent(mmc_dev(cq_host->mmc), cq_host->data_size, &cq_host->trans_desc_dma_base, GFP_KERNEL); - if (!cq_host->desc_base || !cq_host->trans_desc_base) + if (!cq_host->trans_desc_base) { + dmam_free_coherent(mmc_dev(cq_host->mmc), cq_host->desc_size, + cq_host->desc_base, + cq_host->desc_dma_base); + cq_host->desc_base = NULL; + cq_host->desc_dma_base = 0; return -ENOMEM; + } pr_debug("%s: cqhci: desc-base: 0x%p trans-base: 0x%p\n desc_dma 0x%llx trans_dma: 0x%llx\n", mmc_hostname(cq_host->mmc), cq_host->desc_base, cq_host->trans_desc_base, @@ -528,6 +537,8 @@ static void cqhci_prep_dcmd_desc(struct mmc_host *mmc, CQHCI_ACT(0x5) | CQHCI_CMD_INDEX(mrq->cmd->opcode) | CQHCI_CMD_TIMING(timing) | CQHCI_RESP_TYPE(resp_type)); + if (cq_host->ops->update_dcmd_desc) + cq_host->ops->update_dcmd_desc(mmc, mrq, &data); *task_desc |= data; desc = (u8 *)task_desc; pr_debug("%s: cqhci: dcmd: cmd: %d timing: %d resp: %d\n", diff --git a/drivers/mmc/host/cqhci.h b/drivers/mmc/host/cqhci.h index 9e68286a07b4..1e8e01d81015 100644 --- a/drivers/mmc/host/cqhci.h +++ b/drivers/mmc/host/cqhci.h @@ -88,6 +88,7 @@ /* send status config 1 */ #define CQHCI_SSC1 0x40 +#define CQHCI_SSC1_CBC_MASK GENMASK(19, 16) /* send status config 2 */ #define CQHCI_SSC2 0x44 @@ -147,6 +148,7 @@ struct cqhci_host_ops; struct mmc_host; +struct mmc_request; struct cqhci_slot; struct cqhci_host { @@ -210,6 +212,8 @@ struct cqhci_host_ops { u32 (*read_l)(struct cqhci_host *host, int reg); void (*enable)(struct mmc_host *mmc); void (*disable)(struct mmc_host *mmc, bool recovery); + void (*update_dcmd_desc)(struct mmc_host *mmc, struct mmc_request *mrq, + u64 *data); }; static inline void cqhci_writel(struct cqhci_host *host, u32 val, int reg) diff --git a/drivers/mmc/host/davinci_mmc.c b/drivers/mmc/host/davinci_mmc.c index 9e68c3645e22..f37003df1e01 100644 --- a/drivers/mmc/host/davinci_mmc.c +++ b/drivers/mmc/host/davinci_mmc.c @@ -1117,7 +1117,7 @@ static inline void mmc_davinci_cpufreq_deregister(struct mmc_davinci_host *host) { } #endif -static void __init init_mmcsd_host(struct mmc_davinci_host *host) +static void init_mmcsd_host(struct mmc_davinci_host *host) { mmc_davinci_reset_ctrl(host, 1); @@ -1193,7 +1193,7 @@ static int mmc_davinci_parse_pdata(struct mmc_host *mmc) else if (ret) mmc->caps |= MMC_CAP_NEEDS_POLL; - ret = mmc_gpiod_request_ro(mmc, "wp", 0, false, 0, NULL); + ret = mmc_gpiod_request_ro(mmc, "wp", 0, 0, NULL); if (ret == -EPROBE_DEFER) return ret; diff --git a/drivers/mmc/host/jz4740_mmc.c b/drivers/mmc/host/jz4740_mmc.c index 33215d66afa2..63303022669c 100644 --- a/drivers/mmc/host/jz4740_mmc.c +++ b/drivers/mmc/host/jz4740_mmc.c @@ -21,7 +21,6 @@ #include <linux/dmaengine.h> #include <linux/dma-mapping.h> #include <linux/err.h> -#include <linux/gpio/consumer.h> #include <linux/interrupt.h> #include <linux/io.h> #include <linux/irq.h> @@ -36,7 +35,6 @@ #include <asm/cacheflush.h> #include <asm/mach-jz4740/dma.h> -#include <asm/mach-jz4740/jz4740_mmc.h> #define JZ_REG_MMC_STRPCL 0x00 #define JZ_REG_MMC_STATUS 0x04 @@ -148,9 +146,7 @@ enum jz4780_cookie { struct jz4740_mmc_host { struct mmc_host *mmc; struct platform_device *pdev; - struct jz4740_mmc_platform_data *pdata; struct clk *clk; - struct gpio_desc *power; enum jz4740_mmc_version version; @@ -743,6 +739,7 @@ static irqreturn_t jz_mmc_irq_worker(int irq, void *devid) break; jz_mmc_prepare_data_transfer(host); + /* fall through */ case JZ4740_MMC_STATE_TRANSFER_DATA: if (host->use_dma) { @@ -777,6 +774,7 @@ static irqreturn_t jz_mmc_irq_worker(int irq, void *devid) break; } jz4740_mmc_write_irq_reg(host, JZ_MMC_IRQ_DATA_TRAN_DONE); + /* fall through */ case JZ4740_MMC_STATE_SEND_STOP: if (!req->stop) @@ -894,16 +892,16 @@ static void jz4740_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) switch (ios->power_mode) { case MMC_POWER_UP: jz4740_mmc_reset(host); - if (host->power) - gpiod_set_value(host->power, 1); + if (!IS_ERR(mmc->supply.vmmc)) + mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, ios->vdd); host->cmdat |= JZ_MMC_CMDAT_INIT; clk_prepare_enable(host->clk); break; case MMC_POWER_ON: break; default: - if (host->power) - gpiod_set_value(host->power, 0); + if (!IS_ERR(mmc->supply.vmmc)) + mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0); clk_disable_unprepare(host->clk); break; } @@ -936,38 +934,6 @@ static const struct mmc_host_ops jz4740_mmc_ops = { .enable_sdio_irq = jz4740_mmc_enable_sdio_irq, }; -static int jz4740_mmc_request_gpios(struct jz4740_mmc_host *host, - struct mmc_host *mmc, - struct platform_device *pdev) -{ - struct jz4740_mmc_platform_data *pdata = dev_get_platdata(&pdev->dev); - int ret = 0; - - if (!pdata) - return 0; - - if (!pdata->card_detect_active_low) - mmc->caps2 |= MMC_CAP2_CD_ACTIVE_HIGH; - if (!pdata->read_only_active_low) - mmc->caps2 |= MMC_CAP2_RO_ACTIVE_HIGH; - - /* - * Get optional card detect and write protect GPIOs, - * only back out on probe deferral. - */ - ret = mmc_gpiod_request_cd(mmc, "cd", 0, false, 0, NULL); - if (ret == -EPROBE_DEFER) - return ret; - - ret = mmc_gpiod_request_ro(mmc, "wp", 0, false, 0, NULL); - if (ret == -EPROBE_DEFER) - return ret; - - host->power = devm_gpiod_get_optional(&pdev->dev, "power", - GPIOD_OUT_HIGH); - return PTR_ERR_OR_ZERO(host->power); -} - static const struct of_device_id jz4740_mmc_of_match[] = { { .compatible = "ingenic,jz4740-mmc", .data = (void *) JZ_MMC_JZ4740 }, { .compatible = "ingenic,jz4725b-mmc", .data = (void *)JZ_MMC_JZ4725B }, @@ -982,9 +948,6 @@ static int jz4740_mmc_probe(struct platform_device* pdev) struct mmc_host *mmc; struct jz4740_mmc_host *host; const struct of_device_id *match; - struct jz4740_mmc_platform_data *pdata; - - pdata = dev_get_platdata(&pdev->dev); mmc = mmc_alloc_host(sizeof(struct jz4740_mmc_host), &pdev->dev); if (!mmc) { @@ -993,29 +956,25 @@ static int jz4740_mmc_probe(struct platform_device* pdev) } host = mmc_priv(mmc); - host->pdata = pdata; match = of_match_device(jz4740_mmc_of_match, &pdev->dev); if (match) { host->version = (enum jz4740_mmc_version)match->data; - ret = mmc_of_parse(mmc); - if (ret) { - if (ret != -EPROBE_DEFER) - dev_err(&pdev->dev, - "could not parse of data: %d\n", ret); - goto err_free_host; - } } else { /* JZ4740 should be the only one using legacy probe */ host->version = JZ_MMC_JZ4740; - mmc->caps |= MMC_CAP_SDIO_IRQ; - if (!(pdata && pdata->data_1bit)) - mmc->caps |= MMC_CAP_4_BIT_DATA; - ret = jz4740_mmc_request_gpios(host, mmc, pdev); - if (ret) - goto err_free_host; } + ret = mmc_of_parse(mmc); + if (ret) { + if (ret != -EPROBE_DEFER) + dev_err(&pdev->dev, + "could not parse device properties: %d\n", ret); + goto err_free_host; + } + + mmc_regulator_get_supply(mmc); + host->irq = platform_get_irq(pdev, 0); if (host->irq < 0) { ret = host->irq; diff --git a/drivers/mmc/host/meson-gx-mmc.c b/drivers/mmc/host/meson-gx-mmc.c index f19ec60bcbdc..c5a8af4ca76b 100644 --- a/drivers/mmc/host/meson-gx-mmc.c +++ b/drivers/mmc/host/meson-gx-mmc.c @@ -23,6 +23,7 @@ #include <linux/init.h> #include <linux/delay.h> #include <linux/device.h> +#include <linux/iopoll.h> #include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/ioport.h> @@ -48,6 +49,8 @@ #define CLK_CORE_PHASE_MASK GENMASK(9, 8) #define CLK_TX_PHASE_MASK GENMASK(11, 10) #define CLK_RX_PHASE_MASK GENMASK(13, 12) +#define CLK_PHASE_0 0 +#define CLK_PHASE_180 2 #define CLK_V2_TX_DELAY_MASK GENMASK(19, 16) #define CLK_V2_RX_DELAY_MASK GENMASK(23, 20) #define CLK_V2_ALWAYS_ON BIT(24) @@ -56,10 +59,6 @@ #define CLK_V3_RX_DELAY_MASK GENMASK(27, 22) #define CLK_V3_ALWAYS_ON BIT(28) -#define CLK_DELAY_STEP_PS 200 -#define CLK_PHASE_STEP 30 -#define CLK_PHASE_POINT_NUM (360 / CLK_PHASE_STEP) - #define CLK_TX_DELAY_MASK(h) (h->data->tx_delay_mask) #define CLK_RX_DELAY_MASK(h) (h->data->rx_delay_mask) #define CLK_ALWAYS_ON(h) (h->data->always_on) @@ -164,10 +163,10 @@ struct meson_host { void __iomem *regs; struct clk *core_clk; + struct clk *mux_clk; struct clk *mmc_clk; - struct clk *rx_clk; - struct clk *tx_clk; unsigned long req_rate; + bool ddr; struct pinctrl *pinctrl; struct pinctrl_state *pins_default; @@ -207,90 +206,6 @@ struct meson_host { #define CMD_RESP_MASK GENMASK(31, 1) #define CMD_RESP_SRAM BIT(0) -struct meson_mmc_phase { - struct clk_hw hw; - void __iomem *reg; - unsigned long phase_mask; - unsigned long delay_mask; - unsigned int delay_step_ps; -}; - -#define to_meson_mmc_phase(_hw) container_of(_hw, struct meson_mmc_phase, hw) - -static int meson_mmc_clk_get_phase(struct clk_hw *hw) -{ - struct meson_mmc_phase *mmc = to_meson_mmc_phase(hw); - unsigned int phase_num = 1 << hweight_long(mmc->phase_mask); - unsigned long period_ps, p, d; - int degrees; - u32 val; - - val = readl(mmc->reg); - p = (val & mmc->phase_mask) >> __ffs(mmc->phase_mask); - degrees = p * 360 / phase_num; - - if (mmc->delay_mask) { - period_ps = DIV_ROUND_UP((unsigned long)NSEC_PER_SEC * 1000, - clk_get_rate(hw->clk)); - d = (val & mmc->delay_mask) >> __ffs(mmc->delay_mask); - degrees += d * mmc->delay_step_ps * 360 / period_ps; - degrees %= 360; - } - - return degrees; -} - -static void meson_mmc_apply_phase_delay(struct meson_mmc_phase *mmc, - unsigned int phase, - unsigned int delay) -{ - u32 val; - - val = readl(mmc->reg); - val &= ~mmc->phase_mask; - val |= phase << __ffs(mmc->phase_mask); - - if (mmc->delay_mask) { - val &= ~mmc->delay_mask; - val |= delay << __ffs(mmc->delay_mask); - } - - writel(val, mmc->reg); -} - -static int meson_mmc_clk_set_phase(struct clk_hw *hw, int degrees) -{ - struct meson_mmc_phase *mmc = to_meson_mmc_phase(hw); - unsigned int phase_num = 1 << hweight_long(mmc->phase_mask); - unsigned long period_ps, d = 0, r; - uint64_t p; - - p = degrees % 360; - - if (!mmc->delay_mask) { - p = DIV_ROUND_CLOSEST_ULL(p, 360 / phase_num); - } else { - period_ps = DIV_ROUND_UP((unsigned long)NSEC_PER_SEC * 1000, - clk_get_rate(hw->clk)); - - /* First compute the phase index (p), the remainder (r) is the - * part we'll try to acheive using the delays (d). - */ - r = do_div(p, 360 / phase_num); - d = DIV_ROUND_CLOSEST(r * period_ps, - 360 * mmc->delay_step_ps); - d = min(d, mmc->delay_mask >> __ffs(mmc->delay_mask)); - } - - meson_mmc_apply_phase_delay(mmc, p, d); - return 0; -} - -static const struct clk_ops meson_mmc_clk_phase_ops = { - .get_phase = meson_mmc_clk_get_phase, - .set_phase = meson_mmc_clk_set_phase, -}; - static unsigned int meson_mmc_get_timeout_msecs(struct mmc_data *data) { unsigned int timeout = data->timeout_ns / NSEC_PER_MSEC; @@ -383,16 +298,6 @@ static void meson_mmc_post_req(struct mmc_host *mmc, struct mmc_request *mrq, mmc_get_dma_dir(data)); } -static bool meson_mmc_timing_is_ddr(struct mmc_ios *ios) -{ - if (ios->timing == MMC_TIMING_MMC_DDR52 || - ios->timing == MMC_TIMING_UHS_DDR50 || - ios->timing == MMC_TIMING_MMC_HS400) - return true; - - return false; -} - /* * Gating the clock on this controller is tricky. It seems the mmc clock * is also used by the controller. It may crash during some operation if the @@ -429,36 +334,41 @@ static void meson_mmc_clk_ungate(struct meson_host *host) writel(cfg, host->regs + SD_EMMC_CFG); } -static int meson_mmc_clk_set(struct meson_host *host, struct mmc_ios *ios) +static int meson_mmc_clk_set(struct meson_host *host, unsigned long rate, + bool ddr) { struct mmc_host *mmc = host->mmc; - unsigned long rate = ios->clock; int ret; u32 cfg; - /* DDR modes require higher module clock */ - if (meson_mmc_timing_is_ddr(ios)) - rate <<= 1; - /* Same request - bail-out */ - if (host->req_rate == rate) + if (host->ddr == ddr && host->req_rate == rate) return 0; /* stop clock */ meson_mmc_clk_gate(host); host->req_rate = 0; + mmc->actual_clock = 0; - if (!rate) { - mmc->actual_clock = 0; - /* return with clock being stopped */ + /* return with clock being stopped */ + if (!rate) return 0; - } /* Stop the clock during rate change to avoid glitches */ cfg = readl(host->regs + SD_EMMC_CFG); cfg |= CFG_STOP_CLOCK; writel(cfg, host->regs + SD_EMMC_CFG); + if (ddr) { + /* DDR modes require higher module clock */ + rate <<= 1; + cfg |= CFG_DDR; + } else { + cfg &= ~CFG_DDR; + } + writel(cfg, host->regs + SD_EMMC_CFG); + host->ddr = ddr; + ret = clk_set_rate(host->mmc_clk, rate); if (ret) { dev_err(host->dev, "Unable to set cfg_div_clk to %lu. ret=%d\n", @@ -470,12 +380,14 @@ static int meson_mmc_clk_set(struct meson_host *host, struct mmc_ios *ios) mmc->actual_clock = clk_get_rate(host->mmc_clk); /* We should report the real output frequency of the controller */ - if (meson_mmc_timing_is_ddr(ios)) + if (ddr) { + host->req_rate >>= 1; mmc->actual_clock >>= 1; + } dev_dbg(host->dev, "clk rate: %u Hz\n", mmc->actual_clock); - if (ios->clock != mmc->actual_clock) - dev_dbg(host->dev, "requested rate was %u\n", ios->clock); + if (rate != mmc->actual_clock) + dev_dbg(host->dev, "requested rate was %lu\n", rate); /* (re)start clock */ meson_mmc_clk_ungate(host); @@ -493,8 +405,6 @@ static int meson_mmc_clk_init(struct meson_host *host) struct clk_init_data init; struct clk_mux *mux; struct clk_divider *div; - struct meson_mmc_phase *core, *tx, *rx; - struct clk *clk; char clk_name[32]; int i, ret = 0; const char *mux_parent_names[MUX_CLK_NUM_PARENTS]; @@ -502,9 +412,11 @@ static int meson_mmc_clk_init(struct meson_host *host) u32 clk_reg; /* init SD_EMMC_CLOCK to sane defaults w/min clock rate */ - clk_reg = 0; - clk_reg |= CLK_ALWAYS_ON(host); + clk_reg = CLK_ALWAYS_ON(host); clk_reg |= CLK_DIV_MASK; + clk_reg |= FIELD_PREP(CLK_CORE_PHASE_MASK, CLK_PHASE_180); + clk_reg |= FIELD_PREP(CLK_TX_PHASE_MASK, CLK_PHASE_0); + clk_reg |= FIELD_PREP(CLK_RX_PHASE_MASK, CLK_PHASE_0); writel(clk_reg, host->regs + SD_EMMC_CLOCK); /* get the mux parents */ @@ -540,9 +452,9 @@ static int meson_mmc_clk_init(struct meson_host *host) mux->mask = CLK_SRC_MASK >> mux->shift; mux->hw.init = &init; - clk = devm_clk_register(host->dev, &mux->hw); - if (WARN_ON(IS_ERR(clk))) - return PTR_ERR(clk); + host->mux_clk = devm_clk_register(host->dev, &mux->hw); + if (WARN_ON(IS_ERR(host->mux_clk))) + return PTR_ERR(host->mux_clk); /* create the divider */ div = devm_kzalloc(host->dev, sizeof(*div), GFP_KERNEL); @@ -553,7 +465,7 @@ static int meson_mmc_clk_init(struct meson_host *host) init.name = clk_name; init.ops = &clk_divider_ops; init.flags = CLK_SET_RATE_PARENT; - clk_parent[0] = __clk_get_name(clk); + clk_parent[0] = __clk_get_name(host->mux_clk); init.parent_names = clk_parent; init.num_parents = 1; @@ -563,190 +475,104 @@ static int meson_mmc_clk_init(struct meson_host *host) div->hw.init = &init; div->flags = CLK_DIVIDER_ONE_BASED; - clk = devm_clk_register(host->dev, &div->hw); - if (WARN_ON(IS_ERR(clk))) - return PTR_ERR(clk); - - /* create the mmc core clock */ - core = devm_kzalloc(host->dev, sizeof(*core), GFP_KERNEL); - if (!core) - return -ENOMEM; - - snprintf(clk_name, sizeof(clk_name), "%s#core", dev_name(host->dev)); - init.name = clk_name; - init.ops = &meson_mmc_clk_phase_ops; - init.flags = CLK_SET_RATE_PARENT; - clk_parent[0] = __clk_get_name(clk); - init.parent_names = clk_parent; - init.num_parents = 1; - - core->reg = host->regs + SD_EMMC_CLOCK; - core->phase_mask = CLK_CORE_PHASE_MASK; - core->hw.init = &init; - - host->mmc_clk = devm_clk_register(host->dev, &core->hw); - if (WARN_ON(PTR_ERR_OR_ZERO(host->mmc_clk))) + host->mmc_clk = devm_clk_register(host->dev, &div->hw); + if (WARN_ON(IS_ERR(host->mmc_clk))) return PTR_ERR(host->mmc_clk); - /* create the mmc tx clock */ - tx = devm_kzalloc(host->dev, sizeof(*tx), GFP_KERNEL); - if (!tx) - return -ENOMEM; - - snprintf(clk_name, sizeof(clk_name), "%s#tx", dev_name(host->dev)); - init.name = clk_name; - init.ops = &meson_mmc_clk_phase_ops; - init.flags = 0; - clk_parent[0] = __clk_get_name(host->mmc_clk); - init.parent_names = clk_parent; - init.num_parents = 1; - - tx->reg = host->regs + SD_EMMC_CLOCK; - tx->phase_mask = CLK_TX_PHASE_MASK; - tx->delay_mask = CLK_TX_DELAY_MASK(host); - tx->delay_step_ps = CLK_DELAY_STEP_PS; - tx->hw.init = &init; - - host->tx_clk = devm_clk_register(host->dev, &tx->hw); - if (WARN_ON(PTR_ERR_OR_ZERO(host->tx_clk))) - return PTR_ERR(host->tx_clk); - - /* create the mmc rx clock */ - rx = devm_kzalloc(host->dev, sizeof(*rx), GFP_KERNEL); - if (!rx) - return -ENOMEM; - - snprintf(clk_name, sizeof(clk_name), "%s#rx", dev_name(host->dev)); - init.name = clk_name; - init.ops = &meson_mmc_clk_phase_ops; - init.flags = 0; - clk_parent[0] = __clk_get_name(host->mmc_clk); - init.parent_names = clk_parent; - init.num_parents = 1; - - rx->reg = host->regs + SD_EMMC_CLOCK; - rx->phase_mask = CLK_RX_PHASE_MASK; - rx->delay_mask = CLK_RX_DELAY_MASK(host); - rx->delay_step_ps = CLK_DELAY_STEP_PS; - rx->hw.init = &init; - - host->rx_clk = devm_clk_register(host->dev, &rx->hw); - if (WARN_ON(PTR_ERR_OR_ZERO(host->rx_clk))) - return PTR_ERR(host->rx_clk); - /* init SD_EMMC_CLOCK to sane defaults w/min clock rate */ host->mmc->f_min = clk_round_rate(host->mmc_clk, 400000); ret = clk_set_rate(host->mmc_clk, host->mmc->f_min); if (ret) return ret; - clk_set_phase(host->mmc_clk, 180); - clk_set_phase(host->tx_clk, 0); - clk_set_phase(host->rx_clk, 0); - return clk_prepare_enable(host->mmc_clk); } -static void meson_mmc_shift_map(unsigned long *map, unsigned long shift) +static void meson_mmc_disable_resampling(struct meson_host *host) { - DECLARE_BITMAP(left, CLK_PHASE_POINT_NUM); - DECLARE_BITMAP(right, CLK_PHASE_POINT_NUM); + unsigned int val = readl(host->regs + host->data->adjust); - /* - * shift the bitmap right and reintroduce the dropped bits on the left - * of the bitmap - */ - bitmap_shift_right(right, map, shift, CLK_PHASE_POINT_NUM); - bitmap_shift_left(left, map, CLK_PHASE_POINT_NUM - shift, - CLK_PHASE_POINT_NUM); - bitmap_or(map, left, right, CLK_PHASE_POINT_NUM); + val &= ~ADJUST_ADJ_EN; + writel(val, host->regs + host->data->adjust); } -static void meson_mmc_find_next_region(unsigned long *map, - unsigned long *start, - unsigned long *stop) +static void meson_mmc_reset_resampling(struct meson_host *host) { - *start = find_next_bit(map, CLK_PHASE_POINT_NUM, *start); - *stop = find_next_zero_bit(map, CLK_PHASE_POINT_NUM, *start); + unsigned int val; + + meson_mmc_disable_resampling(host); + + val = readl(host->regs + host->data->adjust); + val &= ~ADJUST_ADJ_DELAY_MASK; + writel(val, host->regs + host->data->adjust); } -static int meson_mmc_find_tuning_point(unsigned long *test) +static int meson_mmc_resampling_tuning(struct mmc_host *mmc, u32 opcode) { - unsigned long shift, stop, offset = 0, start = 0, size = 0; + struct meson_host *host = mmc_priv(mmc); + unsigned int val, dly, max_dly, i; + int ret; - /* Get the all good/all bad situation out the way */ - if (bitmap_full(test, CLK_PHASE_POINT_NUM)) - return 0; /* All points are good so point 0 will do */ - else if (bitmap_empty(test, CLK_PHASE_POINT_NUM)) - return -EIO; /* No successful tuning point */ + /* Resampling is done using the source clock */ + max_dly = DIV_ROUND_UP(clk_get_rate(host->mux_clk), + clk_get_rate(host->mmc_clk)); - /* - * Now we know there is a least one region find. Make sure it does - * not wrap by the shifting the bitmap if necessary - */ - shift = find_first_zero_bit(test, CLK_PHASE_POINT_NUM); - if (shift != 0) - meson_mmc_shift_map(test, shift); + val = readl(host->regs + host->data->adjust); + val |= ADJUST_ADJ_EN; + writel(val, host->regs + host->data->adjust); - while (start < CLK_PHASE_POINT_NUM) { - meson_mmc_find_next_region(test, &start, &stop); + if (mmc->doing_retune) + dly = FIELD_GET(ADJUST_ADJ_DELAY_MASK, val) + 1; + else + dly = 0; - if ((stop - start) > size) { - offset = start; - size = stop - start; - } + for (i = 0; i < max_dly; i++) { + val &= ~ADJUST_ADJ_DELAY_MASK; + val |= FIELD_PREP(ADJUST_ADJ_DELAY_MASK, (dly + i) % max_dly); + writel(val, host->regs + host->data->adjust); - start = stop; + ret = mmc_send_tuning(mmc, opcode, NULL); + if (!ret) { + dev_dbg(mmc_dev(mmc), "resampling delay: %u\n", + (dly + i) % max_dly); + return 0; + } } - /* Get the center point of the region */ - offset += (size / 2); - - /* Shift the result back */ - offset = (offset + shift) % CLK_PHASE_POINT_NUM; - - return offset; + meson_mmc_reset_resampling(host); + return -EIO; } -static int meson_mmc_clk_phase_tuning(struct mmc_host *mmc, u32 opcode, - struct clk *clk) +static int meson_mmc_prepare_ios_clock(struct meson_host *host, + struct mmc_ios *ios) { - int point, ret; - DECLARE_BITMAP(test, CLK_PHASE_POINT_NUM); + bool ddr; - dev_dbg(mmc_dev(mmc), "%s phase/delay tunning...\n", - __clk_get_name(clk)); - bitmap_zero(test, CLK_PHASE_POINT_NUM); + switch (ios->timing) { + case MMC_TIMING_MMC_DDR52: + case MMC_TIMING_UHS_DDR50: + ddr = true; + break; - /* Explore tuning points */ - for (point = 0; point < CLK_PHASE_POINT_NUM; point++) { - clk_set_phase(clk, point * CLK_PHASE_STEP); - ret = mmc_send_tuning(mmc, opcode, NULL); - if (!ret) - set_bit(point, test); + default: + ddr = false; + break; } - /* Find the optimal tuning point and apply it */ - point = meson_mmc_find_tuning_point(test); - if (point < 0) - return point; /* tuning failed */ - - clk_set_phase(clk, point * CLK_PHASE_STEP); - dev_dbg(mmc_dev(mmc), "success with phase: %d\n", - clk_get_phase(clk)); - return 0; + return meson_mmc_clk_set(host, ios->clock, ddr); } -static int meson_mmc_execute_tuning(struct mmc_host *mmc, u32 opcode) +static void meson_mmc_check_resampling(struct meson_host *host, + struct mmc_ios *ios) { - struct meson_host *host = mmc_priv(mmc); - int adj = 0; - - /* enable signal resampling w/o delay */ - adj = ADJUST_ADJ_EN; - writel(adj, host->regs + host->data->adjust); - - return meson_mmc_clk_phase_tuning(mmc, opcode, host->rx_clk); + switch (ios->timing) { + case MMC_TIMING_LEGACY: + case MMC_TIMING_MMC_HS: + case MMC_TIMING_SD_HS: + case MMC_TIMING_MMC_DDR52: + meson_mmc_disable_resampling(host); + break; + } } static void meson_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) @@ -775,12 +601,6 @@ static void meson_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) if (!IS_ERR(mmc->supply.vmmc)) mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, ios->vdd); - /* disable signal resampling */ - writel(0, host->regs + host->data->adjust); - - /* Reset rx phase */ - clk_set_phase(host->rx_clk, 0); - break; case MMC_POWER_ON: @@ -817,20 +637,13 @@ static void meson_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) val = readl(host->regs + SD_EMMC_CFG); val &= ~CFG_BUS_WIDTH_MASK; val |= FIELD_PREP(CFG_BUS_WIDTH_MASK, bus_width); + writel(val, host->regs + SD_EMMC_CFG); - val &= ~CFG_DDR; - if (meson_mmc_timing_is_ddr(ios)) - val |= CFG_DDR; - - val &= ~CFG_CHK_DS; - if (ios->timing == MMC_TIMING_MMC_HS400) - val |= CFG_CHK_DS; - - err = meson_mmc_clk_set(host, ios); + meson_mmc_check_resampling(host, ios); + err = meson_mmc_prepare_ios_clock(host, ios); if (err) dev_err(host->dev, "Failed to set clock: %d\n,", err); - writel(val, host->regs + SD_EMMC_CFG); dev_dbg(host->dev, "SD_EMMC_CFG: 0x%08x\n", val); } @@ -1081,9 +894,6 @@ static irqreturn_t meson_mmc_irq(int irq, void *dev_id) } out: - /* ack all enabled interrupts */ - writel(irq_en, host->regs + SD_EMMC_STATUS); - if (cmd->error) { /* Stop desc in case of errors */ u32 start = readl(host->regs + SD_EMMC_START); @@ -1095,12 +905,14 @@ out: if (ret == IRQ_HANDLED) meson_mmc_request_done(host->mmc, cmd->mrq); + /* ack all raised interrupts */ + writel(status, host->regs + SD_EMMC_STATUS); + return ret; } static int meson_mmc_wait_desc_stop(struct meson_host *host) { - int loop; u32 status; /* @@ -1110,20 +922,10 @@ static int meson_mmc_wait_desc_stop(struct meson_host *host) * If we don't confirm the descriptor is stopped, it might raise new * IRQs after we have called mmc_request_done() which is bad. */ - for (loop = 50; loop; loop--) { - status = readl(host->regs + SD_EMMC_STATUS); - if (status & (STATUS_BUSY | STATUS_DESC_BUSY)) - udelay(100); - else - break; - } - - if (status & (STATUS_BUSY | STATUS_DESC_BUSY)) { - dev_err(host->dev, "Timed out waiting for host to stop\n"); - return -ETIMEDOUT; - } - return 0; + return readl_poll_timeout(host->regs + SD_EMMC_STATUS, status, + !(status & (STATUS_BUSY | STATUS_DESC_BUSY)), + 100, 5000); } static irqreturn_t meson_mmc_irq_thread(int irq, void *dev_id) @@ -1227,7 +1029,7 @@ static const struct mmc_host_ops meson_mmc_ops = { .get_cd = meson_mmc_get_cd, .pre_req = meson_mmc_pre_req, .post_req = meson_mmc_post_req, - .execute_tuning = meson_mmc_execute_tuning, + .execute_tuning = meson_mmc_resampling_tuning, .card_busy = meson_mmc_card_busy, .start_signal_voltage_switch = meson_mmc_voltage_switch, }; @@ -1338,7 +1140,8 @@ static int meson_mmc_probe(struct platform_device *pdev) host->regs + SD_EMMC_IRQ_EN); ret = request_threaded_irq(host->irq, meson_mmc_irq, - meson_mmc_irq_thread, IRQF_SHARED, NULL, host); + meson_mmc_irq_thread, IRQF_ONESHOT, + dev_name(&pdev->dev), host); if (ret) goto err_init_clk; @@ -1348,6 +1151,13 @@ static int meson_mmc_probe(struct platform_device *pdev) mmc->max_segs = SD_EMMC_DESC_BUF_LEN / sizeof(struct sd_emmc_desc); mmc->max_seg_size = mmc->max_req_size; + /* + * At the moment, we don't know how to reliably enable HS400. + * From the different datasheets, it is not even clear if this mode + * is officially supported by any of the SoCs + */ + mmc->caps2 &= ~MMC_CAP2_HS400; + /* data bounce buffer */ host->bounce_buf_size = mmc->max_req_size; host->bounce_buf = diff --git a/drivers/mmc/host/mmc_spi.c b/drivers/mmc/host/mmc_spi.c index 10ba46b728e8..19544b121276 100644 --- a/drivers/mmc/host/mmc_spi.c +++ b/drivers/mmc/host/mmc_spi.c @@ -1,5 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * mmc_spi.c - Access SD/MMC cards through SPI master controllers + * Access SD/MMC cards through SPI master controllers * * (C) Copyright 2005, Intec Automation, * Mike Lavender (mike@steroidmicros) @@ -8,21 +9,6 @@ * Hans-Peter Nilsson (hp@axis.com) * (C) Copyright 2007, ATRON electronic GmbH, * Jan Nikitenko <jan.nikitenko@gmail.com> - * - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <linux/sched.h> #include <linux/delay.h> @@ -197,7 +183,7 @@ mmc_spi_readbytes(struct mmc_spi_host *host, unsigned len) static int mmc_spi_skip(struct mmc_spi_host *host, unsigned long timeout, unsigned n, u8 byte) { - u8 *cp = host->data->status; + u8 *cp = host->data->status; unsigned long start = jiffies; while (1) { @@ -220,7 +206,7 @@ static int mmc_spi_skip(struct mmc_spi_host *host, unsigned long timeout, * We use jiffies here because we want to have a relation * between elapsed time and the blocking of the scheduler. */ - if (time_is_before_jiffies(start+1)) + if (time_is_before_jiffies(start + 1)) schedule(); } return -ETIMEDOUT; @@ -415,7 +401,7 @@ checkstatus: default: dev_dbg(&host->spi->dev, "bad response type %04x\n", - mmc_spi_resp_type(cmd)); + mmc_spi_resp_type(cmd)); if (value >= 0) value = -EINVAL; goto done; @@ -467,8 +453,8 @@ mmc_spi_command_send(struct mmc_spi_host *host, memset(cp, 0xff, sizeof(data->status)); cp[1] = 0x40 | cmd->opcode; - put_unaligned_be32(cmd->arg, cp+2); - cp[6] = crc7_be(0, cp+1, 5) | 0x01; + put_unaligned_be32(cmd->arg, cp + 2); + cp[6] = crc7_be(0, cp + 1, 5) | 0x01; cp += 7; /* Then, read up to 13 bytes (while writing all-ones): @@ -642,9 +628,7 @@ mmc_spi_setup_data_message( if (multiple || direction == DMA_TO_DEVICE) { t = &host->early_status; memset(t, 0, sizeof(*t)); - t->len = (direction == DMA_TO_DEVICE) - ? sizeof(scratch->status) - : 1; + t->len = (direction == DMA_TO_DEVICE) ? sizeof(scratch->status) : 1; t->tx_buf = host->ones; t->tx_dma = host->ones_dma; t->rx_buf = scratch->status; @@ -677,8 +661,7 @@ mmc_spi_writeblock(struct mmc_spi_host *host, struct spi_transfer *t, u32 pattern; if (host->mmc->use_spi_crc) - scratch->crc_val = cpu_to_be16( - crc_itu_t(0, t->tx_buf, t->len)); + scratch->crc_val = cpu_to_be16(crc_itu_t(0, t->tx_buf, t->len)); if (host->dma_dev) dma_sync_single_for_device(host->dma_dev, host->data_dma, sizeof(*scratch), @@ -819,6 +802,10 @@ mmc_spi_readblock(struct mmc_spi_host *host, struct spi_transfer *t, } status = spi_sync_locked(spi, &host->m); + if (status < 0) { + dev_dbg(&spi->dev, "read error %d\n", status); + return status; + } if (host->dma_dev) { dma_sync_single_for_cpu(host->dma_dev, @@ -855,9 +842,9 @@ mmc_spi_readblock(struct mmc_spi_host *host, struct spi_transfer *t, be16_to_cpus(&scratch->crc_val); if (scratch->crc_val != crc) { - dev_dbg(&spi->dev, "read - crc error: crc_val=0x%04x, " - "computed=0x%04x len=%d\n", - scratch->crc_val, crc, t->len); + dev_dbg(&spi->dev, + "read - crc error: crc_val=0x%04x, computed=0x%04x len=%d\n", + scratch->crc_val, crc, t->len); return -EILSEQ; } } @@ -945,9 +932,7 @@ mmc_spi_data_do(struct mmc_spi_host *host, struct mmc_command *cmd, dev_dbg(&host->spi->dev, " mmc_spi: %s block, %d bytes\n", - (direction == DMA_TO_DEVICE) - ? "write" - : "read", + (direction == DMA_TO_DEVICE) ? "write" : "read", t->len); if (direction == DMA_TO_DEVICE) @@ -974,8 +959,7 @@ mmc_spi_data_do(struct mmc_spi_host *host, struct mmc_command *cmd, if (status < 0) { data->error = status; dev_dbg(&spi->dev, "%s status %d\n", - (direction == DMA_TO_DEVICE) - ? "write" : "read", + (direction == DMA_TO_DEVICE) ? "write" : "read", status); break; } @@ -1249,8 +1233,7 @@ static void mmc_spi_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) mres = spi_setup(host->spi); if (mres < 0) dev_dbg(&host->spi->dev, - "switch back to SPI mode 3" - " failed\n"); + "switch back to SPI mode 3 failed\n"); } } @@ -1450,9 +1433,10 @@ static int mmc_spi_probe(struct spi_device *spi) mmc->caps &= ~MMC_CAP_NEEDS_POLL; mmc_gpiod_request_cd_irq(mmc); } + mmc_detect_change(mmc, 0); /* Index 1 is write protect/read only */ - status = mmc_gpiod_request_ro(mmc, NULL, 1, false, 0, NULL); + status = mmc_gpiod_request_ro(mmc, NULL, 1, 0, NULL); if (status == -EPROBE_DEFER) goto fail_add_host; if (!status) @@ -1469,7 +1453,7 @@ static int mmc_spi_probe(struct spi_device *spi) return 0; fail_add_host: - mmc_remove_host (mmc); + mmc_remove_host(mmc); fail_glue_init: if (host->dma_dev) dma_unmap_single(host->dma_dev, host->data_dma, @@ -1484,7 +1468,6 @@ fail_ones_dma: fail_nobuf1: mmc_free_host(mmc); mmc_spi_put_pdata(spi); - dev_set_drvdata(&spi->dev, NULL); nomem: kfree(ones); @@ -1495,32 +1478,27 @@ nomem: static int mmc_spi_remove(struct spi_device *spi) { struct mmc_host *mmc = dev_get_drvdata(&spi->dev); - struct mmc_spi_host *host; - - if (mmc) { - host = mmc_priv(mmc); + struct mmc_spi_host *host = mmc_priv(mmc); - /* prevent new mmc_detect_change() calls */ - if (host->pdata && host->pdata->exit) - host->pdata->exit(&spi->dev, mmc); + /* prevent new mmc_detect_change() calls */ + if (host->pdata && host->pdata->exit) + host->pdata->exit(&spi->dev, mmc); - mmc_remove_host(mmc); + mmc_remove_host(mmc); - if (host->dma_dev) { - dma_unmap_single(host->dma_dev, host->ones_dma, - MMC_SPI_BLOCKSIZE, DMA_TO_DEVICE); - dma_unmap_single(host->dma_dev, host->data_dma, - sizeof(*host->data), DMA_BIDIRECTIONAL); - } + if (host->dma_dev) { + dma_unmap_single(host->dma_dev, host->ones_dma, + MMC_SPI_BLOCKSIZE, DMA_TO_DEVICE); + dma_unmap_single(host->dma_dev, host->data_dma, + sizeof(*host->data), DMA_BIDIRECTIONAL); + } - kfree(host->data); - kfree(host->ones); + kfree(host->data); + kfree(host->ones); - spi->max_speed_hz = mmc->f_max; - mmc_free_host(mmc); - mmc_spi_put_pdata(spi); - dev_set_drvdata(&spi->dev, NULL); - } + spi->max_speed_hz = mmc->f_max; + mmc_free_host(mmc); + mmc_spi_put_pdata(spi); return 0; } @@ -1541,8 +1519,7 @@ static struct spi_driver mmc_spi_driver = { module_spi_driver(mmc_spi_driver); -MODULE_AUTHOR("Mike Lavender, David Brownell, " - "Hans-Peter Nilsson, Jan Nikitenko"); +MODULE_AUTHOR("Mike Lavender, David Brownell, Hans-Peter Nilsson, Jan Nikitenko"); MODULE_DESCRIPTION("SPI SD/MMC host driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS("spi:mmc_spi"); diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index e352f5ad5801..356833a606d5 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -43,21 +43,11 @@ #include <asm/io.h> #include "mmci.h" -#include "mmci_qcom_dml.h" #define DRIVER_NAME "mmci-pl18x" -#ifdef CONFIG_DMA_ENGINE -void mmci_variant_init(struct mmci_host *host); -#else -static inline void mmci_variant_init(struct mmci_host *host) {} -#endif - -#ifdef CONFIG_MMC_STM32_SDMMC -void sdmmc_variant_init(struct mmci_host *host); -#else -static inline void sdmmc_variant_init(struct mmci_host *host) {} -#endif +static void mmci_variant_init(struct mmci_host *host); +static void ux500v2_variant_init(struct mmci_host *host); static unsigned int fmax = 515633; @@ -70,7 +60,6 @@ static struct variant_data variant_arm = { .cmdreg_srsp = MCI_CPSM_RESPONSE, .datalength_bits = 16, .datactrl_blocksz = 11, - .datactrl_dpsm_enable = MCI_DPSM_ENABLE, .pwrreg_powerup = MCI_PWR_UP, .f_max = 100000000, .reversed_irq_handling = true, @@ -90,7 +79,6 @@ static struct variant_data variant_arm_extended_fifo = { .cmdreg_srsp = MCI_CPSM_RESPONSE, .datalength_bits = 16, .datactrl_blocksz = 11, - .datactrl_dpsm_enable = MCI_DPSM_ENABLE, .pwrreg_powerup = MCI_PWR_UP, .f_max = 100000000, .mmcimask1 = true, @@ -110,7 +98,6 @@ static struct variant_data variant_arm_extended_fifo_hwfc = { .cmdreg_srsp = MCI_CPSM_RESPONSE, .datalength_bits = 16, .datactrl_blocksz = 11, - .datactrl_dpsm_enable = MCI_DPSM_ENABLE, .pwrreg_powerup = MCI_PWR_UP, .f_max = 100000000, .mmcimask1 = true, @@ -131,7 +118,6 @@ static struct variant_data variant_u300 = { .cmdreg_srsp = MCI_CPSM_RESPONSE, .datalength_bits = 16, .datactrl_blocksz = 11, - .datactrl_dpsm_enable = MCI_DPSM_ENABLE, .datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN, .st_sdio = true, .pwrreg_powerup = MCI_PWR_ON, @@ -157,7 +143,6 @@ static struct variant_data variant_nomadik = { .cmdreg_srsp = MCI_CPSM_RESPONSE, .datalength_bits = 24, .datactrl_blocksz = 11, - .datactrl_dpsm_enable = MCI_DPSM_ENABLE, .datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN, .st_sdio = true, .st_clkdiv = true, @@ -186,7 +171,6 @@ static struct variant_data variant_ux500 = { .cmdreg_srsp = MCI_CPSM_RESPONSE, .datalength_bits = 24, .datactrl_blocksz = 11, - .datactrl_dpsm_enable = MCI_DPSM_ENABLE, .datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN, .st_sdio = true, .st_clkdiv = true, @@ -220,11 +204,9 @@ static struct variant_data variant_ux500v2 = { .datactrl_mask_ddrmode = MCI_DPSM_ST_DDRMODE, .datalength_bits = 24, .datactrl_blocksz = 11, - .datactrl_dpsm_enable = MCI_DPSM_ENABLE, .datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN, .st_sdio = true, .st_clkdiv = true, - .blksz_datactrl16 = true, .pwrreg_powerup = MCI_PWR_ON, .f_max = 100000000, .signal_direction = true, @@ -238,7 +220,7 @@ static struct variant_data variant_ux500v2 = { .irq_pio_mask = MCI_IRQ_PIO_MASK, .start_err = MCI_STARTBITERR, .opendrain = MCI_OD, - .init = mmci_variant_init, + .init = ux500v2_variant_init, }; static struct variant_data variant_stm32 = { @@ -255,7 +237,6 @@ static struct variant_data variant_stm32 = { .irq_pio_mask = MCI_IRQ_PIO_MASK, .datalength_bits = 24, .datactrl_blocksz = 11, - .datactrl_dpsm_enable = MCI_DPSM_ENABLE, .datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN, .st_sdio = true, .st_clkdiv = true, @@ -299,10 +280,8 @@ static struct variant_data variant_qcom = { .cmdreg_srsp_crc = MCI_CPSM_RESPONSE, .cmdreg_srsp = MCI_CPSM_RESPONSE, .data_cmd_enable = MCI_CPSM_QCOM_DATCMD, - .blksz_datactrl4 = true, .datalength_bits = 24, .datactrl_blocksz = 11, - .datactrl_dpsm_enable = MCI_DPSM_ENABLE, .pwrreg_powerup = MCI_PWR_UP, .f_max = 208000000, .explicit_mclk_control = true, @@ -624,6 +603,16 @@ static void mmci_init_sg(struct mmci_host *host, struct mmc_data *data) sg_miter_start(&host->sg_miter, data->sg, data->sg_len, flags); } +static u32 mmci_get_dctrl_cfg(struct mmci_host *host) +{ + return MCI_DPSM_ENABLE | mmci_dctrl_blksz(host); +} + +static u32 ux500v2_get_dctrl_cfg(struct mmci_host *host) +{ + return MCI_DPSM_ENABLE | (host->data->blksz << 16); +} + /* * All the DMA operation mode stuff goes inside this ifdef. * This assumes that you have a generic DMA device interface, @@ -886,15 +875,11 @@ int mmci_dmae_prep_data(struct mmci_host *host, int mmci_dmae_start(struct mmci_host *host, unsigned int *datactrl) { struct mmci_dmae_priv *dmae = host->dma_priv; - struct mmc_data *data = host->data; host->dma_in_progress = true; dmaengine_submit(dmae->desc_current); dma_async_issue_pending(dmae->cur); - if (host->variant->qcom_dml) - dml_start_xfer(host, data); - *datactrl |= MCI_DPSM_DMAENABLE; return 0; @@ -952,6 +937,7 @@ void mmci_dmae_unprep_data(struct mmci_host *host, static struct mmci_host_ops mmci_variant_ops = { .prep_data = mmci_dmae_prep_data, .unprep_data = mmci_dmae_unprep_data, + .get_datactrl_cfg = mmci_get_dctrl_cfg, .get_next_data = mmci_dmae_get_next_data, .dma_setup = mmci_dmae_setup, .dma_release = mmci_dmae_release, @@ -959,12 +945,22 @@ static struct mmci_host_ops mmci_variant_ops = { .dma_finalize = mmci_dmae_finalize, .dma_error = mmci_dmae_error, }; +#else +static struct mmci_host_ops mmci_variant_ops = { + .get_datactrl_cfg = mmci_get_dctrl_cfg, +}; +#endif void mmci_variant_init(struct mmci_host *host) { host->ops = &mmci_variant_ops; } -#endif + +void ux500v2_variant_init(struct mmci_host *host) +{ + host->ops = &mmci_variant_ops; + host->ops->get_datactrl_cfg = ux500v2_get_dctrl_cfg; +} static void mmci_pre_request(struct mmc_host *mmc, struct mmc_request *mrq) { @@ -1000,7 +996,6 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data) unsigned int datactrl, timeout, irqmask; unsigned long long clks; void __iomem *base; - int blksz_bits; dev_dbg(mmc_dev(host->mmc), "blksz %04x blks %04x flags %08x\n", data->blksz, data->blocks, data->flags); @@ -1018,18 +1013,8 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data) writel(timeout, base + MMCIDATATIMER); writel(host->size, base + MMCIDATALENGTH); - blksz_bits = ffs(data->blksz) - 1; - BUG_ON(1 << blksz_bits != data->blksz); - - if (variant->blksz_datactrl16) - datactrl = variant->datactrl_dpsm_enable | (data->blksz << 16); - else if (variant->blksz_datactrl4) - datactrl = variant->datactrl_dpsm_enable | (data->blksz << 4); - else - datactrl = variant->datactrl_dpsm_enable | blksz_bits << 4; - - if (data->flags & MMC_DATA_READ) - datactrl |= MCI_DPSM_DIRECTION; + datactrl = host->ops->get_datactrl_cfg(host); + datactrl |= host->data->flags & MMC_DATA_READ ? MCI_DPSM_DIRECTION : 0; if (host->mmc->card && mmc_card_sdio(host->mmc->card)) { u32 clk; @@ -1127,6 +1112,12 @@ mmci_start_command(struct mmci_host *host, struct mmc_command *cmd, u32 c) writel(c, base + MMCICOMMAND); } +static void mmci_stop_command(struct mmci_host *host) +{ + host->stop_abort.error = 0; + mmci_start_command(host, &host->stop_abort, 0); +} + static void mmci_data_irq(struct mmci_host *host, struct mmc_data *data, unsigned int status) @@ -1196,10 +1187,16 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data, /* The error clause is handled above, success! */ data->bytes_xfered = data->blksz * data->blocks; - if (!data->stop || (host->mrq->sbc && !data->error)) + if (!data->stop) { + if (host->variant->cmdreg_stop && data->error) + mmci_stop_command(host); + else + mmci_request_end(host, data->mrq); + } else if (host->mrq->sbc && !data->error) { mmci_request_end(host, data->mrq); - else + } else { mmci_start_command(host, data->stop, 0); + } } } @@ -1208,12 +1205,13 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd, unsigned int status) { void __iomem *base = host->base; - bool sbc; + bool sbc, busy_resp; if (!cmd) return; sbc = (cmd == host->mrq->sbc); + busy_resp = !!(cmd->flags & MMC_RSP_BUSY); /* * We need to be one of these interrupts to be considered worth @@ -1227,8 +1225,7 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd, /* * ST Micro variant: handle busy detection. */ - if (host->variant->busy_detect) { - bool busy_resp = !!(cmd->flags & MMC_RSP_BUSY); + if (busy_resp && host->variant->busy_detect) { /* We are busy with a command, return */ if (host->busy_status && @@ -1241,7 +1238,7 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd, * that the special busy status bit is still set before * proceeding. */ - if (!host->busy_status && busy_resp && + if (!host->busy_status && !(status & (MCI_CMDCRCFAIL|MCI_CMDTIMEOUT)) && (readl(base + MMCISTATUS) & host->variant->busy_detect_flag)) { @@ -1298,6 +1295,10 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd, mmci_dma_error(host); mmci_stop_data(host); + if (host->variant->cmdreg_stop && cmd->error) { + mmci_stop_command(host); + return; + } } mmci_request_end(host, host->mrq); } else if (sbc) { @@ -1534,9 +1535,10 @@ static irqreturn_t mmci_irq(int irq, void *dev_id) } /* - * Don't poll for busy completion in irq context. + * Busy detection has been handled by mmci_cmd_irq() above. + * Clear the status bit to prevent polling in IRQ context. */ - if (host->variant->busy_detect && host->busy_status) + if (host->variant->busy_detect_flag) status &= ~host->variant->busy_detect_flag; ret = 1; @@ -1956,6 +1958,11 @@ static int mmci_probe(struct amba_device *dev, mmc->max_busy_timeout = 0; } + /* Prepare a CMD12 - needed to clear the DPSM on some variants. */ + host->stop_abort.opcode = MMC_STOP_TRANSMISSION; + host->stop_abort.arg = 0; + host->stop_abort.flags = MMC_RSP_R1B | MMC_CMD_AC; + mmc->ops = &mmci_ops; /* We support these PM capabilities. */ @@ -2011,7 +2018,7 @@ static int mmci_probe(struct amba_device *dev, if (ret == -EPROBE_DEFER) goto clk_disable; - ret = mmc_gpiod_request_ro(mmc, "wp", 0, false, 0, NULL); + ret = mmc_gpiod_request_ro(mmc, "wp", 0, 0, NULL); if (ret == -EPROBE_DEFER) goto clk_disable; } diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h index 24229097d05c..4f071bd34e59 100644 --- a/drivers/mmc/host/mmci.h +++ b/drivers/mmc/host/mmci.h @@ -131,6 +131,11 @@ /* Control register extensions in the Qualcomm versions */ #define MCI_DPSM_QCOM_DATA_PEND BIT(17) #define MCI_DPSM_QCOM_RX_DATA_PEND BIT(20) +/* Control register extensions in STM32 versions */ +#define MCI_DPSM_STM32_MODE_BLOCK (0 << 2) +#define MCI_DPSM_STM32_MODE_SDIO (1 << 2) +#define MCI_DPSM_STM32_MODE_STREAM (2 << 2) +#define MCI_DPSM_STM32_MODE_BLOCK_STOP (3 << 2) #define MMCIDATACNT 0x030 #define MMCISTATUS 0x034 @@ -275,12 +280,8 @@ struct mmci_host; * @st_clkdiv: true if using a ST-specific clock divider algorithm * @stm32_clkdiv: true if using a STM32-specific clock divider algorithm * @datactrl_mask_ddrmode: ddr mode mask in datactrl register. - * @blksz_datactrl16: true if Block size is at b16..b30 position in datactrl register - * @blksz_datactrl4: true if Block size is at b4..b16 position in datactrl - * register * @datactrl_mask_sdio: SDIO enable mask in datactrl register * @datactrl_blksz: block size in power of two - * @datactrl_dpsm_enable: enable value for DPSM * @datactrl_first: true if data must be setup before send command * @datacnt_useless: true if you could not use datacnt register to read * remaining data @@ -325,14 +326,11 @@ struct variant_data { unsigned int datactrl_mask_ddrmode; unsigned int datactrl_mask_sdio; unsigned int datactrl_blocksz; - unsigned int datactrl_dpsm_enable; u8 datactrl_first:1; u8 datacnt_useless:1; u8 st_sdio:1; u8 st_clkdiv:1; u8 stm32_clkdiv:1; - u8 blksz_datactrl16:1; - u8 blksz_datactrl4:1; u32 pwrreg_powerup; u32 f_max; u8 signal_direction:1; @@ -362,6 +360,7 @@ struct mmci_host_ops { bool next); void (*unprep_data)(struct mmci_host *host, struct mmc_data *data, int err); + u32 (*get_datactrl_cfg)(struct mmci_host *host); void (*get_next_data)(struct mmci_host *host, struct mmc_data *data); int (*dma_setup)(struct mmci_host *host); void (*dma_release)(struct mmci_host *host); @@ -377,6 +376,7 @@ struct mmci_host { void __iomem *base; struct mmc_request *mrq; struct mmc_command *cmd; + struct mmc_command stop_abort; struct mmc_data *data; struct mmc_host *mmc; struct clk *clk; @@ -428,6 +428,12 @@ struct mmci_host { void mmci_write_clkreg(struct mmci_host *host, u32 clk); void mmci_write_pwrreg(struct mmci_host *host, u32 pwr); +static inline u32 mmci_dctrl_blksz(struct mmci_host *host) +{ + return (ffs(host->data->blksz) - 1) << 4; +} + +#ifdef CONFIG_DMA_ENGINE int mmci_dmae_prep_data(struct mmci_host *host, struct mmc_data *data, bool next); void mmci_dmae_unprep_data(struct mmci_host *host, struct mmc_data *data, @@ -438,3 +444,16 @@ void mmci_dmae_release(struct mmci_host *host); int mmci_dmae_start(struct mmci_host *host, unsigned int *datactrl); void mmci_dmae_finalize(struct mmci_host *host, struct mmc_data *data); void mmci_dmae_error(struct mmci_host *host); +#endif + +#ifdef CONFIG_MMC_QCOM_DML +void qcom_variant_init(struct mmci_host *host); +#else +static inline void qcom_variant_init(struct mmci_host *host) {} +#endif + +#ifdef CONFIG_MMC_STM32_SDMMC +void sdmmc_variant_init(struct mmci_host *host); +#else +static inline void sdmmc_variant_init(struct mmci_host *host) {} +#endif diff --git a/drivers/mmc/host/mmci_qcom_dml.c b/drivers/mmc/host/mmci_qcom_dml.c index 25d0a75533ea..3af396b3e0a0 100644 --- a/drivers/mmc/host/mmci_qcom_dml.c +++ b/drivers/mmc/host/mmci_qcom_dml.c @@ -54,10 +54,15 @@ #define DML_OFFSET 0x800 -void dml_start_xfer(struct mmci_host *host, struct mmc_data *data) +static int qcom_dma_start(struct mmci_host *host, unsigned int *datactrl) { u32 config; void __iomem *base = host->base + DML_OFFSET; + struct mmc_data *data = host->data; + int ret = mmci_dmae_start(host, datactrl); + + if (ret) + return ret; if (data->flags & MMC_DATA_READ) { /* Read operation: configure DML for producer operation */ @@ -96,6 +101,7 @@ void dml_start_xfer(struct mmci_host *host, struct mmc_data *data) /* make sure the dml is configured before dma is triggered */ wmb(); + return 0; } static int of_get_dml_pipe_index(struct device_node *np, const char *name) @@ -133,7 +139,6 @@ static int qcom_dma_setup(struct mmci_host *host) producer_id = of_get_dml_pipe_index(np, "rx"); if (producer_id < 0 || consumer_id < 0) { - host->variant->qcom_dml = false; mmci_dmae_release(host); return -EINVAL; } @@ -183,13 +188,19 @@ static int qcom_dma_setup(struct mmci_host *host) return 0; } +static u32 qcom_get_dctrl_cfg(struct mmci_host *host) +{ + return MCI_DPSM_ENABLE | (host->data->blksz << 4); +} + static struct mmci_host_ops qcom_variant_ops = { .prep_data = mmci_dmae_prep_data, .unprep_data = mmci_dmae_unprep_data, + .get_datactrl_cfg = qcom_get_dctrl_cfg, .get_next_data = mmci_dmae_get_next_data, .dma_setup = qcom_dma_setup, .dma_release = mmci_dmae_release, - .dma_start = mmci_dmae_start, + .dma_start = qcom_dma_start, .dma_finalize = mmci_dmae_finalize, .dma_error = mmci_dmae_error, }; diff --git a/drivers/mmc/host/mmci_qcom_dml.h b/drivers/mmc/host/mmci_qcom_dml.h deleted file mode 100644 index fa16f6f4d4ad..000000000000 --- a/drivers/mmc/host/mmci_qcom_dml.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * - * Copyright (c) 2011, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ -#ifndef __MMC_QCOM_DML_H__ -#define __MMC_QCOM_DML_H__ - -#ifdef CONFIG_MMC_QCOM_DML -void qcom_variant_init(struct mmci_host *host); -void dml_start_xfer(struct mmci_host *host, struct mmc_data *data); -#else -static inline void qcom_variant_init(struct mmci_host *host) -{ -} -static inline void dml_start_xfer(struct mmci_host *host, struct mmc_data *data) -{ -} -#endif /* CONFIG_MMC_QCOM_DML */ - -#endif /* __MMC_QCOM_DML_H__ */ diff --git a/drivers/mmc/host/mmci_stm32_sdmmc.c b/drivers/mmc/host/mmci_stm32_sdmmc.c index cfbfc6f1048f..8e83ae6920ae 100644 --- a/drivers/mmc/host/mmci_stm32_sdmmc.c +++ b/drivers/mmc/host/mmci_stm32_sdmmc.c @@ -265,10 +265,28 @@ static void mmci_sdmmc_set_pwrreg(struct mmci_host *host, unsigned int pwr) } } +static u32 sdmmc_get_dctrl_cfg(struct mmci_host *host) +{ + u32 datactrl; + + datactrl = mmci_dctrl_blksz(host); + + if (host->mmc->card && mmc_card_sdio(host->mmc->card) && + host->data->blocks == 1) + datactrl |= MCI_DPSM_STM32_MODE_SDIO; + else if (host->data->stop && !host->mrq->sbc) + datactrl |= MCI_DPSM_STM32_MODE_BLOCK_STOP; + else + datactrl |= MCI_DPSM_STM32_MODE_BLOCK; + + return datactrl; +} + static struct mmci_host_ops sdmmc_variant_ops = { .validate_data = sdmmc_idma_validate_data, .prep_data = sdmmc_idma_prep_data, .unprep_data = sdmmc_idma_unprep_data, + .get_datactrl_cfg = sdmmc_get_dctrl_cfg, .dma_setup = sdmmc_idma_setup, .dma_start = sdmmc_idma_start, .dma_finalize = sdmmc_idma_finalize, diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c index 833ef0590af8..c518cc208a1f 100644 --- a/drivers/mmc/host/mtk-sd.c +++ b/drivers/mmc/host/mtk-sd.c @@ -300,6 +300,8 @@ #define CMD_TIMEOUT (HZ/10 * 5) /* 100ms x5 */ #define DAT_TIMEOUT (HZ * 5) /* 1000ms x5 */ +#define DEFAULT_DEBOUNCE (8) /* 8 cycles CD debounce */ + #define PAD_DELAY_MAX 32 /* PAD delay cells */ /*--------------------------------------------------------------------------*/ /* Descriptor Structure */ @@ -372,6 +374,7 @@ struct mtk_mmc_compatible { bool stop_clk_fix; bool enhance_rx; bool support_64g; + bool use_internal_cd; }; struct msdc_tune_para { @@ -430,6 +433,7 @@ struct msdc_host { bool hs400_cmd_resp_sel_rising; /* cmd response sample selection for HS400 */ bool hs400_mode; /* current eMMC will run at hs400 mode */ + bool internal_cd; /* Use internal card-detect logic */ struct msdc_save_para save_para; /* used when gate HCLK */ struct msdc_tune_para def_tune_para; /* default tune setting */ struct msdc_tune_para saved_tune_para; /* tune result of CMD21/CMD19 */ @@ -507,6 +511,28 @@ static const struct mtk_mmc_compatible mt7622_compat = { .support_64g = false, }; +static const struct mtk_mmc_compatible mt8516_compat = { + .clk_div_bits = 12, + .hs400_tune = false, + .pad_tune_reg = MSDC_PAD_TUNE0, + .async_fifo = true, + .data_tune = true, + .busy_check = true, + .stop_clk_fix = true, +}; + +static const struct mtk_mmc_compatible mt7620_compat = { + .clk_div_bits = 8, + .hs400_tune = false, + .pad_tune_reg = MSDC_PAD_TUNE, + .async_fifo = false, + .data_tune = false, + .busy_check = false, + .stop_clk_fix = false, + .enhance_rx = false, + .use_internal_cd = true, +}; + static const struct of_device_id msdc_of_ids[] = { { .compatible = "mediatek,mt8135-mmc", .data = &mt8135_compat}, { .compatible = "mediatek,mt8173-mmc", .data = &mt8173_compat}, @@ -514,6 +540,8 @@ static const struct of_device_id msdc_of_ids[] = { { .compatible = "mediatek,mt2701-mmc", .data = &mt2701_compat}, { .compatible = "mediatek,mt2712-mmc", .data = &mt2712_compat}, { .compatible = "mediatek,mt7622-mmc", .data = &mt7622_compat}, + { .compatible = "mediatek,mt8516-mmc", .data = &mt8516_compat}, + { .compatible = "mediatek,mt7620-mmc", .data = &mt7620_compat}, {} }; MODULE_DEVICE_TABLE(of, msdc_of_ids); @@ -1407,6 +1435,12 @@ static irqreturn_t msdc_irq(int irq, void *dev_id) sdio_signal_irq(host->mmc); } + if ((events & event_mask) & MSDC_INT_CDSC) { + if (host->internal_cd) + mmc_detect_change(host->mmc, msecs_to_jiffies(20)); + events &= ~MSDC_INT_CDSC; + } + if (!(events & (event_mask & ~MSDC_INT_SDIOIRQ))) break; @@ -1440,14 +1474,24 @@ static void msdc_init_hw(struct msdc_host *host) /* Reset */ msdc_reset_hw(host); - /* Disable card detection */ - sdr_clr_bits(host->base + MSDC_PS, MSDC_PS_CDEN); - /* Disable and clear all interrupts */ writel(0, host->base + MSDC_INTEN); val = readl(host->base + MSDC_INT); writel(val, host->base + MSDC_INT); + /* Configure card detection */ + if (host->internal_cd) { + sdr_set_field(host->base + MSDC_PS, MSDC_PS_CDDEBOUNCE, + DEFAULT_DEBOUNCE); + sdr_set_bits(host->base + MSDC_PS, MSDC_PS_CDEN); + sdr_set_bits(host->base + MSDC_INTEN, MSDC_INTEN_CDSC); + sdr_set_bits(host->base + SDC_CFG, SDC_CFG_INSWKUP); + } else { + sdr_clr_bits(host->base + SDC_CFG, SDC_CFG_INSWKUP); + sdr_clr_bits(host->base + MSDC_PS, MSDC_PS_CDEN); + sdr_clr_bits(host->base + MSDC_INTEN, MSDC_INTEN_CDSC); + } + if (host->top_base) { writel(0, host->top_base + EMMC_TOP_CONTROL); writel(0, host->top_base + EMMC_TOP_CMD); @@ -1557,6 +1601,13 @@ static void msdc_init_hw(struct msdc_host *host) static void msdc_deinit_hw(struct msdc_host *host) { u32 val; + + if (host->internal_cd) { + /* Disabled card-detect */ + sdr_clr_bits(host->base + MSDC_PS, MSDC_PS_CDEN); + sdr_clr_bits(host->base + SDC_CFG, SDC_CFG_INSWKUP); + } + /* Disable and clear all interrupts */ writel(0, host->base + MSDC_INTEN); @@ -2055,13 +2106,31 @@ static void msdc_ack_sdio_irq(struct mmc_host *mmc) __msdc_enable_sdio_irq(mmc, 1); } +static int msdc_get_cd(struct mmc_host *mmc) +{ + struct msdc_host *host = mmc_priv(mmc); + int val; + + if (mmc->caps & MMC_CAP_NONREMOVABLE) + return 1; + + if (!host->internal_cd) + return mmc_gpio_get_cd(mmc); + + val = readl(host->base + MSDC_PS) & MSDC_PS_CDSTS; + if (mmc->caps2 & MMC_CAP2_CD_ACTIVE_HIGH) + return !!val; + else + return !val; +} + static const struct mmc_host_ops mt_msdc_ops = { .post_req = msdc_post_req, .pre_req = msdc_pre_req, .request = msdc_ops_request, .set_ios = msdc_ops_set_ios, .get_ro = mmc_gpio_get_ro, - .get_cd = mmc_gpio_get_cd, + .get_cd = msdc_get_cd, .enable_sdio_irq = msdc_enable_sdio_irq, .ack_sdio_irq = msdc_ack_sdio_irq, .start_signal_voltage_switch = msdc_ops_switch_volt, @@ -2123,9 +2192,11 @@ static int msdc_drv_probe(struct platform_device *pdev) } res = platform_get_resource(pdev, IORESOURCE_MEM, 1); - host->top_base = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(host->top_base)) - host->top_base = NULL; + if (res) { + host->top_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(host->top_base)) + host->top_base = NULL; + } ret = mmc_regulator_get_supply(mmc); if (ret) @@ -2191,6 +2262,16 @@ static int msdc_drv_probe(struct platform_device *pdev) else mmc->f_min = DIV_ROUND_UP(host->src_clk_freq, 4 * 4095); + if (!(mmc->caps & MMC_CAP_NONREMOVABLE) && + !mmc_can_gpio_cd(mmc) && + host->dev_comp->use_internal_cd) { + /* + * Is removable but no GPIO declared, so + * use internal functionality. + */ + host->internal_cd = true; + } + if (mmc->caps & MMC_CAP_SDIO_IRQ) mmc->caps2 |= MMC_CAP2_SDIO_IRQ_NOTHREAD; @@ -2227,7 +2308,7 @@ static int msdc_drv_probe(struct platform_device *pdev) msdc_init_hw(host); ret = devm_request_irq(&pdev->dev, host->irq, msdc_irq, - IRQF_TRIGGER_LOW | IRQF_ONESHOT, pdev->name, host); + IRQF_TRIGGER_NONE, pdev->name, host); if (ret) goto release; diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c index 4d17032d15ee..45f7b9b53d48 100644 --- a/drivers/mmc/host/mxcmmc.c +++ b/drivers/mmc/host/mxcmmc.c @@ -31,14 +31,12 @@ #include <linux/delay.h> #include <linux/clk.h> #include <linux/io.h> -#include <linux/gpio.h> #include <linux/regulator/consumer.h> #include <linux/dmaengine.h> #include <linux/types.h> #include <linux/of.h> #include <linux/of_device.h> #include <linux/of_dma.h> -#include <linux/of_gpio.h> #include <linux/mmc/slot-gpio.h> #include <asm/dma.h> @@ -292,11 +290,8 @@ static void mxcmci_swap_buffers(struct mmc_data *data) struct scatterlist *sg; int i; - for_each_sg(data->sg, sg, data->sg_len, i) { - void *buf = kmap_atomic(sg_page(sg) + sg->offset); - buffer_swap32(buf, sg->length); - kunmap_atomic(buf); - } + for_each_sg(data->sg, sg, data->sg_len, i) + buffer_swap32(sg_virt(sg), sg->length); } #else static inline void mxcmci_swap_buffers(struct mmc_data *data) {} @@ -613,7 +608,6 @@ static int mxcmci_transfer_data(struct mxcmci_host *host) { struct mmc_data *data = host->req->data; struct scatterlist *sg; - void *buf; int stat, i; host->data = data; @@ -621,18 +615,14 @@ static int mxcmci_transfer_data(struct mxcmci_host *host) if (data->flags & MMC_DATA_READ) { for_each_sg(data->sg, sg, data->sg_len, i) { - buf = kmap_atomic(sg_page(sg) + sg->offset); - stat = mxcmci_pull(host, buf, sg->length); - kunmap(buf); + stat = mxcmci_pull(host, sg_virt(sg), sg->length); if (stat) return stat; host->datasize += sg->length; } } else { for_each_sg(data->sg, sg, data->sg_len, i) { - buf = kmap_atomic(sg_page(sg) + sg->offset); - stat = mxcmci_push(host, buf, sg->length); - kunmap(buf); + stat = mxcmci_push(host, sg_virt(sg), sg->length); if (stat) return stat; host->datasize += sg->length; diff --git a/drivers/mmc/host/mxs-mmc.c b/drivers/mmc/host/mxs-mmc.c index add1e70195ea..c021d433b04f 100644 --- a/drivers/mmc/host/mxs-mmc.c +++ b/drivers/mmc/host/mxs-mmc.c @@ -25,7 +25,6 @@ #include <linux/ioport.h> #include <linux/of.h> #include <linux/of_device.h> -#include <linux/of_gpio.h> #include <linux/platform_device.h> #include <linux/delay.h> #include <linux/interrupt.h> @@ -39,7 +38,6 @@ #include <linux/mmc/mmc.h> #include <linux/mmc/sdio.h> #include <linux/mmc/slot-gpio.h> -#include <linux/gpio.h> #include <linux/regulator/consumer.h> #include <linux/module.h> #include <linux/stmp_device.h> @@ -650,7 +648,8 @@ static int mxs_mmc_probe(struct platform_device *pdev) /* set mmc core parameters */ mmc->ops = &mxs_mmc_ops; mmc->caps = MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED | - MMC_CAP_SDIO_IRQ | MMC_CAP_NEEDS_POLL | MMC_CAP_CMD23; + MMC_CAP_SDIO_IRQ | MMC_CAP_NEEDS_POLL | MMC_CAP_CMD23 | + MMC_CAP_ERASE; host->broken_cd = of_property_read_bool(np, "broken-cd"); diff --git a/drivers/mmc/host/of_mmc_spi.c b/drivers/mmc/host/of_mmc_spi.c index b294b221f225..3c4d950a4755 100644 --- a/drivers/mmc/host/of_mmc_spi.c +++ b/drivers/mmc/host/of_mmc_spi.c @@ -1,14 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * OpenFirmware bindings for the MMC-over-SPI driver * * Copyright (c) MontaVista Software, Inc. 2008. * * Author: Anton Vorontsov <avorontsov@ru.mvista.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. */ #include <linux/kernel.h> @@ -61,9 +57,6 @@ struct mmc_spi_platform_data *mmc_spi_get_pdata(struct spi_device *spi) struct device *dev = &spi->dev; struct device_node *np = dev->of_node; struct of_mmc_spi *oms; - const __be32 *voltage_ranges; - int num_ranges; - int i; if (dev->platform_data || !np) return dev->platform_data; @@ -72,25 +65,8 @@ struct mmc_spi_platform_data *mmc_spi_get_pdata(struct spi_device *spi) if (!oms) return NULL; - voltage_ranges = of_get_property(np, "voltage-ranges", &num_ranges); - num_ranges = num_ranges / sizeof(*voltage_ranges) / 2; - if (!voltage_ranges || !num_ranges) { - dev_err(dev, "OF: voltage-ranges unspecified\n"); + if (mmc_of_parse_voltage(np, &oms->pdata.ocr_mask) <= 0) goto err_ocr; - } - - for (i = 0; i < num_ranges; i++) { - const int j = i * 2; - u32 mask; - - mask = mmc_vddrange_to_ocrmask(be32_to_cpu(voltage_ranges[j]), - be32_to_cpu(voltage_ranges[j + 1])); - if (!mask) { - dev_err(dev, "OF: voltage-range #%d is invalid\n", i); - goto err_ocr; - } - oms->pdata.ocr_mask |= mask; - } oms->detect_irq = irq_of_parse_and_map(np, 0); if (oms->detect_irq != 0) { diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c index c60a7625b1fa..b2873a2432b6 100644 --- a/drivers/mmc/host/omap.c +++ b/drivers/mmc/host/omap.c @@ -920,7 +920,7 @@ static inline void set_cmd_timeout(struct mmc_omap_host *host, struct mmc_reques reg &= ~(1 << 5); OMAP_MMC_WRITE(host, SDIO, reg); /* Set maximum timeout */ - OMAP_MMC_WRITE(host, CTO, 0xff); + OMAP_MMC_WRITE(host, CTO, 0xfd); } static inline void set_data_timeout(struct mmc_omap_host *host, struct mmc_request *req) diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 29a1ddaa7466..952fa4063ff8 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -2077,7 +2077,7 @@ static int omap_hsmmc_runtime_suspend(struct device *dev) unsigned long flags; int ret = 0; - host = platform_get_drvdata(to_platform_device(dev)); + host = dev_get_drvdata(dev); omap_hsmmc_context_save(host); dev_dbg(dev, "disabled\n"); @@ -2118,7 +2118,7 @@ static int omap_hsmmc_runtime_resume(struct device *dev) struct omap_hsmmc_host *host; unsigned long flags; - host = platform_get_drvdata(to_platform_device(dev)); + host = dev_get_drvdata(dev); omap_hsmmc_context_restore(host); dev_dbg(dev, "enabled\n"); diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c index 8779bbaa6b69..c1d3f0e38921 100644 --- a/drivers/mmc/host/pxamci.c +++ b/drivers/mmc/host/pxamci.c @@ -162,7 +162,7 @@ static void pxamci_dma_irq(void *param); static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data) { struct dma_async_tx_descriptor *tx; - enum dma_data_direction direction; + enum dma_transfer_direction direction; struct dma_slave_config config; struct dma_chan *chan; unsigned int nob = data->blocks; @@ -743,7 +743,7 @@ static int pxamci_probe(struct platform_device *pdev) goto out; } - ret = mmc_gpiod_request_ro(mmc, "wp", 0, false, 0, NULL); + ret = mmc_gpiod_request_ro(mmc, "wp", 0, 0, NULL); if (ret && ret != -ENOENT) { dev_err(dev, "Failed requesting gpio_ro\n"); goto out; diff --git a/drivers/mmc/host/renesas_sdhi.h b/drivers/mmc/host/renesas_sdhi.h index da1e49c45bec..c0504aa90857 100644 --- a/drivers/mmc/host/renesas_sdhi.h +++ b/drivers/mmc/host/renesas_sdhi.h @@ -3,7 +3,7 @@ * Renesas Mobile SDHI * * Copyright (C) 2017 Horms Solutions Ltd., Simon Horman - * Copyright (C) 2017 Renesas Electronics Corporation + * Copyright (C) 2017-19 Renesas Electronics Corporation */ #ifndef RENESAS_SDHI_H @@ -15,6 +15,7 @@ struct renesas_sdhi_scc { unsigned long clk_rate; /* clock rate for SDR104 */ u32 tap; /* sampling clock position for SDR104 */ + u32 tap_hs400; /* sampling clock position for HS400 */ }; struct renesas_sdhi_of_data { @@ -49,6 +50,7 @@ struct renesas_sdhi { struct pinctrl_state *pins_default, *pins_uhs; void __iomem *scc_ctl; u32 scc_tappos; + u32 scc_tappos_hs400; }; #define host_to_priv(host) \ diff --git a/drivers/mmc/host/renesas_sdhi_core.c b/drivers/mmc/host/renesas_sdhi_core.c index 31a351a20dc0..5e9e36ed2107 100644 --- a/drivers/mmc/host/renesas_sdhi_core.c +++ b/drivers/mmc/host/renesas_sdhi_core.c @@ -2,8 +2,8 @@ /* * Renesas SDHI * - * Copyright (C) 2015-17 Renesas Electronics Corporation - * Copyright (C) 2016-17 Sang Engineering, Wolfram Sang + * Copyright (C) 2015-19 Renesas Electronics Corporation + * Copyright (C) 2016-19 Sang Engineering, Wolfram Sang * Copyright (C) 2016-17 Horms Solutions, Simon Horman * Copyright (C) 2009 Magnus Damm * @@ -337,6 +337,10 @@ static void renesas_sdhi_hs400_complete(struct tmio_mmc_host *host) /* Set HS400 mode */ sd_ctrl_write16(host, CTL_SDIF_MODE, 0x0001 | sd_ctrl_read16(host, CTL_SDIF_MODE)); + + sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_DT2FF, + priv->scc_tappos_hs400); + sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_TMPPORT2, (SH_MOBILE_SDHI_SCC_TMPPORT2_HS400EN | SH_MOBILE_SDHI_SCC_TMPPORT2_HS400OSEL) | @@ -396,6 +400,9 @@ static void renesas_sdhi_reset_hs400_mode(struct tmio_mmc_host *host, /* Reset HS400 mode */ sd_ctrl_write16(host, CTL_SDIF_MODE, ~0x0001 & sd_ctrl_read16(host, CTL_SDIF_MODE)); + + sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_DT2FF, priv->scc_tappos); + sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_TMPPORT2, ~(SH_MOBILE_SDHI_SCC_TMPPORT2_HS400EN | SH_MOBILE_SDHI_SCC_TMPPORT2_HS400OSEL) & @@ -634,6 +641,7 @@ int renesas_sdhi_probe(struct platform_device *pdev, struct renesas_sdhi *priv; struct resource *res; int irq, ret, i; + u16 ver; of_data = of_device_get_match_data(&pdev->dev); @@ -723,6 +731,13 @@ int renesas_sdhi_probe(struct platform_device *pdev, host->ops.start_signal_voltage_switch = renesas_sdhi_start_signal_voltage_switch; host->sdcard_irq_setbit_mask = TMIO_STAT_ALWAYS_SET_27; + + /* SDR and HS200/400 registers requires HW reset */ + if (of_data && of_data->scc_offset) { + priv->scc_ctl = host->ctl + of_data->scc_offset; + host->mmc->caps |= MMC_CAP_HW_RESET; + host->hw_reset = renesas_sdhi_hw_reset; + } } /* Orginally registers were 16 bit apart, could be 32 or 64 nowadays */ @@ -759,14 +774,19 @@ int renesas_sdhi_probe(struct platform_device *pdev, if (ret) goto efree; - ret = tmio_mmc_host_probe(host); - if (ret < 0) - goto edisclk; + ver = sd_ctrl_read16(host, CTL_VERSION); + /* GEN2_SDR104 is first known SDHI to use 32bit block count */ + if (ver < SDHI_VER_GEN2_SDR104 && mmc_data->max_blk_count > U16_MAX) + mmc_data->max_blk_count = U16_MAX; /* One Gen2 SDHI incarnation does NOT have a CBSY bit */ - if (sd_ctrl_read16(host, CTL_VERSION) == SDHI_VER_GEN2_SDR50) + if (ver == SDHI_VER_GEN2_SDR50) mmc_data->flags &= ~TMIO_MMC_HAVE_CBSY; + ret = tmio_mmc_host_probe(host); + if (ret < 0) + goto edisclk; + /* Enable tuning iff we have an SCC and a supported mode */ if (of_data && of_data->scc_offset && (host->mmc->caps & MMC_CAP_UHS_SDR104 || @@ -775,12 +795,11 @@ int renesas_sdhi_probe(struct platform_device *pdev, const struct renesas_sdhi_scc *taps = of_data->taps; bool hit = false; - host->mmc->caps |= MMC_CAP_HW_RESET; - for (i = 0; i < of_data->taps_num; i++) { if (taps[i].clk_rate == 0 || taps[i].clk_rate == host->mmc->f_max) { priv->scc_tappos = taps->tap; + priv->scc_tappos_hs400 = taps->tap_hs400; hit = true; break; } @@ -789,12 +808,10 @@ int renesas_sdhi_probe(struct platform_device *pdev, if (!hit) dev_warn(&host->pdev->dev, "Unknown clock rate for SDR104\n"); - priv->scc_ctl = host->ctl + of_data->scc_offset; host->init_tuning = renesas_sdhi_init_tuning; host->prepare_tuning = renesas_sdhi_prepare_tuning; host->select_tuning = renesas_sdhi_select_tuning; host->check_scc_error = renesas_sdhi_check_scc_error; - host->hw_reset = renesas_sdhi_hw_reset; host->prepare_hs400_tuning = renesas_sdhi_prepare_hs400_tuning; host->hs400_downgrade = renesas_sdhi_disable_scc; diff --git a/drivers/mmc/host/renesas_sdhi_internal_dmac.c b/drivers/mmc/host/renesas_sdhi_internal_dmac.c index 92c9b15252da..751fe91c7571 100644 --- a/drivers/mmc/host/renesas_sdhi_internal_dmac.c +++ b/drivers/mmc/host/renesas_sdhi_internal_dmac.c @@ -2,8 +2,9 @@ /* * DMA support for Internal DMAC with SDHI SD/SDIO controller * - * Copyright (C) 2016-17 Renesas Electronics Corporation + * Copyright (C) 2016-19 Renesas Electronics Corporation * Copyright (C) 2016-17 Horms Solutions, Simon Horman + * Copyright (C) 2018-19 Sang Engineering, Wolfram Sang */ #include <linux/bitops.h> @@ -81,6 +82,7 @@ static struct renesas_sdhi_scc rcar_gen3_scc_taps[] = { { .clk_rate = 0, .tap = 0x00000300, + .tap_hs400 = 0x00000704, }, }; @@ -94,8 +96,8 @@ static const struct renesas_sdhi_of_data of_rza2_compatible = { .scc_offset = 0 - 0x1000, .taps = rcar_gen3_scc_taps, .taps_num = ARRAY_SIZE(rcar_gen3_scc_taps), - /* DMAC can handle 0xffffffff blk count but only 1 segment */ - .max_blk_count = 0xffffffff, + /* DMAC can handle 32bit blk count but only 1 segment */ + .max_blk_count = UINT_MAX / TMIO_MAX_BLK_SIZE, .max_segs = 1, }; @@ -109,8 +111,8 @@ static const struct renesas_sdhi_of_data of_rcar_gen3_compatible = { .scc_offset = 0x1000, .taps = rcar_gen3_scc_taps, .taps_num = ARRAY_SIZE(rcar_gen3_scc_taps), - /* DMAC can handle 0xffffffff blk count but only 1 segment */ - .max_blk_count = 0xffffffff, + /* DMAC can handle 32bit blk count but only 1 segment */ + .max_blk_count = UINT_MAX / TMIO_MAX_BLK_SIZE, .max_segs = 1, }; diff --git a/drivers/mmc/host/renesas_sdhi_sys_dmac.c b/drivers/mmc/host/renesas_sdhi_sys_dmac.c index 8471160316e0..1d29b822efb8 100644 --- a/drivers/mmc/host/renesas_sdhi_sys_dmac.c +++ b/drivers/mmc/host/renesas_sdhi_sys_dmac.c @@ -2,8 +2,8 @@ /* * DMA support use of SYS DMAC with SDHI SD/SDIO controller * - * Copyright (C) 2016-17 Renesas Electronics Corporation - * Copyright (C) 2016-17 Sang Engineering, Wolfram Sang + * Copyright (C) 2016-19 Renesas Electronics Corporation + * Copyright (C) 2016-19 Sang Engineering, Wolfram Sang * Copyright (C) 2017 Horms Solutions, Simon Horman * Copyright (C) 2010-2011 Guennadi Liakhovetski */ @@ -65,6 +65,7 @@ static const struct renesas_sdhi_of_data of_rcar_gen2_compatible = { .scc_offset = 0x0300, .taps = rcar_gen2_scc_taps, .taps_num = ARRAY_SIZE(rcar_gen2_scc_taps), + .max_blk_count = UINT_MAX / TMIO_MAX_BLK_SIZE, }; /* Definitions for sampling clocks */ diff --git a/drivers/mmc/host/s3cmci.c b/drivers/mmc/host/s3cmci.c index 10f5219b3b40..f31333e831a7 100644 --- a/drivers/mmc/host/s3cmci.c +++ b/drivers/mmc/host/s3cmci.c @@ -1530,7 +1530,7 @@ static int s3cmci_probe_pdata(struct s3cmci_host *host) return ret; } - ret = mmc_gpiod_request_ro(host->mmc, "wp", 0, false, 0, NULL); + ret = mmc_gpiod_request_ro(host->mmc, "wp", 0, 0, NULL); if (ret != -ENOENT) { dev_err(&pdev->dev, "error requesting GPIO for WP %d\n", ret); diff --git a/drivers/mmc/host/sdhci-bcm-kona.c b/drivers/mmc/host/sdhci-bcm-kona.c index bdbd4897c0f7..a6c2bd202b45 100644 --- a/drivers/mmc/host/sdhci-bcm-kona.c +++ b/drivers/mmc/host/sdhci-bcm-kona.c @@ -18,12 +18,10 @@ #include <linux/platform_device.h> #include <linux/mmc/host.h> #include <linux/io.h> -#include <linux/gpio.h> #include <linux/clk.h> #include <linux/regulator/consumer.h> #include <linux/of.h> #include <linux/of_device.h> -#include <linux/of_gpio.h> #include <linux/mmc/slot-gpio.h> #include "sdhci-pltfm.h" diff --git a/drivers/mmc/host/sdhci-brcmstb.c b/drivers/mmc/host/sdhci-brcmstb.c index 552bddc5096c..1cd10356fc14 100644 --- a/drivers/mmc/host/sdhci-brcmstb.c +++ b/drivers/mmc/host/sdhci-brcmstb.c @@ -55,7 +55,9 @@ static int sdhci_brcmstb_probe(struct platform_device *pdev) } sdhci_get_of_property(pdev); - mmc_of_parse(host->mmc); + res = mmc_of_parse(host->mmc); + if (res) + goto err; /* * Supply the existing CAPS, but clear the UHS modes. This diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c index d0d319398a54..c391510e9ef4 100644 --- a/drivers/mmc/host/sdhci-esdhc-imx.c +++ b/drivers/mmc/host/sdhci-esdhc-imx.c @@ -14,6 +14,7 @@ #include <linux/clk.h> #include <linux/module.h> #include <linux/slab.h> +#include <linux/pm_qos.h> #include <linux/mmc/host.h> #include <linux/mmc/mmc.h> #include <linux/mmc/sdio.h> @@ -25,6 +26,7 @@ #include <linux/pm_runtime.h> #include "sdhci-pltfm.h" #include "sdhci-esdhc.h" +#include "cqhci.h" #define ESDHC_SYS_CTRL_DTOCV_MASK 0x0f #define ESDHC_CTRL_D3CD 0x08 @@ -50,6 +52,7 @@ #define ESDHC_MIX_CTRL_AUTO_TUNE_EN (1 << 24) #define ESDHC_MIX_CTRL_FBCLK_SEL (1 << 25) #define ESDHC_MIX_CTRL_HS400_EN (1 << 26) +#define ESDHC_MIX_CTRL_HS400_ES_EN (1 << 27) /* Bits 3 and 6 are not SDHCI standard definitions */ #define ESDHC_MIX_CTRL_SDHCI_MASK 0xb7 /* Tuning bits */ @@ -71,11 +74,15 @@ #define ESDHC_STROBE_DLL_CTRL_ENABLE (1 << 0) #define ESDHC_STROBE_DLL_CTRL_RESET (1 << 1) #define ESDHC_STROBE_DLL_CTRL_SLV_DLY_TARGET_SHIFT 3 +#define ESDHC_STROBE_DLL_CTRL_SLV_UPDATE_INT_DEFAULT (4 << 20) #define ESDHC_STROBE_DLL_STATUS 0x74 #define ESDHC_STROBE_DLL_STS_REF_LOCK (1 << 1) #define ESDHC_STROBE_DLL_STS_SLV_LOCK 0x1 +#define ESDHC_VEND_SPEC2 0xc8 +#define ESDHC_VEND_SPEC2_EN_BUSY_IRQ (1 << 8) + #define ESDHC_TUNING_CTRL 0xcc #define ESDHC_STD_TUNING_EN (1 << 24) /* NOTE: the minimum valid tuning start tap for mx6sl is 1 */ @@ -103,6 +110,9 @@ */ #define ESDHC_INT_VENDOR_SPEC_DMA_ERR (1 << 28) +/* the address offset of CQHCI */ +#define ESDHC_CQHCI_ADDR_OFFSET 0x100 + /* * The CMDTYPE of the CMD register (offset 0xE) should be set to * "11" when the STOP CMD12 is issued on imx53 to abort one @@ -138,51 +148,79 @@ #define ESDHC_FLAG_HS200 BIT(8) /* The IP supports HS400 mode */ #define ESDHC_FLAG_HS400 BIT(9) - -/* A clock frequency higher than this rate requires strobe dll control */ -#define ESDHC_STROBE_DLL_CLK_FREQ 100000000 +/* + * The IP has errata ERR010450 + * uSDHC: Due to the I/O timing limit, for SDR mode, SD card clock can't + * exceed 150MHz, for DDR mode, SD card clock can't exceed 45MHz. + */ +#define ESDHC_FLAG_ERR010450 BIT(10) +/* The IP supports HS400ES mode */ +#define ESDHC_FLAG_HS400_ES BIT(11) +/* The IP has Host Controller Interface for Command Queuing */ +#define ESDHC_FLAG_CQHCI BIT(12) +/* need request pmqos during low power */ +#define ESDHC_FLAG_PMQOS BIT(13) struct esdhc_soc_data { u32 flags; }; -static struct esdhc_soc_data esdhc_imx25_data = { +static const struct esdhc_soc_data esdhc_imx25_data = { .flags = ESDHC_FLAG_ERR004536, }; -static struct esdhc_soc_data esdhc_imx35_data = { +static const struct esdhc_soc_data esdhc_imx35_data = { .flags = ESDHC_FLAG_ERR004536, }; -static struct esdhc_soc_data esdhc_imx51_data = { +static const struct esdhc_soc_data esdhc_imx51_data = { .flags = 0, }; -static struct esdhc_soc_data esdhc_imx53_data = { +static const struct esdhc_soc_data esdhc_imx53_data = { .flags = ESDHC_FLAG_MULTIBLK_NO_INT, }; -static struct esdhc_soc_data usdhc_imx6q_data = { +static const struct esdhc_soc_data usdhc_imx6q_data = { .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_MAN_TUNING, }; -static struct esdhc_soc_data usdhc_imx6sl_data = { +static const struct esdhc_soc_data usdhc_imx6sl_data = { .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING | ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_ERR004536 | ESDHC_FLAG_HS200, }; -static struct esdhc_soc_data usdhc_imx6sx_data = { +static const struct esdhc_soc_data usdhc_imx6sx_data = { .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING | ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200, }; -static struct esdhc_soc_data usdhc_imx7d_data = { +static const struct esdhc_soc_data usdhc_imx6ull_data = { + .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING + | ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200 + | ESDHC_FLAG_ERR010450, +}; + +static const struct esdhc_soc_data usdhc_imx7d_data = { .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING | ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200 | ESDHC_FLAG_HS400, }; +static struct esdhc_soc_data usdhc_imx7ulp_data = { + .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING + | ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200 + | ESDHC_FLAG_PMQOS | ESDHC_FLAG_HS400, +}; + +static struct esdhc_soc_data usdhc_imx8qxp_data = { + .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING + | ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200 + | ESDHC_FLAG_HS400 | ESDHC_FLAG_HS400_ES + | ESDHC_FLAG_CQHCI, +}; + struct pltfm_imx_data { u32 scratchpad; struct pinctrl *pinctrl; @@ -201,6 +239,7 @@ struct pltfm_imx_data { WAIT_FOR_INT, /* sent CMD12, waiting for response INT */ } multiblock_status; u32 is_ddr; + struct pm_qos_request pm_qos_req; }; static const struct platform_device_id imx_esdhc_devtype[] = { @@ -227,7 +266,10 @@ static const struct of_device_id imx_esdhc_dt_ids[] = { { .compatible = "fsl,imx6sx-usdhc", .data = &usdhc_imx6sx_data, }, { .compatible = "fsl,imx6sl-usdhc", .data = &usdhc_imx6sl_data, }, { .compatible = "fsl,imx6q-usdhc", .data = &usdhc_imx6q_data, }, + { .compatible = "fsl,imx6ull-usdhc", .data = &usdhc_imx6ull_data, }, { .compatible = "fsl,imx7d-usdhc", .data = &usdhc_imx7d_data, }, + { .compatible = "fsl,imx7ulp-usdhc", .data = &usdhc_imx7ulp_data, }, + { .compatible = "fsl,imx8qxp-usdhc", .data = &usdhc_imx8qxp_data, }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, imx_esdhc_dt_ids); @@ -733,6 +775,14 @@ static inline void esdhc_pltfm_set_clock(struct sdhci_host *host, | ESDHC_CLOCK_MASK); sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL); + if (imx_data->socdata->flags & ESDHC_FLAG_ERR010450) { + unsigned int max_clock; + + max_clock = imx_data->is_ddr ? 45000000 : 150000000; + + clock = min(clock, max_clock); + } + while (host_clock / (16 * pre_div * ddr_pre_div) > clock && pre_div < 256) pre_div *= 2; @@ -801,6 +851,20 @@ static void esdhc_pltfm_set_bus_width(struct sdhci_host *host, int width) SDHCI_HOST_CONTROL); } +static int usdhc_execute_tuning(struct mmc_host *mmc, u32 opcode) +{ + struct sdhci_host *host = mmc_priv(mmc); + + /* + * i.MX uSDHC internally already uses a fixed optimized timing for + * DDR50, normally does not require tuning for DDR50 mode. + */ + if (host->timing == MMC_TIMING_UHS_DDR50) + return 0; + + return sdhci_execute_tuning(mmc, opcode); +} + static void esdhc_prepare_tuning(struct sdhci_host *host, u32 val) { u32 reg; @@ -864,6 +928,19 @@ static int esdhc_executing_tuning(struct sdhci_host *host, u32 opcode) return ret; } +static void esdhc_hs400_enhanced_strobe(struct mmc_host *mmc, struct mmc_ios *ios) +{ + struct sdhci_host *host = mmc_priv(mmc); + u32 m; + + m = readl(host->ioaddr + ESDHC_MIX_CTRL); + if (ios->enhanced_strobe) + m |= ESDHC_MIX_CTRL_HS400_ES_EN; + else + m &= ~ESDHC_MIX_CTRL_HS400_ES_EN; + writel(m, host->ioaddr + ESDHC_MIX_CTRL); +} + static int esdhc_change_pinstate(struct sdhci_host *host, unsigned int uhs) { @@ -905,39 +982,39 @@ static int esdhc_change_pinstate(struct sdhci_host *host, * edge of data_strobe line. Due to the time delay between CLK line and * data_strobe line, if the delay time is larger than one clock cycle, * then CLK and data_strobe line will be misaligned, read error shows up. - * So when the CLK is higher than 100MHz, each clock cycle is short enough, - * host should configure the delay target. */ static void esdhc_set_strobe_dll(struct sdhci_host *host) { u32 v; - if (host->mmc->actual_clock > ESDHC_STROBE_DLL_CLK_FREQ) { - /* disable clock before enabling strobe dll */ - writel(readl(host->ioaddr + ESDHC_VENDOR_SPEC) & - ~ESDHC_VENDOR_SPEC_FRC_SDCLK_ON, - host->ioaddr + ESDHC_VENDOR_SPEC); + /* disable clock before enabling strobe dll */ + writel(readl(host->ioaddr + ESDHC_VENDOR_SPEC) & + ~ESDHC_VENDOR_SPEC_FRC_SDCLK_ON, + host->ioaddr + ESDHC_VENDOR_SPEC); - /* force a reset on strobe dll */ - writel(ESDHC_STROBE_DLL_CTRL_RESET, - host->ioaddr + ESDHC_STROBE_DLL_CTRL); - /* - * enable strobe dll ctrl and adjust the delay target - * for the uSDHC loopback read clock - */ - v = ESDHC_STROBE_DLL_CTRL_ENABLE | - (7 << ESDHC_STROBE_DLL_CTRL_SLV_DLY_TARGET_SHIFT); - writel(v, host->ioaddr + ESDHC_STROBE_DLL_CTRL); - /* wait 1us to make sure strobe dll status register stable */ - udelay(1); - v = readl(host->ioaddr + ESDHC_STROBE_DLL_STATUS); - if (!(v & ESDHC_STROBE_DLL_STS_REF_LOCK)) - dev_warn(mmc_dev(host->mmc), - "warning! HS400 strobe DLL status REF not lock!\n"); - if (!(v & ESDHC_STROBE_DLL_STS_SLV_LOCK)) - dev_warn(mmc_dev(host->mmc), - "warning! HS400 strobe DLL status SLV not lock!\n"); - } + /* force a reset on strobe dll */ + writel(ESDHC_STROBE_DLL_CTRL_RESET, + host->ioaddr + ESDHC_STROBE_DLL_CTRL); + /* clear the reset bit on strobe dll before any setting */ + writel(0, host->ioaddr + ESDHC_STROBE_DLL_CTRL); + + /* + * enable strobe dll ctrl and adjust the delay target + * for the uSDHC loopback read clock + */ + v = ESDHC_STROBE_DLL_CTRL_ENABLE | + ESDHC_STROBE_DLL_CTRL_SLV_UPDATE_INT_DEFAULT | + (7 << ESDHC_STROBE_DLL_CTRL_SLV_DLY_TARGET_SHIFT); + writel(v, host->ioaddr + ESDHC_STROBE_DLL_CTRL); + /* wait 5us to make sure strobe dll status register stable */ + udelay(5); + v = readl(host->ioaddr + ESDHC_STROBE_DLL_STATUS); + if (!(v & ESDHC_STROBE_DLL_STS_REF_LOCK)) + dev_warn(mmc_dev(host->mmc), + "warning! HS400 strobe DLL status REF not lock!\n"); + if (!(v & ESDHC_STROBE_DLL_STS_SLV_LOCK)) + dev_warn(mmc_dev(host->mmc), + "warning! HS400 strobe DLL status SLV not lock!\n"); } static void esdhc_reset_tuning(struct sdhci_host *host) @@ -979,6 +1056,7 @@ static void esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned timing) case MMC_TIMING_UHS_SDR25: case MMC_TIMING_UHS_SDR50: case MMC_TIMING_UHS_SDR104: + case MMC_TIMING_MMC_HS: case MMC_TIMING_MMC_HS200: writel(m, host->ioaddr + ESDHC_MIX_CTRL); break; @@ -1042,6 +1120,19 @@ static void esdhc_set_timeout(struct sdhci_host *host, struct mmc_command *cmd) SDHCI_TIMEOUT_CONTROL); } +static u32 esdhc_cqhci_irq(struct sdhci_host *host, u32 intmask) +{ + int cmd_error = 0; + int data_error = 0; + + if (!sdhci_cqe_irq(host, intmask, &cmd_error, &data_error)) + return intmask; + + cqhci_irq(host->mmc, intmask, cmd_error, data_error); + + return 0; +} + static struct sdhci_ops sdhci_esdhc_ops = { .read_l = esdhc_readl_le, .read_w = esdhc_readw_le, @@ -1058,6 +1149,7 @@ static struct sdhci_ops sdhci_esdhc_ops = { .set_bus_width = esdhc_pltfm_set_bus_width, .set_uhs_signaling = esdhc_set_uhs_signaling, .reset = esdhc_reset, + .irq = esdhc_cqhci_irq, }; static const struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = { @@ -1095,16 +1187,34 @@ static void sdhci_esdhc_imx_hwinit(struct sdhci_host *host) writel(readl(host->ioaddr + SDHCI_HOST_CONTROL) | ESDHC_BURST_LEN_EN_INCR, host->ioaddr + SDHCI_HOST_CONTROL); + /* - * erratum ESDHC_FLAG_ERR004536 fix for MX6Q TO1.2 and MX6DL - * TO1.1, it's harmless for MX6SL - */ - writel(readl(host->ioaddr + 0x6c) | BIT(7), + * erratum ESDHC_FLAG_ERR004536 fix for MX6Q TO1.2 and MX6DL + * TO1.1, it's harmless for MX6SL + */ + writel(readl(host->ioaddr + 0x6c) & ~BIT(7), host->ioaddr + 0x6c); /* disable DLL_CTRL delay line settings */ writel(0x0, host->ioaddr + ESDHC_DLL_CTRL); + /* + * For the case of command with busy, if set the bit + * ESDHC_VEND_SPEC2_EN_BUSY_IRQ, USDHC will generate a + * transfer complete interrupt when busy is deasserted. + * When CQHCI use DCMD to send a CMD need R1b respons, + * CQHCI require to set ESDHC_VEND_SPEC2_EN_BUSY_IRQ, + * otherwise DCMD will always meet timeout waiting for + * hardware interrupt issue. + */ + if (imx_data->socdata->flags & ESDHC_FLAG_CQHCI) { + tmp = readl(host->ioaddr + ESDHC_VEND_SPEC2); + tmp |= ESDHC_VEND_SPEC2_EN_BUSY_IRQ; + writel(tmp, host->ioaddr + ESDHC_VEND_SPEC2); + + host->quirks &= ~SDHCI_QUIRK_NO_BUSY_IRQ; + } + if (imx_data->socdata->flags & ESDHC_FLAG_STD_TUNING) { tmp = readl(host->ioaddr + ESDHC_TUNING_CTRL); tmp |= ESDHC_STD_TUNING_EN | @@ -1120,10 +1230,81 @@ static void sdhci_esdhc_imx_hwinit(struct sdhci_host *host) << ESDHC_TUNING_STEP_SHIFT; } writel(tmp, host->ioaddr + ESDHC_TUNING_CTRL); + } else if (imx_data->socdata->flags & ESDHC_FLAG_MAN_TUNING) { + /* + * ESDHC_STD_TUNING_EN may be configed in bootloader + * or ROM code, so clear this bit here to make sure + * the manual tuning can work. + */ + tmp = readl(host->ioaddr + ESDHC_TUNING_CTRL); + tmp &= ~ESDHC_STD_TUNING_EN; + writel(tmp, host->ioaddr + ESDHC_TUNING_CTRL); } } } +static void esdhc_cqe_enable(struct mmc_host *mmc) +{ + struct sdhci_host *host = mmc_priv(mmc); + struct cqhci_host *cq_host = mmc->cqe_private; + u32 reg; + u16 mode; + int count = 10; + + /* + * CQE gets stuck if it sees Buffer Read Enable bit set, which can be + * the case after tuning, so ensure the buffer is drained. + */ + reg = sdhci_readl(host, SDHCI_PRESENT_STATE); + while (reg & SDHCI_DATA_AVAILABLE) { + sdhci_readl(host, SDHCI_BUFFER); + reg = sdhci_readl(host, SDHCI_PRESENT_STATE); + if (count-- == 0) { + dev_warn(mmc_dev(host->mmc), + "CQE may get stuck because the Buffer Read Enable bit is set\n"); + break; + } + mdelay(1); + } + + /* + * Runtime resume will reset the entire host controller, which + * will also clear the DMAEN/BCEN of register ESDHC_MIX_CTRL. + * Here set DMAEN and BCEN when enable CMDQ. + */ + mode = sdhci_readw(host, SDHCI_TRANSFER_MODE); + if (host->flags & SDHCI_REQ_USE_DMA) + mode |= SDHCI_TRNS_DMA; + if (!(host->quirks2 & SDHCI_QUIRK2_SUPPORT_SINGLE)) + mode |= SDHCI_TRNS_BLK_CNT_EN; + sdhci_writew(host, mode, SDHCI_TRANSFER_MODE); + + /* + * Though Runtime resume reset the entire host controller, + * but do not impact the CQHCI side, need to clear the + * HALT bit, avoid CQHCI stuck in the first request when + * system resume back. + */ + cqhci_writel(cq_host, 0, CQHCI_CTL); + if (cqhci_readl(cq_host, CQHCI_CTL) && CQHCI_HALT) + dev_err(mmc_dev(host->mmc), + "failed to exit halt state when enable CQE\n"); + + + sdhci_cqe_enable(mmc); +} + +static void esdhc_sdhci_dumpregs(struct mmc_host *mmc) +{ + sdhci_dumpregs(mmc_priv(mmc)); +} + +static const struct cqhci_host_ops esdhc_cqhci_ops = { + .enable = esdhc_cqe_enable, + .disable = sdhci_cqe_disable, + .dumpregs = esdhc_sdhci_dumpregs, +}; + #ifdef CONFIG_OF static int sdhci_esdhc_imx_probe_dt(struct platform_device *pdev, @@ -1200,7 +1381,7 @@ static int sdhci_esdhc_imx_probe_nondt(struct platform_device *pdev, host->mmc->parent->platform_data); /* write_protect */ if (boarddata->wp_type == ESDHC_WP_GPIO) { - err = mmc_gpiod_request_ro(host->mmc, "wp", 0, false, 0, NULL); + err = mmc_gpiod_request_ro(host->mmc, "wp", 0, 0, NULL); if (err) { dev_err(mmc_dev(host->mmc), "failed to request write-protect gpio!\n"); @@ -1255,6 +1436,7 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev) of_match_device(imx_esdhc_dt_ids, &pdev->dev); struct sdhci_pltfm_host *pltfm_host; struct sdhci_host *host; + struct cqhci_host *cq_host; int err; struct pltfm_imx_data *imx_data; @@ -1270,6 +1452,10 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev) imx_data->socdata = of_id ? of_id->data : (struct esdhc_soc_data *) pdev->id_entry->driver_data; + if (imx_data->socdata->flags & ESDHC_FLAG_PMQOS) + pm_qos_add_request(&imx_data->pm_qos_req, + PM_QOS_CPU_DMA_LATENCY, 0); + imx_data->clk_ipg = devm_clk_get(&pdev->dev, "ipg"); if (IS_ERR(imx_data->clk_ipg)) { err = PTR_ERR(imx_data->clk_ipg); @@ -1321,6 +1507,12 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev) writel(0x0, host->ioaddr + ESDHC_MIX_CTRL); writel(0x0, host->ioaddr + SDHCI_AUTO_CMD_STATUS); writel(0x0, host->ioaddr + ESDHC_TUNE_CTRL_STATUS); + + /* + * Link usdhc specific mmc_host_ops execute_tuning function, + * to replace the standard one in sdhci_ops. + */ + host->mmc_host_ops.execute_tuning = usdhc_execute_tuning; } if (imx_data->socdata->flags & ESDHC_FLAG_MAN_TUNING) @@ -1333,6 +1525,28 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev) if (imx_data->socdata->flags & ESDHC_FLAG_HS400) host->quirks2 |= SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400; + if (imx_data->socdata->flags & ESDHC_FLAG_HS400_ES) { + host->mmc->caps2 |= MMC_CAP2_HS400_ES; + host->mmc_host_ops.hs400_enhanced_strobe = + esdhc_hs400_enhanced_strobe; + } + + if (imx_data->socdata->flags & ESDHC_FLAG_CQHCI) { + host->mmc->caps2 |= MMC_CAP2_CQE | MMC_CAP2_CQE_DCMD; + cq_host = devm_kzalloc(&pdev->dev, sizeof(*cq_host), GFP_KERNEL); + if (!cq_host) { + err = -ENOMEM; + goto disable_ahb_clk; + } + + cq_host->mmio = host->ioaddr + ESDHC_CQHCI_ADDR_OFFSET; + cq_host->ops = &esdhc_cqhci_ops; + + err = cqhci_init(cq_host, host->mmc, false); + if (err) + goto disable_ahb_clk; + } + if (of_id) err = sdhci_esdhc_imx_probe_dt(pdev, host, imx_data); else @@ -1340,6 +1554,8 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev) if (err) goto disable_ahb_clk; + host->tuning_delay = 1; + sdhci_esdhc_imx_hwinit(host); err = sdhci_add_host(host); @@ -1361,6 +1577,8 @@ disable_ipg_clk: disable_per_clk: clk_disable_unprepare(imx_data->clk_per); free_sdhci: + if (imx_data->socdata->flags & ESDHC_FLAG_PMQOS) + pm_qos_remove_request(&imx_data->pm_qos_req); sdhci_pltfm_free(pdev); return err; } @@ -1382,6 +1600,9 @@ static int sdhci_esdhc_imx_remove(struct platform_device *pdev) clk_disable_unprepare(imx_data->clk_ipg); clk_disable_unprepare(imx_data->clk_ahb); + if (imx_data->socdata->flags & ESDHC_FLAG_PMQOS) + pm_qos_remove_request(&imx_data->pm_qos_req); + sdhci_pltfm_free(pdev); return 0; @@ -1391,6 +1612,13 @@ static int sdhci_esdhc_imx_remove(struct platform_device *pdev) static int sdhci_esdhc_suspend(struct device *dev) { struct sdhci_host *host = dev_get_drvdata(dev); + int ret; + + if (host->mmc->caps2 & MMC_CAP2_CQE) { + ret = cqhci_suspend(host->mmc); + if (ret) + return ret; + } if (host->tuning_mode != SDHCI_TUNING_MODE_3) mmc_retune_needed(host->mmc); @@ -1401,11 +1629,19 @@ static int sdhci_esdhc_suspend(struct device *dev) static int sdhci_esdhc_resume(struct device *dev) { struct sdhci_host *host = dev_get_drvdata(dev); + int ret; /* re-initialize hw state in case it's lost in low power mode */ sdhci_esdhc_imx_hwinit(host); - return sdhci_resume_host(host); + ret = sdhci_resume_host(host); + if (ret) + return ret; + + if (host->mmc->caps2 & MMC_CAP2_CQE) + ret = cqhci_resume(host->mmc); + + return ret; } #endif @@ -1417,6 +1653,12 @@ static int sdhci_esdhc_runtime_suspend(struct device *dev) struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); int ret; + if (host->mmc->caps2 & MMC_CAP2_CQE) { + ret = cqhci_suspend(host->mmc); + if (ret) + return ret; + } + ret = sdhci_runtime_suspend_host(host); if (ret) return ret; @@ -1432,6 +1674,9 @@ static int sdhci_esdhc_runtime_suspend(struct device *dev) } clk_disable_unprepare(imx_data->clk_ahb); + if (imx_data->socdata->flags & ESDHC_FLAG_PMQOS) + pm_qos_remove_request(&imx_data->pm_qos_req); + return ret; } @@ -1442,9 +1687,13 @@ static int sdhci_esdhc_runtime_resume(struct device *dev) struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); int err; + if (imx_data->socdata->flags & ESDHC_FLAG_PMQOS) + pm_qos_add_request(&imx_data->pm_qos_req, + PM_QOS_CPU_DMA_LATENCY, 0); + err = clk_prepare_enable(imx_data->clk_ahb); if (err) - return err; + goto remove_pm_qos_request; if (!sdhci_sdio_irq_enabled(host)) { err = clk_prepare_enable(imx_data->clk_per); @@ -1460,7 +1709,10 @@ static int sdhci_esdhc_runtime_resume(struct device *dev) if (err) goto disable_ipg_clk; - return 0; + if (host->mmc->caps2 & MMC_CAP2_CQE) + err = cqhci_resume(host->mmc); + + return err; disable_ipg_clk: if (!sdhci_sdio_irq_enabled(host)) @@ -1470,6 +1722,9 @@ disable_per_clk: clk_disable_unprepare(imx_data->clk_per); disable_ahb_clk: clk_disable_unprepare(imx_data->clk_ahb); +remove_pm_qos_request: + if (imx_data->socdata->flags & ESDHC_FLAG_PMQOS) + pm_qos_remove_request(&imx_data->pm_qos_req); return err; } #endif diff --git a/drivers/mmc/host/sdhci-of-arasan.c b/drivers/mmc/host/sdhci-of-arasan.c index c9e3e050ccc8..88dc3f00a5be 100644 --- a/drivers/mmc/host/sdhci-of-arasan.c +++ b/drivers/mmc/host/sdhci-of-arasan.c @@ -832,7 +832,10 @@ static int sdhci_arasan_probe(struct platform_device *pdev) host->mmc_host_ops.start_signal_voltage_switch = sdhci_arasan_voltage_switch; sdhci_arasan->has_cqe = true; - host->mmc->caps2 |= MMC_CAP2_CQE | MMC_CAP2_CQE_DCMD; + host->mmc->caps2 |= MMC_CAP2_CQE; + + if (!of_property_read_bool(np, "disable-cqe-dcmd")) + host->mmc->caps2 |= MMC_CAP2_CQE_DCMD; } ret = sdhci_arasan_add_host(sdhci_arasan); diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c index 4e669b4edfc1..e20c00f14109 100644 --- a/drivers/mmc/host/sdhci-of-esdhc.c +++ b/drivers/mmc/host/sdhci-of-esdhc.c @@ -24,6 +24,7 @@ #include <linux/ktime.h> #include <linux/dma-mapping.h> #include <linux/mmc/host.h> +#include <linux/mmc/mmc.h> #include "sdhci-pltfm.h" #include "sdhci-esdhc.h" @@ -81,6 +82,7 @@ struct sdhci_esdhc { bool quirk_limited_clk_division; bool quirk_unreliable_pulse_detection; bool quirk_fixup_tuning; + bool quirk_ignore_data_inhibit; unsigned int peripheral_clock; const struct esdhc_clk_fixup *clk_fixup; u32 div_ratio; @@ -147,6 +149,19 @@ static u32 esdhc_readl_fixup(struct sdhci_host *host, return ret; } + /* + * Some controllers have unreliable Data Line Active + * bit for commands with busy signal. This affects + * Command Inhibit (data) bit. Just ignore it since + * MMC core driver has already polled card status + * with CMD13 after any command with busy siganl. + */ + if ((spec_reg == SDHCI_PRESENT_STATE) && + (esdhc->quirk_ignore_data_inhibit == true)) { + ret = value & ~SDHCI_DATA_INHIBIT; + return ret; + } + ret = value; return ret; } @@ -694,6 +709,9 @@ static void esdhc_reset(struct sdhci_host *host, u8 mask) sdhci_writel(host, host->ier, SDHCI_INT_ENABLE); sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); + if (of_find_compatible_node(NULL, NULL, "fsl,p2020-esdhc")) + mdelay(5); + if (mask & SDHCI_RESET_ALL) { val = sdhci_readl(host, ESDHC_TBCTL); val &= ~ESDHC_TB_EN; @@ -864,6 +882,25 @@ static void esdhc_set_uhs_signaling(struct sdhci_host *host, sdhci_set_uhs_signaling(host, timing); } +static u32 esdhc_irq(struct sdhci_host *host, u32 intmask) +{ + u32 command; + + if (of_find_compatible_node(NULL, NULL, + "fsl,p2020-esdhc")) { + command = SDHCI_GET_CMD(sdhci_readw(host, + SDHCI_COMMAND)); + if (command == MMC_WRITE_MULTIPLE_BLOCK && + sdhci_readw(host, SDHCI_BLOCK_COUNT) && + intmask & SDHCI_INT_DATA_END) { + intmask &= ~SDHCI_INT_DATA_END; + sdhci_writel(host, SDHCI_INT_DATA_END, + SDHCI_INT_STATUS); + } + } + return intmask; +} + #ifdef CONFIG_PM_SLEEP static u32 esdhc_proctl; static int esdhc_of_suspend(struct device *dev) @@ -911,6 +948,7 @@ static const struct sdhci_ops sdhci_esdhc_be_ops = { .set_bus_width = esdhc_pltfm_set_bus_width, .reset = esdhc_reset, .set_uhs_signaling = esdhc_set_uhs_signaling, + .irq = esdhc_irq, }; static const struct sdhci_ops sdhci_esdhc_le_ops = { @@ -928,6 +966,7 @@ static const struct sdhci_ops sdhci_esdhc_le_ops = { .set_bus_width = esdhc_pltfm_set_bus_width, .reset = esdhc_reset, .set_uhs_signaling = esdhc_set_uhs_signaling, + .irq = esdhc_irq, }; static const struct sdhci_pltfm_data sdhci_esdhc_be_pdata = { @@ -955,6 +994,7 @@ static struct soc_device_attribute soc_incorrect_hostver[] = { static struct soc_device_attribute soc_fixup_sdhc_clkdivs[] = { { .family = "QorIQ LX2160A", .revision = "1.0", }, + { .family = "QorIQ LX2160A", .revision = "2.0", }, { }, }; @@ -1074,6 +1114,11 @@ static int sdhci_esdhc_probe(struct platform_device *pdev) if (esdhc->vendor_ver > VENDOR_V_22) host->quirks &= ~SDHCI_QUIRK_NO_BUSY_IRQ; + if (of_find_compatible_node(NULL, NULL, "fsl,p2020-esdhc")) { + host->quirks2 |= SDHCI_QUIRK_RESET_AFTER_REQUEST; + host->quirks2 |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL; + } + if (of_device_is_compatible(np, "fsl,p5040-esdhc") || of_device_is_compatible(np, "fsl,p5020-esdhc") || of_device_is_compatible(np, "fsl,p4080-esdhc") || @@ -1084,12 +1129,14 @@ static int sdhci_esdhc_probe(struct platform_device *pdev) if (of_device_is_compatible(np, "fsl,ls1021a-esdhc")) host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL; + esdhc->quirk_ignore_data_inhibit = false; if (of_device_is_compatible(np, "fsl,p2020-esdhc")) { /* * Freescale messed up with P2020 as it has a non-standard * host control register */ host->quirks2 |= SDHCI_QUIRK2_BROKEN_HOST_CONTROL; + esdhc->quirk_ignore_data_inhibit = true; } /* call to generic mmc_of_parse to support additional capabilities */ diff --git a/drivers/mmc/host/sdhci-omap.c b/drivers/mmc/host/sdhci-omap.c index c11c18a9aacb..bdb80c503fde 100644 --- a/drivers/mmc/host/sdhci-omap.c +++ b/drivers/mmc/host/sdhci-omap.c @@ -785,7 +785,7 @@ static void sdhci_omap_set_uhs_signaling(struct sdhci_host *host, sdhci_omap_start_clock(omap_host); } -void sdhci_omap_reset(struct sdhci_host *host, u8 mask) +static void sdhci_omap_reset(struct sdhci_host *host, u8 mask) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_omap_host *omap_host = sdhci_pltfm_priv(pltfm_host); @@ -797,6 +797,43 @@ void sdhci_omap_reset(struct sdhci_host *host, u8 mask) sdhci_reset(host, mask); } +#define CMD_ERR_MASK (SDHCI_INT_CRC | SDHCI_INT_END_BIT | SDHCI_INT_INDEX |\ + SDHCI_INT_TIMEOUT) +#define CMD_MASK (CMD_ERR_MASK | SDHCI_INT_RESPONSE) + +static u32 sdhci_omap_irq(struct sdhci_host *host, u32 intmask) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_omap_host *omap_host = sdhci_pltfm_priv(pltfm_host); + + if (omap_host->is_tuning && host->cmd && !host->data_early && + (intmask & CMD_ERR_MASK)) { + + /* + * Since we are not resetting data lines during tuning + * operation, data error or data complete interrupts + * might still arrive. Mark this request as a failure + * but still wait for the data interrupt + */ + if (intmask & SDHCI_INT_TIMEOUT) + host->cmd->error = -ETIMEDOUT; + else + host->cmd->error = -EILSEQ; + + host->cmd = NULL; + + /* + * Sometimes command error interrupts and command complete + * interrupt will arrive together. Clear all command related + * interrupts here. + */ + sdhci_writel(host, intmask & CMD_MASK, SDHCI_INT_STATUS); + intmask &= ~CMD_MASK; + } + + return intmask; +} + static struct sdhci_ops sdhci_omap_ops = { .set_clock = sdhci_omap_set_clock, .set_power = sdhci_omap_set_power, @@ -807,6 +844,7 @@ static struct sdhci_ops sdhci_omap_ops = { .platform_send_init_74_clocks = sdhci_omap_init_74_clocks, .reset = sdhci_omap_reset, .set_uhs_signaling = sdhci_omap_set_uhs_signaling, + .irq = sdhci_omap_irq, }; static int sdhci_omap_set_capabilities(struct sdhci_omap_host *omap_host) @@ -1056,6 +1094,9 @@ static int sdhci_omap_probe(struct platform_device *pdev) mmc->f_max = 48000000; } + if (!mmc_can_gpio_ro(mmc)) + mmc->caps2 |= MMC_CAP2_NO_WRITE_PROTECT; + pltfm_host->clk = devm_clk_get(dev, "fck"); if (IS_ERR(pltfm_host->clk)) { ret = PTR_ERR(pltfm_host->clk); @@ -1097,7 +1138,6 @@ static int sdhci_omap_probe(struct platform_device *pdev) goto err_put_sync; } - host->mmc_host_ops.get_ro = mmc_gpio_get_ro; host->mmc_host_ops.start_signal_voltage_switch = sdhci_omap_start_signal_voltage_switch; host->mmc_host_ops.set_ios = sdhci_omap_set_ios; diff --git a/drivers/mmc/host/sdhci-pci-core.c b/drivers/mmc/host/sdhci-pci-core.c index 2a6eba74b94e..ab9e2b901094 100644 --- a/drivers/mmc/host/sdhci-pci-core.c +++ b/drivers/mmc/host/sdhci-pci-core.c @@ -31,6 +31,10 @@ #include <linux/mmc/sdhci-pci-data.h> #include <linux/acpi.h> +#ifdef CONFIG_X86 +#include <asm/iosf_mbi.h> +#endif + #include "cqhci.h" #include "sdhci.h" @@ -451,6 +455,50 @@ static const struct sdhci_pci_fixes sdhci_intel_pch_sdio = { .probe_slot = pch_hc_probe_slot, }; +#ifdef CONFIG_X86 + +#define BYT_IOSF_SCCEP 0x63 +#define BYT_IOSF_OCP_NETCTRL0 0x1078 +#define BYT_IOSF_OCP_TIMEOUT_BASE GENMASK(10, 8) + +static void byt_ocp_setting(struct pci_dev *pdev) +{ + u32 val = 0; + + if (pdev->device != PCI_DEVICE_ID_INTEL_BYT_EMMC && + pdev->device != PCI_DEVICE_ID_INTEL_BYT_SDIO && + pdev->device != PCI_DEVICE_ID_INTEL_BYT_SD && + pdev->device != PCI_DEVICE_ID_INTEL_BYT_EMMC2) + return; + + if (iosf_mbi_read(BYT_IOSF_SCCEP, MBI_CR_READ, BYT_IOSF_OCP_NETCTRL0, + &val)) { + dev_err(&pdev->dev, "%s read error\n", __func__); + return; + } + + if (!(val & BYT_IOSF_OCP_TIMEOUT_BASE)) + return; + + val &= ~BYT_IOSF_OCP_TIMEOUT_BASE; + + if (iosf_mbi_write(BYT_IOSF_SCCEP, MBI_CR_WRITE, BYT_IOSF_OCP_NETCTRL0, + val)) { + dev_err(&pdev->dev, "%s write error\n", __func__); + return; + } + + dev_dbg(&pdev->dev, "%s completed\n", __func__); +} + +#else + +static inline void byt_ocp_setting(struct pci_dev *pdev) +{ +} + +#endif + enum { INTEL_DSM_FNS = 0, INTEL_DSM_V18_SWITCH = 3, @@ -715,6 +763,8 @@ static void byt_probe_slot(struct sdhci_pci_slot *slot) byt_read_dsm(slot); + byt_ocp_setting(slot->chip->pdev); + ops->execute_tuning = intel_execute_tuning; ops->start_signal_voltage_switch = intel_start_signal_voltage_switch; @@ -938,7 +988,35 @@ static int byt_sd_probe_slot(struct sdhci_pci_slot *slot) return 0; } +#ifdef CONFIG_PM_SLEEP + +static int byt_resume(struct sdhci_pci_chip *chip) +{ + byt_ocp_setting(chip->pdev); + + return sdhci_pci_resume_host(chip); +} + +#endif + +#ifdef CONFIG_PM + +static int byt_runtime_resume(struct sdhci_pci_chip *chip) +{ + byt_ocp_setting(chip->pdev); + + return sdhci_pci_runtime_resume_host(chip); +} + +#endif + static const struct sdhci_pci_fixes sdhci_intel_byt_emmc = { +#ifdef CONFIG_PM_SLEEP + .resume = byt_resume, +#endif +#ifdef CONFIG_PM + .runtime_resume = byt_runtime_resume, +#endif .allow_runtime_pm = true, .probe_slot = byt_emmc_probe_slot, .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC | @@ -972,6 +1050,12 @@ static const struct sdhci_pci_fixes sdhci_intel_glk_emmc = { }; static const struct sdhci_pci_fixes sdhci_ni_byt_sdio = { +#ifdef CONFIG_PM_SLEEP + .resume = byt_resume, +#endif +#ifdef CONFIG_PM + .runtime_resume = byt_runtime_resume, +#endif .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC | SDHCI_QUIRK_NO_LED, .quirks2 = SDHCI_QUIRK2_HOST_OFF_CARD_ON | @@ -983,6 +1067,12 @@ static const struct sdhci_pci_fixes sdhci_ni_byt_sdio = { }; static const struct sdhci_pci_fixes sdhci_intel_byt_sdio = { +#ifdef CONFIG_PM_SLEEP + .resume = byt_resume, +#endif +#ifdef CONFIG_PM + .runtime_resume = byt_runtime_resume, +#endif .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC | SDHCI_QUIRK_NO_LED, .quirks2 = SDHCI_QUIRK2_HOST_OFF_CARD_ON | @@ -994,6 +1084,12 @@ static const struct sdhci_pci_fixes sdhci_intel_byt_sdio = { }; static const struct sdhci_pci_fixes sdhci_intel_byt_sd = { +#ifdef CONFIG_PM_SLEEP + .resume = byt_resume, +#endif +#ifdef CONFIG_PM + .runtime_resume = byt_runtime_resume, +#endif .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC | SDHCI_QUIRK_NO_LED, .quirks2 = SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON | @@ -1257,16 +1353,6 @@ static int jmicron_resume(struct sdhci_pci_chip *chip) } #endif -static const struct sdhci_pci_fixes sdhci_o2 = { - .probe = sdhci_pci_o2_probe, - .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, - .quirks2 = SDHCI_QUIRK2_CLEAR_TRANSFERMODE_REG_BEFORE_CMD, - .probe_slot = sdhci_pci_o2_probe_slot, -#ifdef CONFIG_PM_SLEEP - .resume = sdhci_pci_o2_resume, -#endif -}; - static const struct sdhci_pci_fixes sdhci_jmicron = { .probe = jmicron_probe, @@ -1586,6 +1672,8 @@ static const struct pci_device_id pci_ids[] = { SDHCI_PCI_DEVICE(INTEL, CNPH_SD, intel_byt_sd), SDHCI_PCI_DEVICE(INTEL, ICP_EMMC, intel_glk_emmc), SDHCI_PCI_DEVICE(INTEL, ICP_SD, intel_byt_sd), + SDHCI_PCI_DEVICE(INTEL, CML_EMMC, intel_glk_emmc), + SDHCI_PCI_DEVICE(INTEL, CML_SD, intel_byt_sd), SDHCI_PCI_DEVICE(O2, 8120, o2), SDHCI_PCI_DEVICE(O2, 8220, o2), SDHCI_PCI_DEVICE(O2, 8221, o2), diff --git a/drivers/mmc/host/sdhci-pci-o2micro.c b/drivers/mmc/host/sdhci-pci-o2micro.c index cc3ffeffd7a2..05a012a694b2 100644 --- a/drivers/mmc/host/sdhci-pci-o2micro.c +++ b/drivers/mmc/host/sdhci-pci-o2micro.c @@ -60,6 +60,13 @@ #define O2_SD_VENDOR_SETTING2 0x1C8 #define O2_SD_HW_TUNING_DISABLE BIT(4) +#define O2_PLL_WDT_CONTROL1 0x1CC +#define O2_PLL_FORCE_ACTIVE BIT(18) +#define O2_PLL_LOCK_STATUS BIT(14) +#define O2_PLL_SOFT_RESET BIT(12) + +#define O2_SD_DETECT_SETTING 0x324 + static void sdhci_o2_set_tuning_mode(struct sdhci_host *host) { u16 reg; @@ -283,6 +290,113 @@ static void sdhci_pci_o2_enable_msi(struct sdhci_pci_chip *chip, host->irq = pci_irq_vector(chip->pdev, 0); } +static void sdhci_o2_wait_card_detect_stable(struct sdhci_host *host) +{ + ktime_t timeout; + u32 scratch32; + + /* Wait max 50 ms */ + timeout = ktime_add_ms(ktime_get(), 50); + while (1) { + bool timedout = ktime_after(ktime_get(), timeout); + + scratch32 = sdhci_readl(host, SDHCI_PRESENT_STATE); + if ((scratch32 & SDHCI_CARD_PRESENT) >> SDHCI_CARD_PRES_SHIFT + == (scratch32 & SDHCI_CD_LVL) >> SDHCI_CD_LVL_SHIFT) + break; + + if (timedout) { + pr_err("%s: Card Detect debounce never finished.\n", + mmc_hostname(host->mmc)); + sdhci_dumpregs(host); + return; + } + udelay(10); + } +} + +static void sdhci_o2_enable_internal_clock(struct sdhci_host *host) +{ + ktime_t timeout; + u16 scratch; + u32 scratch32; + + /* PLL software reset */ + scratch32 = sdhci_readl(host, O2_PLL_WDT_CONTROL1); + scratch32 |= O2_PLL_SOFT_RESET; + sdhci_writel(host, scratch32, O2_PLL_WDT_CONTROL1); + udelay(1); + scratch32 &= ~(O2_PLL_SOFT_RESET); + sdhci_writel(host, scratch32, O2_PLL_WDT_CONTROL1); + + /* PLL force active */ + scratch32 |= O2_PLL_FORCE_ACTIVE; + sdhci_writel(host, scratch32, O2_PLL_WDT_CONTROL1); + + /* Wait max 20 ms */ + timeout = ktime_add_ms(ktime_get(), 20); + while (1) { + bool timedout = ktime_after(ktime_get(), timeout); + + scratch = sdhci_readw(host, O2_PLL_WDT_CONTROL1); + if (scratch & O2_PLL_LOCK_STATUS) + break; + if (timedout) { + pr_err("%s: Internal clock never stabilised.\n", + mmc_hostname(host->mmc)); + sdhci_dumpregs(host); + goto out; + } + udelay(10); + } + + /* Wait for card detect finish */ + udelay(1); + sdhci_o2_wait_card_detect_stable(host); + +out: + /* Cancel PLL force active */ + scratch32 = sdhci_readl(host, O2_PLL_WDT_CONTROL1); + scratch32 &= ~O2_PLL_FORCE_ACTIVE; + sdhci_writel(host, scratch32, O2_PLL_WDT_CONTROL1); +} + +static int sdhci_o2_get_cd(struct mmc_host *mmc) +{ + struct sdhci_host *host = mmc_priv(mmc); + + sdhci_o2_enable_internal_clock(host); + + return !!(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT); +} + +static void sdhci_o2_enable_clk(struct sdhci_host *host, u16 clk) +{ + /* Enable internal clock */ + clk |= SDHCI_CLOCK_INT_EN; + sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); + + if (sdhci_o2_get_cd(host->mmc)) { + clk |= SDHCI_CLOCK_CARD_EN; + sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); + } +} + +void sdhci_pci_o2_set_clock(struct sdhci_host *host, unsigned int clock) +{ + u16 clk; + + host->mmc->actual_clock = 0; + + sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL); + + if (clock == 0) + return; + + clk = sdhci_calc_clk(host, clock, &host->mmc->actual_clock); + sdhci_o2_enable_clk(host, clk); +} + int sdhci_pci_o2_probe_slot(struct sdhci_pci_slot *slot) { struct sdhci_pci_chip *chip; @@ -314,9 +428,14 @@ int sdhci_pci_o2_probe_slot(struct sdhci_pci_slot *slot) mmc_hostname(host->mmc)); host->flags &= ~SDHCI_SIGNALING_330; host->flags |= SDHCI_SIGNALING_180; + host->quirks2 |= SDHCI_QUIRK2_CLEAR_TRANSFERMODE_REG_BEFORE_CMD; host->mmc->caps2 |= MMC_CAP2_NO_SD; host->mmc->caps2 |= MMC_CAP2_NO_SDIO; + pci_write_config_dword(chip->pdev, + O2_SD_DETECT_SETTING, 3); } + + slot->host->mmc_host_ops.get_cd = sdhci_o2_get_cd; } host->mmc_host_ops.execute_tuning = sdhci_o2_execute_tuning; @@ -490,9 +609,6 @@ int sdhci_pci_o2_probe(struct sdhci_pci_chip *chip) pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch); break; case PCI_DEVICE_ID_O2_SEABIRD0: - if (chip->pdev->revision == 0x01) - chip->quirks |= SDHCI_QUIRK_DELAY_AFTER_POWER; - /* fall through */ case PCI_DEVICE_ID_O2_SEABIRD1: /* UnLock WP */ ret = pci_read_config_byte(chip->pdev, @@ -550,3 +666,21 @@ int sdhci_pci_o2_resume(struct sdhci_pci_chip *chip) return sdhci_pci_resume_host(chip); } #endif + +static const struct sdhci_ops sdhci_pci_o2_ops = { + .set_clock = sdhci_pci_o2_set_clock, + .enable_dma = sdhci_pci_enable_dma, + .set_bus_width = sdhci_set_bus_width, + .reset = sdhci_reset, + .set_uhs_signaling = sdhci_set_uhs_signaling, +}; + +const struct sdhci_pci_fixes sdhci_o2 = { + .probe = sdhci_pci_o2_probe, + .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, + .probe_slot = sdhci_pci_o2_probe_slot, +#ifdef CONFIG_PM_SLEEP + .resume = sdhci_pci_o2_resume, +#endif + .ops = &sdhci_pci_o2_ops, +}; diff --git a/drivers/mmc/host/sdhci-pci.h b/drivers/mmc/host/sdhci-pci.h index 2ef0bdca9197..e5dc6e44c7a4 100644 --- a/drivers/mmc/host/sdhci-pci.h +++ b/drivers/mmc/host/sdhci-pci.h @@ -50,6 +50,8 @@ #define PCI_DEVICE_ID_INTEL_CNPH_SD 0xa375 #define PCI_DEVICE_ID_INTEL_ICP_EMMC 0x34c4 #define PCI_DEVICE_ID_INTEL_ICP_SD 0x34f8 +#define PCI_DEVICE_ID_INTEL_CML_EMMC 0x02c4 +#define PCI_DEVICE_ID_INTEL_CML_SD 0x02f5 #define PCI_DEVICE_ID_SYSKONNECT_8000 0x8000 #define PCI_DEVICE_ID_VIA_95D0 0x95d0 @@ -179,13 +181,9 @@ static inline void *sdhci_pci_priv(struct sdhci_pci_slot *slot) int sdhci_pci_resume_host(struct sdhci_pci_chip *chip); #endif int sdhci_pci_enable_dma(struct sdhci_host *host); -int sdhci_pci_o2_probe_slot(struct sdhci_pci_slot *slot); -int sdhci_pci_o2_probe(struct sdhci_pci_chip *chip); -#ifdef CONFIG_PM_SLEEP -int sdhci_pci_o2_resume(struct sdhci_pci_chip *chip); -#endif extern const struct sdhci_pci_fixes sdhci_arasan; extern const struct sdhci_pci_fixes sdhci_snps; +extern const struct sdhci_pci_fixes sdhci_o2; #endif /* __SDHCI_PCI_H */ diff --git a/drivers/mmc/host/sdhci-pxav2.c b/drivers/mmc/host/sdhci-pxav2.c index 2c3827f54927..cdc8e16b4567 100644 --- a/drivers/mmc/host/sdhci-pxav2.c +++ b/drivers/mmc/host/sdhci-pxav2.c @@ -23,7 +23,6 @@ #include <linux/clk.h> #include <linux/module.h> #include <linux/io.h> -#include <linux/gpio.h> #include <linux/mmc/card.h> #include <linux/mmc/host.h> #include <linux/platform_data/pxa_sdhci.h> diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c index e6ace31e2a41..f608417ae967 100644 --- a/drivers/mmc/host/sdhci-tegra.c +++ b/drivers/mmc/host/sdhci-tegra.c @@ -33,6 +33,7 @@ #include <linux/ktime.h> #include "sdhci-pltfm.h" +#include "cqhci.h" /* Tegra SDHOST controller vendor register definitions */ #define SDHCI_TEGRA_VENDOR_CLOCK_CTRL 0x100 @@ -65,6 +66,22 @@ #define SDHCI_VNDR_TUN_CTRL0_0 0x1c0 #define SDHCI_VNDR_TUN_CTRL0_TUN_HW_TAP 0x20000 +#define SDHCI_VNDR_TUN_CTRL0_START_TAP_VAL_MASK 0x03fc0000 +#define SDHCI_VNDR_TUN_CTRL0_START_TAP_VAL_SHIFT 18 +#define SDHCI_VNDR_TUN_CTRL0_MUL_M_MASK 0x00001fc0 +#define SDHCI_VNDR_TUN_CTRL0_MUL_M_SHIFT 6 +#define SDHCI_VNDR_TUN_CTRL0_TUN_ITER_MASK 0x000e000 +#define SDHCI_VNDR_TUN_CTRL0_TUN_ITER_SHIFT 13 +#define TRIES_128 2 +#define TRIES_256 4 +#define SDHCI_VNDR_TUN_CTRL0_TUN_WORD_SEL_MASK 0x7 + +#define SDHCI_TEGRA_VNDR_TUN_CTRL1_0 0x1c4 +#define SDHCI_TEGRA_VNDR_TUN_STATUS0 0x1C8 +#define SDHCI_TEGRA_VNDR_TUN_STATUS1 0x1CC +#define SDHCI_TEGRA_VNDR_TUN_STATUS1_TAP_MASK 0xFF +#define SDHCI_TEGRA_VNDR_TUN_STATUS1_END_TAP_SHIFT 0x8 +#define TUNING_WORD_BIT_SIZE 32 #define SDHCI_TEGRA_AUTO_CAL_CONFIG 0x1e4 #define SDHCI_AUTO_CAL_START BIT(31) @@ -75,6 +92,7 @@ #define SDHCI_TEGRA_SDMEM_COMP_PADCTRL_VREF_SEL_MASK 0x0000000f #define SDHCI_TEGRA_SDMEM_COMP_PADCTRL_VREF_SEL_VAL 0x7 #define SDHCI_TEGRA_SDMEM_COMP_PADCTRL_E_INPUT_E_PWRD BIT(31) +#define SDHCI_COMP_PADCTRL_DRVUPDN_OFFSET_MASK 0x07FFF000 #define SDHCI_TEGRA_AUTO_CAL_STATUS 0x1ec #define SDHCI_TEGRA_AUTO_CAL_ACTIVE BIT(31) @@ -88,10 +106,16 @@ #define NVQUIRK_HAS_PADCALIB BIT(6) #define NVQUIRK_NEEDS_PAD_CONTROL BIT(7) #define NVQUIRK_DIS_CARD_CLK_CONFIG_TAP BIT(8) +#define NVQUIRK_CQHCI_DCMD_R1B_CMD_TIMING BIT(9) + +/* SDMMC CQE Base Address for Tegra Host Ver 4.1 and Higher */ +#define SDHCI_TEGRA_CQE_BASE_ADDR 0xF000 struct sdhci_tegra_soc_data { const struct sdhci_pltfm_data *pdata; u32 nvquirks; + u8 min_tap_delay; + u8 max_tap_delay; }; /* Magic pull up and pull down pad calibration offsets */ @@ -121,6 +145,8 @@ struct sdhci_tegra { struct pinctrl *pinctrl_sdmmc; struct pinctrl_state *pinctrl_state_3v3; struct pinctrl_state *pinctrl_state_1v8; + struct pinctrl_state *pinctrl_state_3v3_drv; + struct pinctrl_state *pinctrl_state_1v8_drv; struct sdhci_tegra_autocal_offsets autocal_offsets; ktime_t last_calib; @@ -128,6 +154,9 @@ struct sdhci_tegra { u32 default_tap; u32 default_trim; u32 dqs_trim; + bool enable_hwcq; + unsigned long curr_clk_rate; + u8 tuned_tap_delay; }; static u16 tegra_sdhci_readw(struct sdhci_host *host, int reg) @@ -233,15 +262,11 @@ static void tegra210_sdhci_writew(struct sdhci_host *host, u16 val, int reg) if (is_tuning_cmd) { udelay(1); + sdhci_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA); tegra_sdhci_configure_card_clk(host, clk_enabled); } } -static unsigned int tegra_sdhci_get_ro(struct sdhci_host *host) -{ - return mmc_gpio_get_ro(host->mmc); -} - static bool tegra_sdhci_is_pad_and_regulator_valid(struct sdhci_host *host) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); @@ -411,6 +436,76 @@ static void tegra_sdhci_set_pad_autocal_offset(struct sdhci_host *host, sdhci_writel(host, reg, SDHCI_TEGRA_AUTO_CAL_CONFIG); } +static int tegra_sdhci_set_padctrl(struct sdhci_host *host, int voltage, + bool state_drvupdn) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); + struct sdhci_tegra_autocal_offsets *offsets = + &tegra_host->autocal_offsets; + struct pinctrl_state *pinctrl_drvupdn = NULL; + int ret = 0; + u8 drvup = 0, drvdn = 0; + u32 reg; + + if (!state_drvupdn) { + /* PADS Drive Strength */ + if (voltage == MMC_SIGNAL_VOLTAGE_180) { + if (tegra_host->pinctrl_state_1v8_drv) { + pinctrl_drvupdn = + tegra_host->pinctrl_state_1v8_drv; + } else { + drvup = offsets->pull_up_1v8_timeout; + drvdn = offsets->pull_down_1v8_timeout; + } + } else { + if (tegra_host->pinctrl_state_3v3_drv) { + pinctrl_drvupdn = + tegra_host->pinctrl_state_3v3_drv; + } else { + drvup = offsets->pull_up_3v3_timeout; + drvdn = offsets->pull_down_3v3_timeout; + } + } + + if (pinctrl_drvupdn != NULL) { + ret = pinctrl_select_state(tegra_host->pinctrl_sdmmc, + pinctrl_drvupdn); + if (ret < 0) + dev_err(mmc_dev(host->mmc), + "failed pads drvupdn, ret: %d\n", ret); + } else if ((drvup) || (drvdn)) { + reg = sdhci_readl(host, + SDHCI_TEGRA_SDMEM_COMP_PADCTRL); + reg &= ~SDHCI_COMP_PADCTRL_DRVUPDN_OFFSET_MASK; + reg |= (drvup << 20) | (drvdn << 12); + sdhci_writel(host, reg, + SDHCI_TEGRA_SDMEM_COMP_PADCTRL); + } + + } else { + /* Dual Voltage PADS Voltage selection */ + if (!tegra_host->pad_control_available) + return 0; + + if (voltage == MMC_SIGNAL_VOLTAGE_180) { + ret = pinctrl_select_state(tegra_host->pinctrl_sdmmc, + tegra_host->pinctrl_state_1v8); + if (ret < 0) + dev_err(mmc_dev(host->mmc), + "setting 1.8V failed, ret: %d\n", ret); + } else { + ret = pinctrl_select_state(tegra_host->pinctrl_sdmmc, + tegra_host->pinctrl_state_3v3); + if (ret < 0) + dev_err(mmc_dev(host->mmc), + "setting 3.3V failed, ret: %d\n", ret); + } + } + + return ret; +} + static void tegra_sdhci_pad_autocalib(struct sdhci_host *host) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); @@ -437,6 +532,7 @@ static void tegra_sdhci_pad_autocalib(struct sdhci_host *host) pdpu = offsets.pull_down_3v3 << 8 | offsets.pull_up_3v3; } + /* Set initial offset before auto-calibration */ tegra_sdhci_set_pad_autocal_offset(host, pdpu); card_clk_enabled = tegra_sdhci_configure_card_clk(host, false); @@ -460,19 +556,15 @@ static void tegra_sdhci_pad_autocalib(struct sdhci_host *host) if (ret) { dev_err(mmc_dev(host->mmc), "Pad autocal timed out\n"); - if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_180) - pdpu = offsets.pull_down_1v8_timeout << 8 | - offsets.pull_up_1v8_timeout; - else - pdpu = offsets.pull_down_3v3_timeout << 8 | - offsets.pull_up_3v3_timeout; - - /* Disable automatic calibration and use fixed offsets */ + /* Disable automatic cal and use fixed Drive Strengths */ reg = sdhci_readl(host, SDHCI_TEGRA_AUTO_CAL_CONFIG); reg &= ~SDHCI_AUTO_CAL_ENABLE; sdhci_writel(host, reg, SDHCI_TEGRA_AUTO_CAL_CONFIG); - tegra_sdhci_set_pad_autocal_offset(host, pdpu); + ret = tegra_sdhci_set_padctrl(host, ios->signal_voltage, false); + if (ret < 0) + dev_err(mmc_dev(host->mmc), + "Setting drive strengths failed: %d\n", ret); } } @@ -511,26 +603,46 @@ static void tegra_sdhci_parse_pad_autocal_dt(struct sdhci_host *host) err = device_property_read_u32(host->mmc->parent, "nvidia,pad-autocal-pull-up-offset-3v3-timeout", &autocal->pull_up_3v3_timeout); - if (err) + if (err) { + if (!IS_ERR(tegra_host->pinctrl_state_3v3) && + (tegra_host->pinctrl_state_3v3_drv == NULL)) + pr_warn("%s: Missing autocal timeout 3v3-pad drvs\n", + mmc_hostname(host->mmc)); autocal->pull_up_3v3_timeout = 0; + } err = device_property_read_u32(host->mmc->parent, "nvidia,pad-autocal-pull-down-offset-3v3-timeout", &autocal->pull_down_3v3_timeout); - if (err) + if (err) { + if (!IS_ERR(tegra_host->pinctrl_state_3v3) && + (tegra_host->pinctrl_state_3v3_drv == NULL)) + pr_warn("%s: Missing autocal timeout 3v3-pad drvs\n", + mmc_hostname(host->mmc)); autocal->pull_down_3v3_timeout = 0; + } err = device_property_read_u32(host->mmc->parent, "nvidia,pad-autocal-pull-up-offset-1v8-timeout", &autocal->pull_up_1v8_timeout); - if (err) + if (err) { + if (!IS_ERR(tegra_host->pinctrl_state_1v8) && + (tegra_host->pinctrl_state_1v8_drv == NULL)) + pr_warn("%s: Missing autocal timeout 1v8-pad drvs\n", + mmc_hostname(host->mmc)); autocal->pull_up_1v8_timeout = 0; + } err = device_property_read_u32(host->mmc->parent, "nvidia,pad-autocal-pull-down-offset-1v8-timeout", &autocal->pull_down_1v8_timeout); - if (err) + if (err) { + if (!IS_ERR(tegra_host->pinctrl_state_1v8) && + (tegra_host->pinctrl_state_1v8_drv == NULL)) + pr_warn("%s: Missing autocal timeout 1v8-pad drvs\n", + mmc_hostname(host->mmc)); autocal->pull_down_1v8_timeout = 0; + } err = device_property_read_u32(host->mmc->parent, "nvidia,pad-autocal-pull-up-offset-sdr104", @@ -595,6 +707,20 @@ static void tegra_sdhci_parse_tap_and_trim(struct sdhci_host *host) tegra_host->dqs_trim = 0x11; } +static void tegra_sdhci_parse_dt(struct sdhci_host *host) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); + + if (device_property_read_bool(host->mmc->parent, "supports-cqe")) + tegra_host->enable_hwcq = true; + else + tegra_host->enable_hwcq = false; + + tegra_sdhci_parse_pad_autocal_dt(host); + tegra_sdhci_parse_tap_and_trim(host); +} + static void tegra_sdhci_set_clock(struct sdhci_host *host, unsigned int clock) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); @@ -618,6 +744,7 @@ static void tegra_sdhci_set_clock(struct sdhci_host *host, unsigned int clock) */ host_clk = tegra_host->ddr_signaling ? clock * 2 : clock; clk_set_rate(pltfm_host->clk, host_clk); + tegra_host->curr_clk_rate = host_clk; if (tegra_host->ddr_signaling) host->max_clk = host_clk; else @@ -666,6 +793,159 @@ static void tegra_sdhci_hs400_dll_cal(struct sdhci_host *host) "HS400 delay line calibration timed out\n"); } +static void tegra_sdhci_tap_correction(struct sdhci_host *host, u8 thd_up, + u8 thd_low, u8 fixed_tap) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); + u32 val, tun_status; + u8 word, bit, edge1, tap, window; + bool tap_result; + bool start_fail = false; + bool start_pass = false; + bool end_pass = false; + bool first_fail = false; + bool first_pass = false; + u8 start_pass_tap = 0; + u8 end_pass_tap = 0; + u8 first_fail_tap = 0; + u8 first_pass_tap = 0; + u8 total_tuning_words = host->tuning_loop_count / TUNING_WORD_BIT_SIZE; + + /* + * Read auto-tuned results and extract good valid passing window by + * filtering out un-wanted bubble/partial/merged windows. + */ + for (word = 0; word < total_tuning_words; word++) { + val = sdhci_readl(host, SDHCI_VNDR_TUN_CTRL0_0); + val &= ~SDHCI_VNDR_TUN_CTRL0_TUN_WORD_SEL_MASK; + val |= word; + sdhci_writel(host, val, SDHCI_VNDR_TUN_CTRL0_0); + tun_status = sdhci_readl(host, SDHCI_TEGRA_VNDR_TUN_STATUS0); + bit = 0; + while (bit < TUNING_WORD_BIT_SIZE) { + tap = word * TUNING_WORD_BIT_SIZE + bit; + tap_result = tun_status & (1 << bit); + if (!tap_result && !start_fail) { + start_fail = true; + if (!first_fail) { + first_fail_tap = tap; + first_fail = true; + } + + } else if (tap_result && start_fail && !start_pass) { + start_pass_tap = tap; + start_pass = true; + if (!first_pass) { + first_pass_tap = tap; + first_pass = true; + } + + } else if (!tap_result && start_fail && start_pass && + !end_pass) { + end_pass_tap = tap - 1; + end_pass = true; + } else if (tap_result && start_pass && start_fail && + end_pass) { + window = end_pass_tap - start_pass_tap; + /* discard merged window and bubble window */ + if (window >= thd_up || window < thd_low) { + start_pass_tap = tap; + end_pass = false; + } else { + /* set tap at middle of valid window */ + tap = start_pass_tap + window / 2; + tegra_host->tuned_tap_delay = tap; + return; + } + } + + bit++; + } + } + + if (!first_fail) { + WARN_ON("no edge detected, continue with hw tuned delay.\n"); + } else if (first_pass) { + /* set tap location at fixed tap relative to the first edge */ + edge1 = first_fail_tap + (first_pass_tap - first_fail_tap) / 2; + if (edge1 - 1 > fixed_tap) + tegra_host->tuned_tap_delay = edge1 - fixed_tap; + else + tegra_host->tuned_tap_delay = edge1 + fixed_tap; + } +} + +static void tegra_sdhci_post_tuning(struct sdhci_host *host) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); + const struct sdhci_tegra_soc_data *soc_data = tegra_host->soc_data; + u32 avg_tap_dly, val, min_tap_dly, max_tap_dly; + u8 fixed_tap, start_tap, end_tap, window_width; + u8 thdupper, thdlower; + u8 num_iter; + u32 clk_rate_mhz, period_ps, bestcase, worstcase; + + /* retain HW tuned tap to use incase if no correction is needed */ + val = sdhci_readl(host, SDHCI_TEGRA_VENDOR_CLOCK_CTRL); + tegra_host->tuned_tap_delay = (val & SDHCI_CLOCK_CTRL_TAP_MASK) >> + SDHCI_CLOCK_CTRL_TAP_SHIFT; + if (soc_data->min_tap_delay && soc_data->max_tap_delay) { + min_tap_dly = soc_data->min_tap_delay; + max_tap_dly = soc_data->max_tap_delay; + clk_rate_mhz = tegra_host->curr_clk_rate / USEC_PER_SEC; + period_ps = USEC_PER_SEC / clk_rate_mhz; + bestcase = period_ps / min_tap_dly; + worstcase = period_ps / max_tap_dly; + /* + * Upper and Lower bound thresholds used to detect merged and + * bubble windows + */ + thdupper = (2 * worstcase + bestcase) / 2; + thdlower = worstcase / 4; + /* + * fixed tap is used when HW tuning result contains single edge + * and tap is set at fixed tap delay relative to the first edge + */ + avg_tap_dly = (period_ps * 2) / (min_tap_dly + max_tap_dly); + fixed_tap = avg_tap_dly / 2; + + val = sdhci_readl(host, SDHCI_TEGRA_VNDR_TUN_STATUS1); + start_tap = val & SDHCI_TEGRA_VNDR_TUN_STATUS1_TAP_MASK; + end_tap = (val >> SDHCI_TEGRA_VNDR_TUN_STATUS1_END_TAP_SHIFT) & + SDHCI_TEGRA_VNDR_TUN_STATUS1_TAP_MASK; + window_width = end_tap - start_tap; + num_iter = host->tuning_loop_count; + /* + * partial window includes edges of the tuning range. + * merged window includes more taps so window width is higher + * than upper threshold. + */ + if (start_tap == 0 || (end_tap == (num_iter - 1)) || + (end_tap == num_iter - 2) || window_width >= thdupper) { + pr_debug("%s: Apply tuning correction\n", + mmc_hostname(host->mmc)); + tegra_sdhci_tap_correction(host, thdupper, thdlower, + fixed_tap); + } + } + + tegra_sdhci_set_tap(host, tegra_host->tuned_tap_delay); +} + +static int tegra_sdhci_execute_hw_tuning(struct mmc_host *mmc, u32 opcode) +{ + struct sdhci_host *host = mmc_priv(mmc); + int err; + + err = sdhci_execute_tuning(mmc, opcode); + if (!err && !host->tuning_err) + tegra_sdhci_post_tuning(host); + + return err; +} + static void tegra_sdhci_set_uhs_signaling(struct sdhci_host *host, unsigned timing) { @@ -674,16 +954,22 @@ static void tegra_sdhci_set_uhs_signaling(struct sdhci_host *host, bool set_default_tap = false; bool set_dqs_trim = false; bool do_hs400_dll_cal = false; + u8 iter = TRIES_256; + u32 val; + tegra_host->ddr_signaling = false; switch (timing) { case MMC_TIMING_UHS_SDR50: + break; case MMC_TIMING_UHS_SDR104: case MMC_TIMING_MMC_HS200: /* Don't set default tap on tunable modes. */ + iter = TRIES_128; break; case MMC_TIMING_MMC_HS400: set_dqs_trim = true; do_hs400_dll_cal = true; + iter = TRIES_128; break; case MMC_TIMING_MMC_DDR52: case MMC_TIMING_UHS_DDR50: @@ -695,11 +981,25 @@ static void tegra_sdhci_set_uhs_signaling(struct sdhci_host *host, break; } + val = sdhci_readl(host, SDHCI_VNDR_TUN_CTRL0_0); + val &= ~(SDHCI_VNDR_TUN_CTRL0_TUN_ITER_MASK | + SDHCI_VNDR_TUN_CTRL0_START_TAP_VAL_MASK | + SDHCI_VNDR_TUN_CTRL0_MUL_M_MASK); + val |= (iter << SDHCI_VNDR_TUN_CTRL0_TUN_ITER_SHIFT | + 0 << SDHCI_VNDR_TUN_CTRL0_START_TAP_VAL_SHIFT | + 1 << SDHCI_VNDR_TUN_CTRL0_MUL_M_SHIFT); + sdhci_writel(host, val, SDHCI_VNDR_TUN_CTRL0_0); + sdhci_writel(host, 0, SDHCI_TEGRA_VNDR_TUN_CTRL1_0); + + host->tuning_loop_count = (iter == TRIES_128) ? 128 : 256; + sdhci_set_uhs_signaling(host, timing); tegra_sdhci_pad_autocalib(host); - if (set_default_tap) + if (tegra_host->tuned_tap_delay && !set_default_tap) + tegra_sdhci_set_tap(host, tegra_host->tuned_tap_delay); + else tegra_sdhci_set_tap(host, tegra_host->default_tap); if (set_dqs_trim) @@ -743,32 +1043,6 @@ static int tegra_sdhci_execute_tuning(struct sdhci_host *host, u32 opcode) return mmc_send_tuning(host->mmc, opcode, NULL); } -static int tegra_sdhci_set_padctrl(struct sdhci_host *host, int voltage) -{ - struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); - int ret; - - if (!tegra_host->pad_control_available) - return 0; - - if (voltage == MMC_SIGNAL_VOLTAGE_180) { - ret = pinctrl_select_state(tegra_host->pinctrl_sdmmc, - tegra_host->pinctrl_state_1v8); - if (ret < 0) - dev_err(mmc_dev(host->mmc), - "setting 1.8V failed, ret: %d\n", ret); - } else { - ret = pinctrl_select_state(tegra_host->pinctrl_sdmmc, - tegra_host->pinctrl_state_3v3); - if (ret < 0) - dev_err(mmc_dev(host->mmc), - "setting 3.3V failed, ret: %d\n", ret); - } - - return ret; -} - static int sdhci_tegra_start_signal_voltage_switch(struct mmc_host *mmc, struct mmc_ios *ios) { @@ -778,7 +1052,7 @@ static int sdhci_tegra_start_signal_voltage_switch(struct mmc_host *mmc, int ret = 0; if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) { - ret = tegra_sdhci_set_padctrl(host, ios->signal_voltage); + ret = tegra_sdhci_set_padctrl(host, ios->signal_voltage, true); if (ret < 0) return ret; ret = sdhci_start_signal_voltage_switch(mmc, ios); @@ -786,7 +1060,7 @@ static int sdhci_tegra_start_signal_voltage_switch(struct mmc_host *mmc, ret = sdhci_start_signal_voltage_switch(mmc, ios); if (ret < 0) return ret; - ret = tegra_sdhci_set_padctrl(host, ios->signal_voltage); + ret = tegra_sdhci_set_padctrl(host, ios->signal_voltage, true); } if (tegra_host->pad_calib_required) @@ -805,6 +1079,20 @@ static int tegra_sdhci_init_pinctrl_info(struct device *dev, return -1; } + tegra_host->pinctrl_state_1v8_drv = pinctrl_lookup_state( + tegra_host->pinctrl_sdmmc, "sdmmc-1v8-drv"); + if (IS_ERR(tegra_host->pinctrl_state_1v8_drv)) { + if (PTR_ERR(tegra_host->pinctrl_state_1v8_drv) == -ENODEV) + tegra_host->pinctrl_state_1v8_drv = NULL; + } + + tegra_host->pinctrl_state_3v3_drv = pinctrl_lookup_state( + tegra_host->pinctrl_sdmmc, "sdmmc-3v3-drv"); + if (IS_ERR(tegra_host->pinctrl_state_3v3_drv)) { + if (PTR_ERR(tegra_host->pinctrl_state_3v3_drv) == -ENODEV) + tegra_host->pinctrl_state_3v3_drv = NULL; + } + tegra_host->pinctrl_state_3v3 = pinctrl_lookup_state(tegra_host->pinctrl_sdmmc, "sdmmc-3v3"); if (IS_ERR(tegra_host->pinctrl_state_3v3)) { @@ -836,8 +1124,115 @@ static void tegra_sdhci_voltage_switch(struct sdhci_host *host) tegra_host->pad_calib_required = true; } +static void tegra_cqhci_writel(struct cqhci_host *cq_host, u32 val, int reg) +{ + struct mmc_host *mmc = cq_host->mmc; + u8 ctrl; + ktime_t timeout; + bool timed_out; + + /* + * During CQE resume/unhalt, CQHCI driver unhalts CQE prior to + * cqhci_host_ops enable where SDHCI DMA and BLOCK_SIZE registers need + * to be re-configured. + * Tegra CQHCI/SDHCI prevents write access to block size register when + * CQE is unhalted. So handling CQE resume sequence here to configure + * SDHCI block registers prior to exiting CQE halt state. + */ + if (reg == CQHCI_CTL && !(val & CQHCI_HALT) && + cqhci_readl(cq_host, CQHCI_CTL) & CQHCI_HALT) { + sdhci_cqe_enable(mmc); + writel(val, cq_host->mmio + reg); + timeout = ktime_add_us(ktime_get(), 50); + while (1) { + timed_out = ktime_compare(ktime_get(), timeout) > 0; + ctrl = cqhci_readl(cq_host, CQHCI_CTL); + if (!(ctrl & CQHCI_HALT) || timed_out) + break; + } + /* + * CQE usually resumes very quick, but incase if Tegra CQE + * doesn't resume retry unhalt. + */ + if (timed_out) + writel(val, cq_host->mmio + reg); + } else { + writel(val, cq_host->mmio + reg); + } +} + +static void sdhci_tegra_update_dcmd_desc(struct mmc_host *mmc, + struct mmc_request *mrq, u64 *data) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(mmc_priv(mmc)); + struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); + const struct sdhci_tegra_soc_data *soc_data = tegra_host->soc_data; + + if (soc_data->nvquirks & NVQUIRK_CQHCI_DCMD_R1B_CMD_TIMING && + mrq->cmd->flags & MMC_RSP_R1B) + *data |= CQHCI_CMD_TIMING(1); +} + +static void sdhci_tegra_cqe_enable(struct mmc_host *mmc) +{ + struct cqhci_host *cq_host = mmc->cqe_private; + u32 val; + + /* + * Tegra CQHCI/SDMMC design prevents write access to sdhci block size + * register when CQE is enabled and unhalted. + * CQHCI driver enables CQE prior to activation, so disable CQE before + * programming block size in sdhci controller and enable it back. + */ + if (!cq_host->activated) { + val = cqhci_readl(cq_host, CQHCI_CFG); + if (val & CQHCI_ENABLE) + cqhci_writel(cq_host, (val & ~CQHCI_ENABLE), + CQHCI_CFG); + sdhci_cqe_enable(mmc); + if (val & CQHCI_ENABLE) + cqhci_writel(cq_host, val, CQHCI_CFG); + } + + /* + * CMD CRC errors are seen sometimes with some eMMC devices when status + * command is sent during transfer of last data block which is the + * default case as send status command block counter (CBC) is 1. + * Recommended fix to set CBC to 0 allowing send status command only + * when data lines are idle. + */ + val = cqhci_readl(cq_host, CQHCI_SSC1); + val &= ~CQHCI_SSC1_CBC_MASK; + cqhci_writel(cq_host, val, CQHCI_SSC1); +} + +static void sdhci_tegra_dumpregs(struct mmc_host *mmc) +{ + sdhci_dumpregs(mmc_priv(mmc)); +} + +static u32 sdhci_tegra_cqhci_irq(struct sdhci_host *host, u32 intmask) +{ + int cmd_error = 0; + int data_error = 0; + + if (!sdhci_cqe_irq(host, intmask, &cmd_error, &data_error)) + return intmask; + + cqhci_irq(host->mmc, intmask, cmd_error, data_error); + + return 0; +} + +static const struct cqhci_host_ops sdhci_tegra_cqhci_ops = { + .write_l = tegra_cqhci_writel, + .enable = sdhci_tegra_cqe_enable, + .disable = sdhci_cqe_disable, + .dumpregs = sdhci_tegra_dumpregs, + .update_dcmd_desc = sdhci_tegra_update_dcmd_desc, +}; + static const struct sdhci_ops tegra_sdhci_ops = { - .get_ro = tegra_sdhci_get_ro, .read_w = tegra_sdhci_readw, .write_l = tegra_sdhci_writel, .set_clock = tegra_sdhci_set_clock, @@ -893,7 +1288,6 @@ static const struct sdhci_tegra_soc_data soc_data_tegra30 = { }; static const struct sdhci_ops tegra114_sdhci_ops = { - .get_ro = tegra_sdhci_get_ro, .read_w = tegra_sdhci_readw, .write_w = tegra_sdhci_writew, .write_l = tegra_sdhci_writel, @@ -947,7 +1341,6 @@ static const struct sdhci_tegra_soc_data soc_data_tegra124 = { }; static const struct sdhci_ops tegra210_sdhci_ops = { - .get_ro = tegra_sdhci_get_ro, .read_w = tegra_sdhci_readw, .write_w = tegra210_sdhci_writew, .write_l = tegra_sdhci_writel, @@ -977,10 +1370,11 @@ static const struct sdhci_tegra_soc_data soc_data_tegra210 = { NVQUIRK_DIS_CARD_CLK_CONFIG_TAP | NVQUIRK_ENABLE_SDR50 | NVQUIRK_ENABLE_SDR104, + .min_tap_delay = 106, + .max_tap_delay = 185, }; static const struct sdhci_ops tegra186_sdhci_ops = { - .get_ro = tegra_sdhci_get_ro, .read_w = tegra_sdhci_readw, .write_l = tegra_sdhci_writel, .set_clock = tegra_sdhci_set_clock, @@ -989,6 +1383,7 @@ static const struct sdhci_ops tegra186_sdhci_ops = { .set_uhs_signaling = tegra_sdhci_set_uhs_signaling, .voltage_switch = tegra_sdhci_voltage_switch, .get_max_clock = tegra_sdhci_get_max_clock, + .irq = sdhci_tegra_cqhci_irq, }; static const struct sdhci_pltfm_data sdhci_tegra186_pdata = { @@ -1016,10 +1411,25 @@ static const struct sdhci_tegra_soc_data soc_data_tegra186 = { NVQUIRK_HAS_PADCALIB | NVQUIRK_DIS_CARD_CLK_CONFIG_TAP | NVQUIRK_ENABLE_SDR50 | + NVQUIRK_ENABLE_SDR104 | + NVQUIRK_CQHCI_DCMD_R1B_CMD_TIMING, + .min_tap_delay = 84, + .max_tap_delay = 136, +}; + +static const struct sdhci_tegra_soc_data soc_data_tegra194 = { + .pdata = &sdhci_tegra186_pdata, + .nvquirks = NVQUIRK_NEEDS_PAD_CONTROL | + NVQUIRK_HAS_PADCALIB | + NVQUIRK_DIS_CARD_CLK_CONFIG_TAP | + NVQUIRK_ENABLE_SDR50 | NVQUIRK_ENABLE_SDR104, + .min_tap_delay = 96, + .max_tap_delay = 139, }; static const struct of_device_id sdhci_tegra_dt_match[] = { + { .compatible = "nvidia,tegra194-sdhci", .data = &soc_data_tegra194 }, { .compatible = "nvidia,tegra186-sdhci", .data = &soc_data_tegra186 }, { .compatible = "nvidia,tegra210-sdhci", .data = &soc_data_tegra210 }, { .compatible = "nvidia,tegra124-sdhci", .data = &soc_data_tegra124 }, @@ -1030,6 +1440,54 @@ static const struct of_device_id sdhci_tegra_dt_match[] = { }; MODULE_DEVICE_TABLE(of, sdhci_tegra_dt_match); +static int sdhci_tegra_add_host(struct sdhci_host *host) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); + struct cqhci_host *cq_host; + bool dma64; + int ret; + + if (!tegra_host->enable_hwcq) + return sdhci_add_host(host); + + sdhci_enable_v4_mode(host); + + ret = sdhci_setup_host(host); + if (ret) + return ret; + + host->mmc->caps2 |= MMC_CAP2_CQE | MMC_CAP2_CQE_DCMD; + + cq_host = devm_kzalloc(host->mmc->parent, + sizeof(*cq_host), GFP_KERNEL); + if (!cq_host) { + ret = -ENOMEM; + goto cleanup; + } + + cq_host->mmio = host->ioaddr + SDHCI_TEGRA_CQE_BASE_ADDR; + cq_host->ops = &sdhci_tegra_cqhci_ops; + + dma64 = host->flags & SDHCI_USE_64_BIT_DMA; + if (dma64) + cq_host->caps |= CQHCI_TASK_DESC_SZ_128; + + ret = cqhci_init(cq_host, host->mmc, dma64); + if (ret) + goto cleanup; + + ret = __sdhci_add_host(host); + if (ret) + goto cleanup; + + return 0; + +cleanup: + sdhci_cleanup_host(host); + return ret; +} + static int sdhci_tegra_probe(struct platform_device *pdev) { const struct of_device_id *match; @@ -1070,6 +1528,10 @@ static int sdhci_tegra_probe(struct platform_device *pdev) host->mmc_host_ops.hs400_enhanced_strobe = tegra_sdhci_hs400_enhanced_strobe; + if (!host->ops->platform_execute_tuning) + host->mmc_host_ops.execute_tuning = + tegra_sdhci_execute_hw_tuning; + rc = mmc_of_parse(host->mmc); if (rc) goto err_parse_dt; @@ -1077,9 +1539,7 @@ static int sdhci_tegra_probe(struct platform_device *pdev) if (tegra_host->soc_data->nvquirks & NVQUIRK_ENABLE_DDR50) host->mmc->caps |= MMC_CAP_1_8V_DDR; - tegra_sdhci_parse_pad_autocal_dt(host); - - tegra_sdhci_parse_tap_and_trim(host); + tegra_sdhci_parse_dt(host); tegra_host->power_gpio = devm_gpiod_get_optional(&pdev->dev, "power", GPIOD_OUT_HIGH); @@ -1117,7 +1577,7 @@ static int sdhci_tegra_probe(struct platform_device *pdev) usleep_range(2000, 4000); - rc = sdhci_add_host(host); + rc = sdhci_tegra_add_host(host); if (rc) goto err_add_host; @@ -1151,11 +1611,67 @@ static int sdhci_tegra_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM_SLEEP +static int __maybe_unused sdhci_tegra_suspend(struct device *dev) +{ + struct sdhci_host *host = dev_get_drvdata(dev); + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + int ret; + + if (host->mmc->caps2 & MMC_CAP2_CQE) { + ret = cqhci_suspend(host->mmc); + if (ret) + return ret; + } + + ret = sdhci_suspend_host(host); + if (ret) { + cqhci_resume(host->mmc); + return ret; + } + + clk_disable_unprepare(pltfm_host->clk); + return 0; +} + +static int __maybe_unused sdhci_tegra_resume(struct device *dev) +{ + struct sdhci_host *host = dev_get_drvdata(dev); + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + int ret; + + ret = clk_prepare_enable(pltfm_host->clk); + if (ret) + return ret; + + ret = sdhci_resume_host(host); + if (ret) + goto disable_clk; + + if (host->mmc->caps2 & MMC_CAP2_CQE) { + ret = cqhci_resume(host->mmc); + if (ret) + goto suspend_host; + } + + return 0; + +suspend_host: + sdhci_suspend_host(host); +disable_clk: + clk_disable_unprepare(pltfm_host->clk); + return ret; +} +#endif + +static SIMPLE_DEV_PM_OPS(sdhci_tegra_dev_pm_ops, sdhci_tegra_suspend, + sdhci_tegra_resume); + static struct platform_driver sdhci_tegra_driver = { .driver = { .name = "sdhci-tegra", .of_match_table = sdhci_tegra_dt_match, - .pm = &sdhci_pltfm_pmops, + .pm = &sdhci_tegra_dev_pm_ops, }, .probe = sdhci_tegra_probe, .remove = sdhci_tegra_remove, diff --git a/drivers/mmc/host/sdhci-xenon-phy.c b/drivers/mmc/host/sdhci-xenon-phy.c index 5b5eb53a63d2..8d07ee1b8f08 100644 --- a/drivers/mmc/host/sdhci-xenon-phy.c +++ b/drivers/mmc/host/sdhci-xenon-phy.c @@ -530,7 +530,7 @@ static bool xenon_emmc_phy_slow_mode(struct sdhci_host *host, ret = true; break; } - /* else: fall through */ + /* fall through */ default: reg &= ~XENON_TIMING_ADJUST_SLOW_MODE; ret = false; diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index eba9bcc92ad3..97158344b862 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -446,6 +446,28 @@ static inline void sdhci_led_deactivate(struct sdhci_host *host) #endif +static void sdhci_mod_timer(struct sdhci_host *host, struct mmc_request *mrq, + unsigned long timeout) +{ + if (sdhci_data_line_cmd(mrq->cmd)) + mod_timer(&host->data_timer, timeout); + else + mod_timer(&host->timer, timeout); +} + +static void sdhci_del_timer(struct sdhci_host *host, struct mmc_request *mrq) +{ + if (sdhci_data_line_cmd(mrq->cmd)) + del_timer(&host->data_timer); + else + del_timer(&host->timer); +} + +static inline bool sdhci_has_requests(struct sdhci_host *host) +{ + return host->cmd || host->data_cmd; +} + /*****************************************************************************\ * * * Core functions * @@ -883,7 +905,7 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd, bool *too_big) { u8 count; - struct mmc_data *data = cmd->data; + struct mmc_data *data; unsigned target_timeout, current_timeout; *too_big = true; @@ -897,6 +919,11 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd, if (host->quirks & SDHCI_QUIRK_BROKEN_TIMEOUT_VAL) return 0xE; + /* Unspecified command, asume max */ + if (cmd == NULL) + return 0xE; + + data = cmd->data; /* Unspecified timeout, assume max */ if (!data && !cmd->busy_timeout) return 0xE; @@ -1216,6 +1243,18 @@ static void __sdhci_finish_mrq(struct sdhci_host *host, struct mmc_request *mrq) { int i; + if (host->cmd && host->cmd->mrq == mrq) + host->cmd = NULL; + + if (host->data_cmd && host->data_cmd->mrq == mrq) + host->data_cmd = NULL; + + if (host->data && host->data->mrq == mrq) + host->data = NULL; + + if (sdhci_needs_reset(host, mrq)) + host->pending_reset = true; + for (i = 0; i < SDHCI_MAX_MRQS; i++) { if (host->mrqs_done[i] == mrq) { WARN_ON(1); @@ -1232,24 +1271,17 @@ static void __sdhci_finish_mrq(struct sdhci_host *host, struct mmc_request *mrq) WARN_ON(i >= SDHCI_MAX_MRQS); - tasklet_schedule(&host->finish_tasklet); + sdhci_del_timer(host, mrq); + + if (!sdhci_has_requests(host)) + sdhci_led_deactivate(host); } static void sdhci_finish_mrq(struct sdhci_host *host, struct mmc_request *mrq) { - if (host->cmd && host->cmd->mrq == mrq) - host->cmd = NULL; - - if (host->data_cmd && host->data_cmd->mrq == mrq) - host->data_cmd = NULL; - - if (host->data && host->data->mrq == mrq) - host->data = NULL; - - if (sdhci_needs_reset(host, mrq)) - host->pending_reset = true; - __sdhci_finish_mrq(host, mrq); + + queue_work(host->complete_wq, &host->complete_work); } static void sdhci_finish_data(struct sdhci_host *host) @@ -1300,34 +1332,17 @@ static void sdhci_finish_data(struct sdhci_host *host) * responsibility to send the stop command if required. */ if (data->mrq->cap_cmd_during_tfr) { - sdhci_finish_mrq(host, data->mrq); + __sdhci_finish_mrq(host, data->mrq); } else { /* Avoid triggering warning in sdhci_send_command() */ host->cmd = NULL; sdhci_send_command(host, data->stop); } } else { - sdhci_finish_mrq(host, data->mrq); + __sdhci_finish_mrq(host, data->mrq); } } -static void sdhci_mod_timer(struct sdhci_host *host, struct mmc_request *mrq, - unsigned long timeout) -{ - if (sdhci_data_line_cmd(mrq->cmd)) - mod_timer(&host->data_timer, timeout); - else - mod_timer(&host->timer, timeout); -} - -static void sdhci_del_timer(struct sdhci_host *host, struct mmc_request *mrq) -{ - if (sdhci_data_line_cmd(mrq->cmd)) - del_timer(&host->data_timer); - else - del_timer(&host->timer); -} - void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd) { int flags; @@ -1487,7 +1502,7 @@ static void sdhci_finish_command(struct sdhci_host *host) sdhci_finish_data(host); if (!cmd->data) - sdhci_finish_mrq(host, cmd->mrq); + __sdhci_finish_mrq(host, cmd->mrq); } } @@ -1802,7 +1817,6 @@ void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq) sdhci_send_command(host, mrq->cmd); } - mmiowb(); spin_unlock_irqrestore(&host->lock, flags); } EXPORT_SYMBOL_GPL(sdhci_request); @@ -2005,8 +2019,6 @@ void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) */ if (host->quirks & SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS) sdhci_do_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA); - - mmiowb(); } EXPORT_SYMBOL_GPL(sdhci_set_ios); @@ -2048,6 +2060,8 @@ static int sdhci_check_ro(struct sdhci_host *host) is_readonly = 0; else if (host->ops->get_ro) is_readonly = host->ops->get_ro(host); + else if (mmc_can_gpio_ro(host->mmc)) + is_readonly = mmc_gpio_get_ro(host->mmc); else is_readonly = !(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_WRITE_PROTECT); @@ -2098,7 +2112,6 @@ static void sdhci_enable_sdio_irq_nolock(struct sdhci_host *host, int enable) sdhci_writel(host, host->ier, SDHCI_INT_ENABLE); sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); - mmiowb(); } } @@ -2346,7 +2359,6 @@ void sdhci_send_tuning(struct sdhci_host *host, u32 opcode) host->tuning_done = 0; - mmiowb(); spin_unlock_irqrestore(&host->lock, flags); /* Wait for Buffer Read Ready interrupt */ @@ -2362,9 +2374,9 @@ static int __sdhci_execute_tuning(struct sdhci_host *host, u32 opcode) /* * Issue opcode repeatedly till Execute Tuning is set to 0 or the number - * of loops reaches 40 times. + * of loops reaches tuning loop count. */ - for (i = 0; i < MAX_TUNING_LOOP; i++) { + for (i = 0; i < host->tuning_loop_count; i++) { u16 ctrl; sdhci_send_tuning(host, opcode); @@ -2376,6 +2388,10 @@ static int __sdhci_execute_tuning(struct sdhci_host *host, u32 opcode) return -ETIMEDOUT; } + /* Spec does not require a delay between tuning cycles */ + if (host->tuning_delay > 0) + mdelay(host->tuning_delay); + ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); if (!(ctrl & SDHCI_CTRL_EXEC_TUNING)) { if (ctrl & SDHCI_CTRL_TUNED_CLK) @@ -2383,9 +2399,6 @@ static int __sdhci_execute_tuning(struct sdhci_host *host, u32 opcode) break; } - /* Spec does not require a delay between tuning cycles */ - if (host->tuning_delay > 0) - mdelay(host->tuning_delay); } pr_info("%s: Tuning failed, falling back to fixed sampling clock\n", @@ -2520,11 +2533,6 @@ static void sdhci_pre_req(struct mmc_host *mmc, struct mmc_request *mrq) sdhci_pre_dma_transfer(host, mrq->data, COOKIE_PRE_MAPPED); } -static inline bool sdhci_has_requests(struct sdhci_host *host) -{ - return host->cmd || host->data_cmd; -} - static void sdhci_error_out_mrqs(struct sdhci_host *host, int err) { if (host->data_cmd) { @@ -2586,7 +2594,7 @@ static const struct mmc_host_ops sdhci_ops = { /*****************************************************************************\ * * - * Tasklets * + * Request done * * * \*****************************************************************************/ @@ -2609,8 +2617,6 @@ static bool sdhci_request_done(struct sdhci_host *host) return true; } - sdhci_del_timer(host, mrq); - /* * Always unmap the data buffers if they were mapped by * sdhci_prepare_data() whenever we finish with a request. @@ -2692,12 +2698,8 @@ static bool sdhci_request_done(struct sdhci_host *host) host->pending_reset = false; } - if (!sdhci_has_requests(host)) - sdhci_led_deactivate(host); - host->mrqs_done[i] = NULL; - mmiowb(); spin_unlock_irqrestore(&host->lock, flags); mmc_request_done(host->mmc, mrq); @@ -2705,9 +2707,10 @@ static bool sdhci_request_done(struct sdhci_host *host) return false; } -static void sdhci_tasklet_finish(unsigned long param) +static void sdhci_complete_work(struct work_struct *work) { - struct sdhci_host *host = (struct sdhci_host *)param; + struct sdhci_host *host = container_of(work, struct sdhci_host, + complete_work); while (!sdhci_request_done(host)) ; @@ -2731,7 +2734,6 @@ static void sdhci_timeout_timer(struct timer_list *t) sdhci_finish_mrq(host, host->cmd->mrq); } - mmiowb(); spin_unlock_irqrestore(&host->lock, flags); } @@ -2753,6 +2755,7 @@ static void sdhci_timeout_data_timer(struct timer_list *t) if (host->data) { host->data->error = -ETIMEDOUT; sdhci_finish_data(host); + queue_work(host->complete_wq, &host->complete_work); } else if (host->data_cmd) { host->data_cmd->error = -ETIMEDOUT; sdhci_finish_mrq(host, host->data_cmd->mrq); @@ -2762,7 +2765,6 @@ static void sdhci_timeout_data_timer(struct timer_list *t) } } - mmiowb(); spin_unlock_irqrestore(&host->lock, flags); } @@ -2819,7 +2821,7 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask, u32 *intmask_p) return; } - sdhci_finish_mrq(host, host->cmd->mrq); + __sdhci_finish_mrq(host, host->cmd->mrq); return; } @@ -2833,7 +2835,7 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask, u32 *intmask_p) if (mrq->sbc && (host->flags & SDHCI_AUTO_CMD23)) { mrq->sbc->error = err; - sdhci_finish_mrq(host, mrq); + __sdhci_finish_mrq(host, mrq); return; } } @@ -2897,7 +2899,7 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) if (intmask & SDHCI_INT_DATA_TIMEOUT) { host->data_cmd = NULL; data_cmd->error = -ETIMEDOUT; - sdhci_finish_mrq(host, data_cmd->mrq); + __sdhci_finish_mrq(host, data_cmd->mrq); return; } if (intmask & SDHCI_INT_DATA_END) { @@ -2910,7 +2912,7 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) if (host->cmd == data_cmd) return; - sdhci_finish_mrq(host, data_cmd->mrq); + __sdhci_finish_mrq(host, data_cmd->mrq); return; } } @@ -2993,12 +2995,24 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) } } +static inline bool sdhci_defer_done(struct sdhci_host *host, + struct mmc_request *mrq) +{ + struct mmc_data *data = mrq->data; + + return host->pending_reset || + ((host->flags & SDHCI_REQ_USE_DMA) && data && + data->host_cookie == COOKIE_MAPPED); +} + static irqreturn_t sdhci_irq(int irq, void *dev_id) { + struct mmc_request *mrqs_done[SDHCI_MAX_MRQS] = {0}; irqreturn_t result = IRQ_NONE; struct sdhci_host *host = dev_id; u32 intmask, mask, unexpected = 0; int max_loops = 16; + int i; spin_lock(&host->lock); @@ -3092,9 +3106,30 @@ cont: intmask = sdhci_readl(host, SDHCI_INT_STATUS); } while (intmask && --max_loops); + + /* Determine if mrqs can be completed immediately */ + for (i = 0; i < SDHCI_MAX_MRQS; i++) { + struct mmc_request *mrq = host->mrqs_done[i]; + + if (!mrq) + continue; + + if (sdhci_defer_done(host, mrq)) { + result = IRQ_WAKE_THREAD; + } else { + mrqs_done[i] = mrq; + host->mrqs_done[i] = NULL; + } + } out: spin_unlock(&host->lock); + /* Process mrqs ready for immediate completion */ + for (i = 0; i < SDHCI_MAX_MRQS; i++) { + if (mrqs_done[i]) + mmc_request_done(host->mmc, mrqs_done[i]); + } + if (unexpected) { pr_err("%s: Unexpected interrupt 0x%08x.\n", mmc_hostname(host->mmc), unexpected); @@ -3110,6 +3145,9 @@ static irqreturn_t sdhci_thread_irq(int irq, void *dev_id) unsigned long flags; u32 isr; + while (!sdhci_request_done(host)) + ; + spin_lock_irqsave(&host->lock, flags); isr = host->thread_isr; host->thread_isr = 0; @@ -3131,7 +3169,7 @@ static irqreturn_t sdhci_thread_irq(int irq, void *dev_id) spin_unlock_irqrestore(&host->lock, flags); } - return isr ? IRQ_HANDLED : IRQ_NONE; + return IRQ_HANDLED; } /*****************************************************************************\ @@ -3243,7 +3281,6 @@ int sdhci_resume_host(struct sdhci_host *host) mmc->ops->set_ios(mmc, &mmc->ios); } else { sdhci_init(host, (host->mmc->pm_flags & MMC_PM_KEEP_POWER)); - mmiowb(); } if (host->irq_wake_enabled) { @@ -3353,7 +3390,14 @@ void sdhci_cqe_enable(struct mmc_host *mmc) ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); ctrl &= ~SDHCI_CTRL_DMA_MASK; - if (host->flags & SDHCI_USE_64_BIT_DMA) + /* + * Host from V4.10 supports ADMA3 DMA type. + * ADMA3 performs integrated descriptor which is more suitable + * for cmd queuing to fetch both command and transfer descriptors. + */ + if (host->v4_mode && (host->caps1 & SDHCI_CAN_DO_ADMA3)) + ctrl |= SDHCI_CTRL_ADMA3; + else if (host->flags & SDHCI_USE_64_BIT_DMA) ctrl |= SDHCI_CTRL_ADMA64; else ctrl |= SDHCI_CTRL_ADMA32; @@ -3363,7 +3407,7 @@ void sdhci_cqe_enable(struct mmc_host *mmc) SDHCI_BLOCK_SIZE); /* Set maximum timeout */ - sdhci_writeb(host, 0xE, SDHCI_TIMEOUT_CONTROL); + sdhci_set_timeout(host, NULL); host->ier = host->cqe_ier; @@ -3376,7 +3420,6 @@ void sdhci_cqe_enable(struct mmc_host *mmc) mmc_hostname(mmc), host->ier, sdhci_readl(host, SDHCI_INT_STATUS)); - mmiowb(); spin_unlock_irqrestore(&host->lock, flags); } EXPORT_SYMBOL_GPL(sdhci_cqe_enable); @@ -3401,7 +3444,6 @@ void sdhci_cqe_disable(struct mmc_host *mmc, bool recovery) mmc_hostname(mmc), host->ier, sdhci_readl(host, SDHCI_INT_STATUS)); - mmiowb(); spin_unlock_irqrestore(&host->lock, flags); } EXPORT_SYMBOL_GPL(sdhci_cqe_disable); @@ -3479,6 +3521,7 @@ struct sdhci_host *sdhci_alloc_host(struct device *dev, host->cqe_err_ier = SDHCI_CQE_INT_ERR_MASK; host->tuning_delay = -1; + host->tuning_loop_count = MAX_TUNING_LOOP; host->sdma_boundary = SDHCI_DEFAULT_BOUNDARY_ARG; @@ -4209,14 +4252,15 @@ EXPORT_SYMBOL_GPL(sdhci_cleanup_host); int __sdhci_add_host(struct sdhci_host *host) { + unsigned int flags = WQ_UNBOUND | WQ_MEM_RECLAIM | WQ_HIGHPRI; struct mmc_host *mmc = host->mmc; int ret; - /* - * Init tasklets. - */ - tasklet_init(&host->finish_tasklet, - sdhci_tasklet_finish, (unsigned long)host); + host->complete_wq = alloc_workqueue("sdhci", flags, 0); + if (!host->complete_wq) + return -ENOMEM; + + INIT_WORK(&host->complete_work, sdhci_complete_work); timer_setup(&host->timer, sdhci_timeout_timer, 0); timer_setup(&host->data_timer, sdhci_timeout_data_timer, 0); @@ -4230,7 +4274,7 @@ int __sdhci_add_host(struct sdhci_host *host) if (ret) { pr_err("%s: Failed to request IRQ %d: %d\n", mmc_hostname(mmc), host->irq, ret); - goto untasklet; + goto unwq; } ret = sdhci_led_register(host); @@ -4240,8 +4284,6 @@ int __sdhci_add_host(struct sdhci_host *host) goto unirq; } - mmiowb(); - ret = mmc_add_host(mmc); if (ret) goto unled; @@ -4263,8 +4305,8 @@ unirq: sdhci_writel(host, 0, SDHCI_INT_ENABLE); sdhci_writel(host, 0, SDHCI_SIGNAL_ENABLE); free_irq(host->irq, host); -untasklet: - tasklet_kill(&host->finish_tasklet); +unwq: + destroy_workqueue(host->complete_wq); return ret; } @@ -4326,7 +4368,7 @@ void sdhci_remove_host(struct sdhci_host *host, int dead) del_timer_sync(&host->timer); del_timer_sync(&host->data_timer); - tasklet_kill(&host->finish_tasklet); + destroy_workqueue(host->complete_wq); if (!IS_ERR(mmc->supply.vqmmc)) regulator_disable(mmc->supply.vqmmc); diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index 6cc9a3c2ac66..d6bcc584c92b 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -73,6 +73,10 @@ #define SDHCI_SPACE_AVAILABLE 0x00000400 #define SDHCI_DATA_AVAILABLE 0x00000800 #define SDHCI_CARD_PRESENT 0x00010000 +#define SDHCI_CARD_PRES_SHIFT 16 +#define SDHCI_CD_STABLE 0x00020000 +#define SDHCI_CD_LVL 0x00040000 +#define SDHCI_CD_LVL_SHIFT 18 #define SDHCI_WRITE_PROTECT 0x00080000 #define SDHCI_DATA_LVL_MASK 0x00F00000 #define SDHCI_DATA_LVL_SHIFT 20 @@ -88,6 +92,7 @@ #define SDHCI_CTRL_ADMA1 0x08 #define SDHCI_CTRL_ADMA32 0x10 #define SDHCI_CTRL_ADMA64 0x18 +#define SDHCI_CTRL_ADMA3 0x18 #define SDHCI_CTRL_8BITBUS 0x20 #define SDHCI_CTRL_CDTEST_INS 0x40 #define SDHCI_CTRL_CDTEST_EN 0x80 @@ -230,6 +235,7 @@ #define SDHCI_RETUNING_MODE_SHIFT 14 #define SDHCI_CLOCK_MUL_MASK 0x00FF0000 #define SDHCI_CLOCK_MUL_SHIFT 16 +#define SDHCI_CAN_DO_ADMA3 0x08000000 #define SDHCI_SUPPORT_HS400 0x80000000 /* Non-standard */ #define SDHCI_CAPABILITIES_1 0x44 @@ -554,7 +560,8 @@ struct sdhci_host { unsigned int desc_sz; /* ADMA descriptor size */ - struct tasklet_struct finish_tasklet; /* Tasklet structures */ + struct workqueue_struct *complete_wq; /* Request completion wq */ + struct work_struct complete_work; /* Request completion work */ struct timer_list timer; /* Timer for timeouts */ struct timer_list data_timer; /* Timer for data timeouts */ @@ -590,6 +597,7 @@ struct sdhci_host { #define SDHCI_TUNING_MODE_3 2 /* Delay (ms) between tuning commands */ int tuning_delay; + int tuning_loop_count; /* Host SDMA buffer boundary. */ u32 sdma_boundary; diff --git a/drivers/mmc/host/sdhci_am654.c b/drivers/mmc/host/sdhci_am654.c index 8c05879850a0..a91c0b45c48d 100644 --- a/drivers/mmc/host/sdhci_am654.c +++ b/drivers/mmc/host/sdhci_am654.c @@ -158,13 +158,35 @@ static void sdhci_am654_set_power(struct sdhci_host *host, unsigned char mode, sdhci_set_power_noreg(host, mode, vdd); } -struct sdhci_ops sdhci_am654_ops = { +static void sdhci_am654_write_b(struct sdhci_host *host, u8 val, int reg) +{ + unsigned char timing = host->mmc->ios.timing; + + if (reg == SDHCI_HOST_CONTROL) { + switch (timing) { + /* + * According to the data manual, HISPD bit + * should not be set in these speed modes. + */ + case MMC_TIMING_SD_HS: + case MMC_TIMING_MMC_HS: + case MMC_TIMING_UHS_SDR12: + case MMC_TIMING_UHS_SDR25: + val &= ~SDHCI_CTRL_HISPD; + } + } + + writeb(val, host->ioaddr + reg); +} + +static struct sdhci_ops sdhci_am654_ops = { .get_max_clock = sdhci_pltfm_clk_get_max_clock, .get_timeout_clock = sdhci_pltfm_clk_get_max_clock, .set_uhs_signaling = sdhci_set_uhs_signaling, .set_bus_width = sdhci_set_bus_width, .set_power = sdhci_am654_set_power, .set_clock = sdhci_am654_set_clock, + .write_b = sdhci_am654_write_b, .reset = sdhci_reset, }; diff --git a/drivers/mmc/host/sunxi-mmc.c b/drivers/mmc/host/sunxi-mmc.c index 279e326e397e..2901a5773d83 100644 --- a/drivers/mmc/host/sunxi-mmc.c +++ b/drivers/mmc/host/sunxi-mmc.c @@ -19,7 +19,6 @@ #include <linux/device.h> #include <linux/dma-mapping.h> #include <linux/err.h> -#include <linux/gpio.h> #include <linux/interrupt.h> #include <linux/io.h> #include <linux/kernel.h> @@ -32,7 +31,6 @@ #include <linux/mmc/slot-gpio.h> #include <linux/module.h> #include <linux/of_address.h> -#include <linux/of_gpio.h> #include <linux/of_platform.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> @@ -1399,13 +1397,37 @@ static int sunxi_mmc_probe(struct platform_device *pdev) mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED | MMC_CAP_ERASE | MMC_CAP_SDIO_IRQ; - if (host->cfg->clk_delays || host->use_new_timings) + /* + * Some H5 devices do not have signal traces precise enough to + * use HS DDR mode for their eMMC chips. + * + * We still enable HS DDR modes for all the other controller + * variants that support them. + */ + if ((host->cfg->clk_delays || host->use_new_timings) && + !of_device_is_compatible(pdev->dev.of_node, + "allwinner,sun50i-h5-emmc")) mmc->caps |= MMC_CAP_1_8V_DDR | MMC_CAP_3_3V_DDR; ret = mmc_of_parse(mmc); if (ret) goto error_free_dma; + /* + * If we don't support delay chains in the SoC, we can't use any + * of the higher speed modes. Mask them out in case the device + * tree specifies the properties for them, which gets added to + * the caps by mmc_of_parse() above. + */ + if (!(host->cfg->clk_delays || host->use_new_timings)) { + mmc->caps &= ~(MMC_CAP_3_3V_DDR | MMC_CAP_1_8V_DDR | + MMC_CAP_1_2V_DDR | MMC_CAP_UHS); + mmc->caps2 &= ~MMC_CAP2_HS200; + } + + /* TODO: This driver doesn't support HS400 mode yet */ + mmc->caps2 &= ~MMC_CAP2_HS400; + ret = sunxi_mmc_init_host(host); if (ret) goto error_free_dma; diff --git a/drivers/mmc/host/tifm_sd.c b/drivers/mmc/host/tifm_sd.c index b6644ce296b2..35dd34b82a4d 100644 --- a/drivers/mmc/host/tifm_sd.c +++ b/drivers/mmc/host/tifm_sd.c @@ -889,7 +889,6 @@ static int tifm_sd_initialize_host(struct tifm_sd *host) struct tifm_dev *sock = host->dev; writel(0, sock->addr + SOCK_MMCSD_INT_ENABLE); - mmiowb(); host->clk_div = 61; host->clk_freq = 20000000; writel(TIFM_MMCSD_RESET, sock->addr + SOCK_MMCSD_SYSTEM_CONTROL); @@ -940,7 +939,6 @@ static int tifm_sd_initialize_host(struct tifm_sd *host) writel(TIFM_MMCSD_CERR | TIFM_MMCSD_BRS | TIFM_MMCSD_EOC | TIFM_MMCSD_ERRMASK, sock->addr + SOCK_MMCSD_INT_ENABLE); - mmiowb(); return 0; } @@ -1005,7 +1003,6 @@ static void tifm_sd_remove(struct tifm_dev *sock) spin_lock_irqsave(&sock->lock, flags); host->eject = 1; writel(0, sock->addr + SOCK_MMCSD_INT_ENABLE); - mmiowb(); spin_unlock_irqrestore(&sock->lock, flags); tasklet_kill(&host->finish_tasklet); diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h index c03529e3f01a..c5ba13fae399 100644 --- a/drivers/mmc/host/tmio_mmc.h +++ b/drivers/mmc/host/tmio_mmc.h @@ -4,8 +4,8 @@ * * TC6393XB TC6391XB TC6387XB T7L66XB ASIC3 * - * Copyright (C) 2015-17 Renesas Electronics Corporation - * Copyright (C) 2016-17 Sang Engineering, Wolfram Sang + * Copyright (C) 2015-19 Renesas Electronics Corporation + * Copyright (C) 2016-19 Sang Engineering, Wolfram Sang * Copyright (C) 2016-17 Horms Solutions, Simon Horman * Copyright (C) 2007 Ian Molton * Copyright (C) 2004 Ian Molton @@ -105,6 +105,8 @@ TMIO_STAT_CARD_REMOVE | TMIO_STAT_CARD_INSERT) #define TMIO_MASK_IRQ (TMIO_MASK_READOP | TMIO_MASK_WRITEOP | TMIO_MASK_CMD) +#define TMIO_MAX_BLK_SIZE 512 + struct tmio_mmc_data; struct tmio_mmc_host; @@ -277,6 +279,11 @@ static inline void sd_ctrl_write32_as_16_and_16(struct tmio_mmc_host *host, iowrite16(val >> 16, host->ctl + ((addr + 2) << host->bus_shift)); } +static inline void sd_ctrl_write32(struct tmio_mmc_host *host, int addr, u32 val) +{ + iowrite32(val, host->ctl + (addr << host->bus_shift)); +} + static inline void sd_ctrl_write32_rep(struct tmio_mmc_host *host, int addr, const u32 *buf, int count) { diff --git a/drivers/mmc/host/tmio_mmc_core.c b/drivers/mmc/host/tmio_mmc_core.c index 085a0fab769c..130b91cb0f8a 100644 --- a/drivers/mmc/host/tmio_mmc_core.c +++ b/drivers/mmc/host/tmio_mmc_core.c @@ -4,8 +4,8 @@ * * TC6393XB, TC6391XB, TC6387XB, T7L66XB, ASIC3, SH-Mobile SoCs * - * Copyright (C) 2015-17 Renesas Electronics Corporation - * Copyright (C) 2016-17 Sang Engineering, Wolfram Sang + * Copyright (C) 2015-19 Renesas Electronics Corporation + * Copyright (C) 2016-19 Sang Engineering, Wolfram Sang * Copyright (C) 2017 Horms Solutions, Simon Horman * Copyright (C) 2011 Guennadi Liakhovetski * Copyright (C) 2007 Ian Molton @@ -43,6 +43,7 @@ #include <linux/regulator/consumer.h> #include <linux/mmc/sdio.h> #include <linux/scatterlist.h> +#include <linux/sizes.h> #include <linux/spinlock.h> #include <linux/swiotlb.h> #include <linux/workqueue.h> @@ -629,7 +630,7 @@ static bool __tmio_mmc_sdcard_irq(struct tmio_mmc_host *host, int ireg, return false; } -static void __tmio_mmc_sdio_irq(struct tmio_mmc_host *host) +static bool __tmio_mmc_sdio_irq(struct tmio_mmc_host *host) { struct mmc_host *mmc = host->mmc; struct tmio_mmc_data *pdata = host->pdata; @@ -637,7 +638,7 @@ static void __tmio_mmc_sdio_irq(struct tmio_mmc_host *host) unsigned int sdio_status; if (!(pdata->flags & TMIO_MMC_SDIO_IRQ)) - return; + return false; status = sd_ctrl_read16(host, CTL_SDIO_STATUS); ireg = status & TMIO_SDIO_MASK_ALL & ~host->sdio_irq_mask; @@ -650,6 +651,8 @@ static void __tmio_mmc_sdio_irq(struct tmio_mmc_host *host) if (mmc->caps & MMC_CAP_SDIO_IRQ && ireg & TMIO_SDIO_STAT_IOIRQ) mmc_signal_sdio_irq(mmc); + + return ireg; } irqreturn_t tmio_mmc_irq(int irq, void *devid) @@ -668,9 +671,10 @@ irqreturn_t tmio_mmc_irq(int irq, void *devid) if (__tmio_mmc_sdcard_irq(host, ireg, status)) return IRQ_HANDLED; - __tmio_mmc_sdio_irq(host); + if (__tmio_mmc_sdio_irq(host)) + return IRQ_HANDLED; - return IRQ_HANDLED; + return IRQ_NONE; } EXPORT_SYMBOL_GPL(tmio_mmc_irq); @@ -700,7 +704,10 @@ static int tmio_mmc_start_data(struct tmio_mmc_host *host, /* Set transfer length / blocksize */ sd_ctrl_write16(host, CTL_SD_XFER_LEN, data->blksz); - sd_ctrl_write16(host, CTL_XFER_BLK_COUNT, data->blocks); + if (host->mmc->max_blk_count >= SZ_64K) + sd_ctrl_write32(host, CTL_XFER_BLK_COUNT, data->blocks); + else + sd_ctrl_write16(host, CTL_XFER_BLK_COUNT, data->blocks); tmio_mmc_start_dma(host, data); @@ -1066,7 +1073,7 @@ static int tmio_mmc_init_ocr(struct tmio_mmc_host *host) /* use ocr_mask if no regulator */ if (!mmc->ocr_avail) - mmc->ocr_avail = pdata->ocr_mask; + mmc->ocr_avail = pdata->ocr_mask; /* * try again. @@ -1179,7 +1186,7 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host) mmc->caps |= MMC_CAP_4_BIT_DATA | pdata->capabilities; mmc->caps2 |= pdata->capabilities2; mmc->max_segs = pdata->max_segs ? : 32; - mmc->max_blk_size = 512; + mmc->max_blk_size = TMIO_MAX_BLK_SIZE; mmc->max_blk_count = pdata->max_blk_count ? : (PAGE_SIZE / mmc->max_blk_size) * mmc->max_segs; mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count; @@ -1287,6 +1294,7 @@ void tmio_mmc_host_remove(struct tmio_mmc_host *host) cancel_delayed_work_sync(&host->delayed_reset_work); tmio_mmc_release_dma(host); + pm_runtime_dont_use_autosuspend(&pdev->dev); pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); } diff --git a/drivers/mmc/host/usdhi6rol0.c b/drivers/mmc/host/usdhi6rol0.c index cd8b1b9d4d8a..b11ac2314328 100644 --- a/drivers/mmc/host/usdhi6rol0.c +++ b/drivers/mmc/host/usdhi6rol0.c @@ -1339,7 +1339,7 @@ static int usdhi6_stop_cmd(struct usdhi6_host *host) host->wait = USDHI6_WAIT_FOR_STOP; return 0; } - /* Unsupported STOP command */ + /* fall through - Unsupported STOP command. */ default: dev_err(mmc_dev(host->mmc), "unsupported stop CMD%d for CMD%d\n", @@ -1687,7 +1687,7 @@ static void usdhi6_timeout_work(struct work_struct *work) switch (host->wait) { default: dev_err(mmc_dev(host->mmc), "Invalid state %u\n", host->wait); - /* mrq can be NULL in this actually impossible case */ + /* fall through - mrq can be NULL, but is impossible. */ case USDHI6_WAIT_FOR_CMD: usdhi6_error_code(host); if (mrq) @@ -1709,10 +1709,7 @@ static void usdhi6_timeout_work(struct work_struct *work) host->offset, data->blocks, data->blksz, data->sg_len, sg_dma_len(sg), sg->offset); usdhi6_sg_unmap(host, true); - /* - * If USDHI6_WAIT_FOR_DATA_END times out, we have already unmapped - * the page - */ + /* fall through - page unmapped in USDHI6_WAIT_FOR_DATA_END. */ case USDHI6_WAIT_FOR_DATA_END: usdhi6_error_code(host); data->error = -ETIMEDOUT; diff --git a/drivers/mmc/host/via-sdmmc.c b/drivers/mmc/host/via-sdmmc.c index 32c4211506fc..412395ac2935 100644 --- a/drivers/mmc/host/via-sdmmc.c +++ b/drivers/mmc/host/via-sdmmc.c @@ -686,7 +686,6 @@ static void via_sdc_request(struct mmc_host *mmc, struct mmc_request *mrq) via_sdc_send_command(host, mrq->cmd); } - mmiowb(); spin_unlock_irqrestore(&host->lock, flags); } @@ -711,7 +710,6 @@ static void via_sdc_set_power(struct via_crdr_mmc_host *host, gatt &= ~VIA_CRDR_PCICLKGATT_PAD_PWRON; writeb(gatt, host->pcictrl_mmiobase + VIA_CRDR_PCICLKGATT); - mmiowb(); spin_unlock_irqrestore(&host->lock, flags); via_pwron_sleep(host); @@ -770,7 +768,6 @@ static void via_sdc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) if (readb(addrbase + VIA_CRDR_PCISDCCLK) != clock) writeb(clock, addrbase + VIA_CRDR_PCISDCCLK); - mmiowb(); spin_unlock_irqrestore(&host->lock, flags); if (ios->power_mode != MMC_POWER_OFF) @@ -830,7 +827,6 @@ static void via_reset_pcictrl(struct via_crdr_mmc_host *host) via_restore_pcictrlreg(host); via_restore_sdcreg(host); - mmiowb(); spin_unlock_irqrestore(&host->lock, flags); } @@ -925,7 +921,6 @@ static irqreturn_t via_sdc_isr(int irq, void *dev_id) result = IRQ_HANDLED; - mmiowb(); out: spin_unlock(&sdhost->lock); @@ -960,7 +955,6 @@ static void via_sdc_timeout(struct timer_list *t) } } - mmiowb(); spin_unlock_irqrestore(&sdhost->lock, flags); } @@ -1012,7 +1006,6 @@ static void via_sdc_card_detect(struct work_struct *work) tasklet_schedule(&host->finish_tasklet); } - mmiowb(); spin_unlock_irqrestore(&host->lock, flags); via_reset_pcictrl(host); @@ -1020,7 +1013,6 @@ static void via_sdc_card_detect(struct work_struct *work) spin_lock_irqsave(&host->lock, flags); } - mmiowb(); spin_unlock_irqrestore(&host->lock, flags); via_print_pcictrl(host); @@ -1188,7 +1180,6 @@ static void via_sd_remove(struct pci_dev *pcidev) /* Disable generating further interrupts */ writeb(0x0, sdhost->pcictrl_mmiobase + VIA_CRDR_PCIINTCTRL); - mmiowb(); if (sdhost->mrq) { pr_err("%s: Controller removed during " @@ -1197,7 +1188,6 @@ static void via_sd_remove(struct pci_dev *pcidev) /* make sure all DMA is stopped */ writel(VIA_CRDR_DMACTRL_SFTRST, sdhost->ddma_mmiobase + VIA_CRDR_DMACTRL); - mmiowb(); sdhost->mrq->cmd->error = -ENOMEDIUM; if (sdhost->mrq->stop) sdhost->mrq->stop->error = -ENOMEDIUM; diff --git a/drivers/mmc/host/wmt-sdmmc.c b/drivers/mmc/host/wmt-sdmmc.c index 3ba42f508014..4fd6da29489e 100644 --- a/drivers/mmc/host/wmt-sdmmc.c +++ b/drivers/mmc/host/wmt-sdmmc.c @@ -19,7 +19,6 @@ #include <linux/io.h> #include <linux/irq.h> #include <linux/clk.h> -#include <linux/gpio.h> #include <linux/interrupt.h> #include <linux/of.h> |

