diff options
Diffstat (limited to 'drivers/mmc')
43 files changed, 960 insertions, 590 deletions
diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index 90e1bcd03b46..4e61b28a002f 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -264,7 +264,7 @@ static ssize_t power_ro_lock_store(struct device *dev, goto out_put; } req_to_mmc_queue_req(req)->drv_op = MMC_DRV_OP_BOOT_WP; - blk_execute_rq(NULL, req, 0); + blk_execute_rq(req, false); ret = req_to_mmc_queue_req(req)->drv_op_result; blk_mq_free_request(req); @@ -657,7 +657,7 @@ static int mmc_blk_ioctl_cmd(struct mmc_blk_data *md, rpmb ? MMC_DRV_OP_IOCTL_RPMB : MMC_DRV_OP_IOCTL; req_to_mmc_queue_req(req)->drv_op_data = idatas; req_to_mmc_queue_req(req)->ioc_count = 1; - blk_execute_rq(NULL, req, 0); + blk_execute_rq(req, false); ioc_err = req_to_mmc_queue_req(req)->drv_op_result; err = mmc_blk_ioctl_copy_to_user(ic_ptr, idata); blk_mq_free_request(req); @@ -726,7 +726,7 @@ static int mmc_blk_ioctl_multi_cmd(struct mmc_blk_data *md, rpmb ? MMC_DRV_OP_IOCTL_RPMB : MMC_DRV_OP_IOCTL; req_to_mmc_queue_req(req)->drv_op_data = idata; req_to_mmc_queue_req(req)->ioc_count = num_of_cmds; - blk_execute_rq(NULL, req, 0); + blk_execute_rq(req, false); ioc_err = req_to_mmc_queue_req(req)->drv_op_result; /* copy to user if data and response */ @@ -1837,7 +1837,7 @@ static void mmc_blk_mq_rw_recovery(struct mmc_queue *mq, struct request *req) /* Reset if the card is in a bad state */ if (!mmc_host_is_spi(mq->card->host) && err && mmc_blk_reset(md, card->host, type)) { - pr_err("%s: recovery failed!\n", req->rq_disk->disk_name); + pr_err("%s: recovery failed!\n", req->q->disk->disk_name); mqrq->retries = MMC_NO_RETRIES; return; } @@ -1908,8 +1908,8 @@ static int mmc_blk_card_busy(struct mmc_card *card, struct request *req) cb_data.card = card; cb_data.status = 0; - err = __mmc_poll_for_busy(card, MMC_BLK_TIMEOUT_MS, &mmc_blk_busy_cb, - &cb_data); + err = __mmc_poll_for_busy(card->host, MMC_BLK_TIMEOUT_MS, + &mmc_blk_busy_cb, &cb_data); /* * Do not assume data transferred correctly if there are any error bits @@ -2051,7 +2051,8 @@ static void mmc_blk_mq_dec_in_flight(struct mmc_queue *mq, struct request *req) mmc_put_card(mq->card, &mq->ctx); } -static void mmc_blk_mq_post_req(struct mmc_queue *mq, struct request *req) +static void mmc_blk_mq_post_req(struct mmc_queue *mq, struct request *req, + bool can_sleep) { struct mmc_queue_req *mqrq = req_to_mmc_queue_req(req); struct mmc_request *mrq = &mqrq->brq.mrq; @@ -2063,10 +2064,14 @@ static void mmc_blk_mq_post_req(struct mmc_queue *mq, struct request *req) * Block layer timeouts race with completions which means the normal * completion path cannot be used during recovery. */ - if (mq->in_recovery) + if (mq->in_recovery) { mmc_blk_mq_complete_rq(mq, req); - else if (likely(!blk_should_fake_timeout(req->q))) - blk_mq_complete_request(req); + } else if (likely(!blk_should_fake_timeout(req->q))) { + if (can_sleep) + blk_mq_complete_request_direct(req, mmc_blk_mq_complete); + else + blk_mq_complete_request(req); + } mmc_blk_mq_dec_in_flight(mq, req); } @@ -2087,7 +2092,7 @@ void mmc_blk_mq_recovery(struct mmc_queue *mq) mmc_blk_urgent_bkops(mq, mqrq); - mmc_blk_mq_post_req(mq, req); + mmc_blk_mq_post_req(mq, req, true); } static void mmc_blk_mq_complete_prev_req(struct mmc_queue *mq, @@ -2106,7 +2111,7 @@ static void mmc_blk_mq_complete_prev_req(struct mmc_queue *mq, if (prev_req) *prev_req = mq->complete_req; else - mmc_blk_mq_post_req(mq, mq->complete_req); + mmc_blk_mq_post_req(mq, mq->complete_req, true); mq->complete_req = NULL; @@ -2178,7 +2183,8 @@ static void mmc_blk_mq_req_done(struct mmc_request *mrq) mq->rw_wait = false; wake_up(&mq->wait); - mmc_blk_mq_post_req(mq, req); + /* context unknown */ + mmc_blk_mq_post_req(mq, req, false); } static bool mmc_blk_rw_wait_cond(struct mmc_queue *mq, int *err) @@ -2238,7 +2244,7 @@ static int mmc_blk_mq_issue_rw_rq(struct mmc_queue *mq, err = mmc_start_request(host, &mqrq->brq.mrq); if (prev_req) - mmc_blk_mq_post_req(mq, prev_req); + mmc_blk_mq_post_req(mq, prev_req, true); if (err) mq->rw_wait = false; @@ -2395,10 +2401,8 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card, md->disk->private_data = md; md->parent = parent; set_disk_ro(md->disk, md->read_only || default_ro); - md->disk->flags = GENHD_FL_EXT_DEVT; if (area_type & (MMC_BLK_DATA_AREA_RPMB | MMC_BLK_DATA_AREA_BOOT)) - md->disk->flags |= GENHD_FL_NO_PART_SCAN - | GENHD_FL_SUPPRESS_PARTITION_INFO; + md->disk->flags |= GENHD_FL_NO_PART; /* * As discussed on lkml, GENHD_FL_REMOVABLE should: @@ -2739,7 +2743,7 @@ static int mmc_dbg_card_status_get(void *data, u64 *val) if (IS_ERR(req)) return PTR_ERR(req); req_to_mmc_queue_req(req)->drv_op = MMC_DRV_OP_GET_CARD_STATUS; - blk_execute_rq(NULL, req, 0); + blk_execute_rq(req, false); ret = req_to_mmc_queue_req(req)->drv_op_result; if (ret >= 0) { *val = ret; @@ -2778,7 +2782,7 @@ static int mmc_ext_csd_open(struct inode *inode, struct file *filp) } req_to_mmc_queue_req(req)->drv_op = MMC_DRV_OP_GET_EXT_CSD; req_to_mmc_queue_req(req)->drv_op_data = &ext_csd; - blk_execute_rq(NULL, req, 0); + blk_execute_rq(req, false); err = req_to_mmc_queue_req(req)->drv_op_result; blk_mq_free_request(req); if (err) { diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c index f6b7a9c5bbff..096ae624be9a 100644 --- a/drivers/mmc/core/bus.c +++ b/drivers/mmc/core/bus.c @@ -53,16 +53,6 @@ static struct attribute *mmc_dev_attrs[] = { }; ATTRIBUTE_GROUPS(mmc_dev); -/* - * This currently matches any MMC driver to any MMC card - drivers - * themselves make the decision whether to drive this card in their - * probe method. - */ -static int mmc_bus_match(struct device *dev, struct device_driver *drv) -{ - return 1; -} - static int mmc_bus_uevent(struct device *dev, struct kobj_uevent_env *env) { @@ -226,7 +216,6 @@ static const struct dev_pm_ops mmc_bus_pm_ops = { static struct bus_type mmc_bus_type = { .name = "mmc", .dev_groups = mmc_dev_groups, - .match = mmc_bus_match, .uevent = mmc_bus_uevent, .probe = mmc_bus_probe, .remove = mmc_bus_remove, diff --git a/drivers/mmc/core/card.h b/drivers/mmc/core/card.h index 7bd392d55cfa..99045e138ba4 100644 --- a/drivers/mmc/core/card.h +++ b/drivers/mmc/core/card.h @@ -59,6 +59,9 @@ struct mmc_fixup { /* for MMC cards */ unsigned int ext_csd_rev; + /* Match against functions declared in device tree */ + const char *of_compatible; + void (*vendor_fixup)(struct mmc_card *card, int data); int data; }; @@ -119,6 +122,21 @@ struct mmc_fixup { _vendor, _device, \ _fixup, _data, EXT_CSD_REV_ANY) \ +#define SDIO_FIXUP_COMPATIBLE(_compatible, _fixup, _data) \ + { \ + .name = CID_NAME_ANY, \ + .manfid = CID_MANFID_ANY, \ + .oemid = CID_OEMID_ANY, \ + .rev_start = 0, \ + .rev_end = -1ull, \ + .cis_vendor = SDIO_ANY_ID, \ + .cis_device = SDIO_ANY_ID, \ + .vendor_fixup = (_fixup), \ + .data = (_data), \ + .ext_csd_rev = EXT_CSD_REV_ANY, \ + .of_compatible = _compatible, \ + } + #define cid_rev(hwrev, fwrev, year, month) \ (((u64) hwrev) << 40 | \ ((u64) fwrev) << 32 | \ @@ -150,6 +168,24 @@ static inline void __maybe_unused add_limit_rate_quirk(struct mmc_card *card, card->quirk_max_rate = data; } +static inline void __maybe_unused wl1251_quirk(struct mmc_card *card, + int data) +{ + /* + * We have TI wl1251 attached to this mmc. Pass this + * information to the SDIO core because it can't be + * probed by normal methods. + */ + + dev_info(card->host->parent, "found wl1251\n"); + card->quirks |= MMC_QUIRK_NONSTD_SDIO; + card->cccr.wide_bus = 1; + card->cis.vendor = 0x104c; + card->cis.device = 0x9066; + card->cis.blksize = 512; + card->cis.max_dtr = 24000000; +} + /* * Quirk add/remove for MMC products. */ diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 240c5af793dc..368f10405e13 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -2264,7 +2264,7 @@ void mmc_start_host(struct mmc_host *host) _mmc_detect_change(host, 0, false); } -void mmc_stop_host(struct mmc_host *host) +void __mmc_stop_host(struct mmc_host *host) { if (host->slot.cd_irq >= 0) { mmc_gpio_set_cd_wake(host, false); @@ -2273,6 +2273,11 @@ void mmc_stop_host(struct mmc_host *host) host->rescan_disable = 1; cancel_delayed_work_sync(&host->detect); +} + +void mmc_stop_host(struct mmc_host *host) +{ + __mmc_stop_host(host); /* clear pm flags now and let card drivers set them as needed */ host->pm_flags = 0; diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h index 7931a4f0137d..f5f3f623ea49 100644 --- a/drivers/mmc/core/core.h +++ b/drivers/mmc/core/core.h @@ -70,6 +70,7 @@ static inline void mmc_delay(unsigned int ms) void mmc_rescan(struct work_struct *work); void mmc_start_host(struct mmc_host *host); +void __mmc_stop_host(struct mmc_host *host); void mmc_stop_host(struct mmc_host *host); void _mmc_detect_change(struct mmc_host *host, unsigned long delay, diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index d4683b1d263f..cf140f4ec864 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -80,9 +80,18 @@ static void mmc_host_classdev_release(struct device *dev) kfree(host); } +static int mmc_host_classdev_shutdown(struct device *dev) +{ + struct mmc_host *host = cls_dev_to_mmc_host(dev); + + __mmc_stop_host(host); + return 0; +} + static struct class mmc_host_class = { .name = "mmc_host", .dev_release = mmc_host_classdev_release, + .shutdown_pre = mmc_host_classdev_shutdown, .pm = MMC_HOST_CLASS_DEV_PM_OPS, }; diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index b1c1716dacf0..bbbbcaf70a59 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -1962,7 +1962,7 @@ static int mmc_sleep(struct mmc_host *host) goto out_release; } - err = __mmc_poll_for_busy(card, timeout_ms, &mmc_sleep_busy_cb, host); + err = __mmc_poll_for_busy(host, timeout_ms, &mmc_sleep_busy_cb, host); out_release: mmc_retune_release(host); diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c index 0c54858e89c0..d63d1c735335 100644 --- a/drivers/mmc/core/mmc_ops.c +++ b/drivers/mmc/core/mmc_ops.c @@ -58,6 +58,12 @@ struct mmc_busy_data { enum mmc_busy_cmd busy_cmd; }; +struct mmc_op_cond_busy_data { + struct mmc_host *host; + u32 ocr; + struct mmc_command *cmd; +}; + int __mmc_send_status(struct mmc_card *card, u32 *status, unsigned int retries) { int err; @@ -173,43 +179,62 @@ int mmc_go_idle(struct mmc_host *host) return err; } +static int __mmc_send_op_cond_cb(void *cb_data, bool *busy) +{ + struct mmc_op_cond_busy_data *data = cb_data; + struct mmc_host *host = data->host; + struct mmc_command *cmd = data->cmd; + u32 ocr = data->ocr; + int err = 0; + + err = mmc_wait_for_cmd(host, cmd, 0); + if (err) + return err; + + if (mmc_host_is_spi(host)) { + if (!(cmd->resp[0] & R1_SPI_IDLE)) { + *busy = false; + return 0; + } + } else { + if (cmd->resp[0] & MMC_CARD_BUSY) { + *busy = false; + return 0; + } + } + + *busy = true; + + /* + * 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); + + return 0; +} + int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) { struct mmc_command cmd = {}; - int i, err = 0; + int err = 0; + struct mmc_op_cond_busy_data cb_data = { + .host = host, + .ocr = ocr, + .cmd = &cmd + }; cmd.opcode = MMC_SEND_OP_COND; cmd.arg = mmc_host_is_spi(host) ? 0 : ocr; cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R3 | MMC_CMD_BCR; - for (i = 100; i; i--) { - err = mmc_wait_for_cmd(host, &cmd, 0); - if (err) - break; - - /* wait until reset completes */ - if (mmc_host_is_spi(host)) { - if (!(cmd.resp[0] & R1_SPI_IDLE)) - break; - } else { - if (cmd.resp[0] & MMC_CARD_BUSY) - break; - } - - 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); - } + err = __mmc_poll_for_busy(host, 1000, &__mmc_send_op_cond_cb, &cb_data); + if (err) + return err; if (rocr && !mmc_host_is_spi(host)) *rocr = cmd.resp[0]; @@ -470,11 +495,10 @@ static int mmc_busy_cb(void *cb_data, bool *busy) return 0; } -int __mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms, +int __mmc_poll_for_busy(struct mmc_host *host, unsigned int timeout_ms, int (*busy_cb)(void *cb_data, bool *busy), void *cb_data) { - struct mmc_host *host = card->host; int err; unsigned long timeout; unsigned int udelay = 32, udelay_max = 32768; @@ -515,13 +539,14 @@ EXPORT_SYMBOL_GPL(__mmc_poll_for_busy); int mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms, bool retry_crc_err, enum mmc_busy_cmd busy_cmd) { + struct mmc_host *host = card->host; struct mmc_busy_data cb_data; cb_data.card = card; cb_data.retry_crc_err = retry_crc_err; cb_data.busy_cmd = busy_cmd; - return __mmc_poll_for_busy(card, timeout_ms, &mmc_busy_cb, &cb_data); + return __mmc_poll_for_busy(host, timeout_ms, &mmc_busy_cb, &cb_data); } EXPORT_SYMBOL_GPL(mmc_poll_for_busy); diff --git a/drivers/mmc/core/mmc_ops.h b/drivers/mmc/core/mmc_ops.h index e5e94567a9a9..9c813b851d0b 100644 --- a/drivers/mmc/core/mmc_ops.h +++ b/drivers/mmc/core/mmc_ops.h @@ -41,7 +41,7 @@ int mmc_can_ext_csd(struct mmc_card *card); int mmc_switch_status(struct mmc_card *card, bool crc_err_fatal); bool mmc_prepare_busy_cmd(struct mmc_host *host, struct mmc_command *cmd, unsigned int timeout_ms); -int __mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms, +int __mmc_poll_for_busy(struct mmc_host *host, unsigned int timeout_ms, int (*busy_cb)(void *cb_data, bool *busy), void *cb_data); int mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms, diff --git a/drivers/mmc/core/pwrseq_simple.c b/drivers/mmc/core/pwrseq_simple.c index ea4d3670560e..988467fbb621 100644 --- a/drivers/mmc/core/pwrseq_simple.c +++ b/drivers/mmc/core/pwrseq_simple.c @@ -54,7 +54,7 @@ static void mmc_pwrseq_simple_set_gpios_value(struct mmc_pwrseq_simple *pwrseq, gpiod_set_array_value_cansleep(nvalues, reset_gpios->desc, reset_gpios->info, values); - kfree(values); + bitmap_free(values); } } diff --git a/drivers/mmc/core/queue.c b/drivers/mmc/core/queue.c index b15c034b42fb..c69b2d9df6f1 100644 --- a/drivers/mmc/core/queue.c +++ b/drivers/mmc/core/queue.c @@ -234,7 +234,7 @@ static blk_status_t mmc_mq_queue_rq(struct blk_mq_hw_ctx *hctx, enum mmc_issue_type issue_type; enum mmc_issued issued; bool get_card, cqe_retune_ok; - int ret; + blk_status_t ret; if (mmc_card_removed(mq->card)) { req->rq_flags |= RQF_QUIET; diff --git a/drivers/mmc/core/quirks.h b/drivers/mmc/core/quirks.h index d68e6e513a4f..20f568727277 100644 --- a/drivers/mmc/core/quirks.h +++ b/drivers/mmc/core/quirks.h @@ -10,6 +10,7 @@ * */ +#include <linux/of.h> #include <linux/mmc/sdio_ids.h> #include "card.h" @@ -145,6 +146,25 @@ static const struct mmc_fixup __maybe_unused sdio_fixup_methods[] = { END_FIXUP }; +static const struct mmc_fixup __maybe_unused sdio_card_init_methods[] = { + SDIO_FIXUP_COMPATIBLE("ti,wl1251", wl1251_quirk, 0), + + END_FIXUP +}; + +static inline bool mmc_fixup_of_compatible_match(struct mmc_card *card, + const char *compatible) +{ + struct device_node *np; + + for_each_child_of_node(mmc_dev(card->host)->of_node, np) { + if (of_device_is_compatible(np, compatible)) + return true; + } + + return false; +} + static inline void mmc_fixup_device(struct mmc_card *card, const struct mmc_fixup *table) { @@ -152,22 +172,32 @@ static inline void mmc_fixup_device(struct mmc_card *card, u64 rev = cid_rev_card(card); for (f = table; f->vendor_fixup; f++) { - if ((f->manfid == CID_MANFID_ANY || - f->manfid == card->cid.manfid) && - (f->oemid == CID_OEMID_ANY || - f->oemid == card->cid.oemid) && - (f->name == CID_NAME_ANY || - !strncmp(f->name, card->cid.prod_name, - sizeof(card->cid.prod_name))) && - (f->cis_vendor == card->cis.vendor || - f->cis_vendor == (u16) SDIO_ANY_ID) && - (f->cis_device == card->cis.device || - f->cis_device == (u16) SDIO_ANY_ID) && - (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 %ps\n", f->vendor_fixup); - f->vendor_fixup(card, f->data); - } + if (f->manfid != CID_MANFID_ANY && + f->manfid != card->cid.manfid) + continue; + if (f->oemid != CID_OEMID_ANY && + f->oemid != card->cid.oemid) + continue; + if (f->name != CID_NAME_ANY && + strncmp(f->name, card->cid.prod_name, + sizeof(card->cid.prod_name))) + continue; + if (f->cis_vendor != (u16)SDIO_ANY_ID && + f->cis_vendor != card->cis.vendor) + continue; + if (f->cis_device != (u16)SDIO_ANY_ID && + f->cis_device != card->cis.device) + continue; + if (f->ext_csd_rev != EXT_CSD_REV_ANY && + f->ext_csd_rev != card->ext_csd.rev) + continue; + if (rev < f->rev_start || rev > f->rev_end) + continue; + if (f->of_compatible && + !mmc_fixup_of_compatible_match(card, f->of_compatible)) + continue; + + dev_dbg(&card->dev, "calling %ps\n", f->vendor_fixup); + f->vendor_fixup(card, f->data); } } diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index c9db24e16af1..45f578793980 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -1666,7 +1666,7 @@ static int sd_poweroff_notify(struct mmc_card *card) cb_data.card = card; cb_data.reg_buf = reg_buf; - err = __mmc_poll_for_busy(card, SD_POWEROFF_NOTIFY_TIMEOUT_MS, + err = __mmc_poll_for_busy(card->host, SD_POWEROFF_NOTIFY_TIMEOUT_MS, &sd_busy_poweroff_notify_cb, &cb_data); out: diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index 68edf7a615be..41164748723d 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -707,6 +707,9 @@ try_again: */ if (host->ops->init_card) host->ops->init_card(host, card); + mmc_fixup_device(card, sdio_card_init_methods); + + card->ocr = ocr_card; /* * If the host and card support UHS-I mode request the card @@ -820,7 +823,7 @@ try_again: goto mismatch; } } - card->ocr = ocr_card; + mmc_fixup_device(card, sdio_fixup_methods); if (card->type == MMC_TYPE_SD_COMBO) { diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index 5af8494c31b5..52b0b27a6839 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -966,6 +966,7 @@ config MMC_REALTEK_USB config MMC_SUNXI tristate "Allwinner sunxi SD/MMC Host Controller support" depends on ARCH_SUNXI || COMPILE_TEST + depends on SUNXI_CCU help This selects support for the SD/MMC Host Controller on Allwinner sunxi SoCs. diff --git a/drivers/mmc/host/au1xmmc.c b/drivers/mmc/host/au1xmmc.c index 0acc237843f7..a9a0837153d8 100644 --- a/drivers/mmc/host/au1xmmc.c +++ b/drivers/mmc/host/au1xmmc.c @@ -969,8 +969,10 @@ static int au1xmmc_probe(struct platform_device *pdev) } host->irq = platform_get_irq(pdev, 0); - if (host->irq < 0) + if (host->irq < 0) { + ret = host->irq; goto out3; + } mmc->ops = &au1xmmc_ops; diff --git a/drivers/mmc/host/bcm2835.c b/drivers/mmc/host/bcm2835.c index 8c2361e66277..463b707d9e99 100644 --- a/drivers/mmc/host/bcm2835.c +++ b/drivers/mmc/host/bcm2835.c @@ -1293,14 +1293,12 @@ static int bcm2835_add_host(struct bcm2835_host *host) host->dma_cfg_tx.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; host->dma_cfg_tx.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; - host->dma_cfg_tx.slave_id = 13; /* DREQ channel */ host->dma_cfg_tx.direction = DMA_MEM_TO_DEV; host->dma_cfg_tx.src_addr = 0; host->dma_cfg_tx.dst_addr = host->phys_addr + SDDATA; host->dma_cfg_rx.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; host->dma_cfg_rx.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; - host->dma_cfg_rx.slave_id = 13; /* DREQ channel */ host->dma_cfg_rx.direction = DMA_DEV_TO_MEM; host->dma_cfg_rx.src_addr = host->phys_addr + SDDATA; host->dma_cfg_rx.dst_addr = 0; diff --git a/drivers/mmc/host/dw_mmc-exynos.c b/drivers/mmc/host/dw_mmc-exynos.c index c2dd29ef45c6..ca5be4445ae0 100644 --- a/drivers/mmc/host/dw_mmc-exynos.c +++ b/drivers/mmc/host/dw_mmc-exynos.c @@ -28,6 +28,7 @@ enum dw_mci_exynos_type { DW_MCI_TYPE_EXYNOS5420_SMU, DW_MCI_TYPE_EXYNOS7, DW_MCI_TYPE_EXYNOS7_SMU, + DW_MCI_TYPE_ARTPEC8, }; /* Exynos implementation specific driver private data */ @@ -69,6 +70,9 @@ static struct dw_mci_exynos_compatible { }, { .compatible = "samsung,exynos7-dw-mshc-smu", .ctrl_type = DW_MCI_TYPE_EXYNOS7_SMU, + }, { + .compatible = "axis,artpec8-dw-mshc", + .ctrl_type = DW_MCI_TYPE_ARTPEC8, }, }; @@ -81,7 +85,8 @@ static inline u8 dw_mci_exynos_get_ciu_div(struct dw_mci *host) else if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS4210) return EXYNOS4210_FIXED_CIU_CLK_DIV; else if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || - priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU) + priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU || + priv->ctrl_type == DW_MCI_TYPE_ARTPEC8) return SDMMC_CLKSEL_GET_DIV(mci_readl(host, CLKSEL64)) + 1; else return SDMMC_CLKSEL_GET_DIV(mci_readl(host, CLKSEL)) + 1; @@ -122,6 +127,11 @@ static int dw_mci_exynos_priv_init(struct dw_mci *host) DQS_CTRL_GET_RD_DELAY(priv->saved_strobe_ctrl); } + if (priv->ctrl_type == DW_MCI_TYPE_ARTPEC8) { + /* Quirk needed for the ARTPEC-8 SoC */ + host->quirks |= DW_MMC_QUIRK_EXTENDED_TMOUT; + } + host->bus_hz /= (priv->ciu_div + 1); return 0; @@ -133,7 +143,8 @@ static void dw_mci_exynos_set_clksel_timing(struct dw_mci *host, u32 timing) u32 clksel; if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || - priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU) + priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU || + priv->ctrl_type == DW_MCI_TYPE_ARTPEC8) clksel = mci_readl(host, CLKSEL64); else clksel = mci_readl(host, CLKSEL); @@ -141,7 +152,8 @@ static void dw_mci_exynos_set_clksel_timing(struct dw_mci *host, u32 timing) clksel = (clksel & ~SDMMC_CLKSEL_TIMING_MASK) | timing; if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || - priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU) + priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU || + priv->ctrl_type == DW_MCI_TYPE_ARTPEC8) mci_writel(host, CLKSEL64, clksel); else mci_writel(host, CLKSEL, clksel); @@ -210,14 +222,16 @@ static int dw_mci_exynos_resume_noirq(struct device *dev) return ret; if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || - priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU) + priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU || + priv->ctrl_type == DW_MCI_TYPE_ARTPEC8) clksel = mci_readl(host, CLKSEL64); else clksel = mci_readl(host, CLKSEL); if (clksel & SDMMC_CLKSEL_WAKEUP_INT) { if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || - priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU) + priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU || + priv->ctrl_type == DW_MCI_TYPE_ARTPEC8) mci_writel(host, CLKSEL64, clksel); else mci_writel(host, CLKSEL, clksel); @@ -238,7 +252,8 @@ static void dw_mci_exynos_config_hs400(struct dw_mci *host, u32 timing) * Not supported to configure register * related to HS400 */ - if (priv->ctrl_type < DW_MCI_TYPE_EXYNOS5420) { + if ((priv->ctrl_type < DW_MCI_TYPE_EXYNOS5420) || + (priv->ctrl_type == DW_MCI_TYPE_ARTPEC8)) { if (timing == MMC_TIMING_MMC_HS400) dev_warn(host->dev, "cannot configure HS400, unsupported chipset\n"); @@ -394,7 +409,8 @@ static inline u8 dw_mci_exynos_get_clksmpl(struct dw_mci *host) struct dw_mci_exynos_priv_data *priv = host->priv; if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || - priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU) + priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU || + priv->ctrl_type == DW_MCI_TYPE_ARTPEC8) return SDMMC_CLKSEL_CCLK_SAMPLE(mci_readl(host, CLKSEL64)); else return SDMMC_CLKSEL_CCLK_SAMPLE(mci_readl(host, CLKSEL)); @@ -406,13 +422,15 @@ static inline void dw_mci_exynos_set_clksmpl(struct dw_mci *host, u8 sample) struct dw_mci_exynos_priv_data *priv = host->priv; if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || - priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU) + priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU || + priv->ctrl_type == DW_MCI_TYPE_ARTPEC8) clksel = mci_readl(host, CLKSEL64); else clksel = mci_readl(host, CLKSEL); clksel = SDMMC_CLKSEL_UP_SAMPLE(clksel, sample); if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || - priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU) + priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU || + priv->ctrl_type == DW_MCI_TYPE_ARTPEC8) mci_writel(host, CLKSEL64, clksel); else mci_writel(host, CLKSEL, clksel); @@ -425,7 +443,8 @@ static inline u8 dw_mci_exynos_move_next_clksmpl(struct dw_mci *host) u8 sample; if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || - priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU) + priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU || + priv->ctrl_type == DW_MCI_TYPE_ARTPEC8) clksel = mci_readl(host, CLKSEL64); else clksel = mci_readl(host, CLKSEL); @@ -434,7 +453,8 @@ static inline u8 dw_mci_exynos_move_next_clksmpl(struct dw_mci *host) clksel = SDMMC_CLKSEL_UP_SAMPLE(clksel, sample); if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || - priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU) + priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU || + priv->ctrl_type == DW_MCI_TYPE_ARTPEC8) mci_writel(host, CLKSEL64, clksel); else mci_writel(host, CLKSEL, clksel); @@ -524,17 +544,65 @@ static int dw_mci_exynos_prepare_hs400_tuning(struct dw_mci *host, return 0; } +static void dw_mci_exynos_set_data_timeout(struct dw_mci *host, + unsigned int timeout_ns) +{ + u32 clk_div, tmout; + u64 tmp; + unsigned int tmp2; + + clk_div = (mci_readl(host, CLKDIV) & 0xFF) * 2; + if (clk_div == 0) + clk_div = 1; + + tmp = DIV_ROUND_UP_ULL((u64)timeout_ns * host->bus_hz, NSEC_PER_SEC); + tmp = DIV_ROUND_UP_ULL(tmp, clk_div); + + /* TMOUT[7:0] (RESPONSE_TIMEOUT) */ + tmout = 0xFF; /* Set maximum */ + + /* + * Extended HW timer (max = 0x6FFFFF2): + * ((TMOUT[10:8] - 1) * 0xFFFFFF + TMOUT[31:11] * 8) + */ + if (!tmp || tmp > 0x6FFFFF2) + tmout |= (0xFFFFFF << 8); + else { + /* TMOUT[10:8] */ + tmp2 = (((unsigned int)tmp / 0xFFFFFF) + 1) & 0x7; + tmout |= tmp2 << 8; + + /* TMOUT[31:11] */ + tmp = tmp - ((tmp2 - 1) * 0xFFFFFF); + tmout |= (tmp & 0xFFFFF8) << 8; + } + + mci_writel(host, TMOUT, tmout); + dev_dbg(host->dev, "timeout_ns: %u => TMOUT[31:8]: %#08x", + timeout_ns, tmout >> 8); +} + +static u32 dw_mci_exynos_get_drto_clks(struct dw_mci *host) +{ + u32 drto_clks; + + drto_clks = mci_readl(host, TMOUT) >> 8; + + return (((drto_clks & 0x7) - 1) * 0xFFFFFF) + ((drto_clks & 0xFFFFF8)); +} + /* Common capabilities of Exynos4/Exynos5 SoC */ static unsigned long exynos_dwmmc_caps[4] = { - MMC_CAP_1_8V_DDR | MMC_CAP_8_BIT_DATA | MMC_CAP_CMD23, - MMC_CAP_CMD23, - MMC_CAP_CMD23, - MMC_CAP_CMD23, + MMC_CAP_1_8V_DDR | MMC_CAP_8_BIT_DATA, + 0, + 0, + 0, }; static const struct dw_mci_drv_data exynos_drv_data = { .caps = exynos_dwmmc_caps, .num_caps = ARRAY_SIZE(exynos_dwmmc_caps), + .common_caps = MMC_CAP_CMD23, .init = dw_mci_exynos_priv_init, .set_ios = dw_mci_exynos_set_ios, .parse_dt = dw_mci_exynos_parse_dt, @@ -542,6 +610,16 @@ static const struct dw_mci_drv_data exynos_drv_data = { .prepare_hs400_tuning = dw_mci_exynos_prepare_hs400_tuning, }; +static const struct dw_mci_drv_data artpec_drv_data = { + .common_caps = MMC_CAP_CMD23, + .init = dw_mci_exynos_priv_init, + .set_ios = dw_mci_exynos_set_ios, + .parse_dt = dw_mci_exynos_parse_dt, + .execute_tuning = dw_mci_exynos_execute_tuning, + .set_data_timeout = dw_mci_exynos_set_data_timeout, + .get_drto_clks = dw_mci_exynos_get_drto_clks, +}; + static const struct of_device_id dw_mci_exynos_match[] = { { .compatible = "samsung,exynos4412-dw-mshc", .data = &exynos_drv_data, }, @@ -555,6 +633,8 @@ static const struct of_device_id dw_mci_exynos_match[] = { .data = &exynos_drv_data, }, { .compatible = "samsung,exynos7-dw-mshc-smu", .data = &exynos_drv_data, }, + { .compatible = "axis,artpec8-dw-mshc", + .data = &artpec_drv_data, }, {}, }; MODULE_DEVICE_TABLE(of, dw_mci_exynos_match); diff --git a/drivers/mmc/host/dw_mmc-hi3798cv200.c b/drivers/mmc/host/dw_mmc-hi3798cv200.c index 39794f93826f..e9437ef8ef19 100644 --- a/drivers/mmc/host/dw_mmc-hi3798cv200.c +++ b/drivers/mmc/host/dw_mmc-hi3798cv200.c @@ -23,12 +23,6 @@ struct hi3798cv200_priv { struct clk *drive_clk; }; -static unsigned long dw_mci_hi3798cv200_caps[] = { - MMC_CAP_CMD23, - MMC_CAP_CMD23, - MMC_CAP_CMD23 -}; - static void dw_mci_hi3798cv200_set_ios(struct dw_mci *host, struct mmc_ios *ios) { struct hi3798cv200_priv *priv = host->priv; @@ -166,8 +160,7 @@ disable_sample_clk: } static const struct dw_mci_drv_data hi3798cv200_data = { - .caps = dw_mci_hi3798cv200_caps, - .num_caps = ARRAY_SIZE(dw_mci_hi3798cv200_caps), + .common_caps = MMC_CAP_CMD23, .init = dw_mci_hi3798cv200_init, .set_ios = dw_mci_hi3798cv200_set_ios, .execute_tuning = dw_mci_hi3798cv200_execute_tuning, diff --git a/drivers/mmc/host/dw_mmc-rockchip.c b/drivers/mmc/host/dw_mmc-rockchip.c index d36991acd6df..95d0ec0f5f3a 100644 --- a/drivers/mmc/host/dw_mmc-rockchip.c +++ b/drivers/mmc/host/dw_mmc-rockchip.c @@ -300,21 +300,12 @@ static int dw_mci_rockchip_init(struct dw_mci *host) return 0; } -/* Common capabilities of RK3288 SoC */ -static unsigned long dw_mci_rk3288_dwmmc_caps[4] = { - MMC_CAP_CMD23, - MMC_CAP_CMD23, - MMC_CAP_CMD23, - MMC_CAP_CMD23, -}; - static const struct dw_mci_drv_data rk2928_drv_data = { .init = dw_mci_rockchip_init, }; static const struct dw_mci_drv_data rk3288_drv_data = { - .caps = dw_mci_rk3288_dwmmc_caps, - .num_caps = ARRAY_SIZE(dw_mci_rk3288_dwmmc_caps), + .common_caps = MMC_CAP_CMD23, .set_ios = dw_mci_rk3288_set_ios, .execute_tuning = dw_mci_rk3288_execute_tuning, .parse_dt = dw_mci_rk3288_parse_dt, diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index d977f34f6b55..42bf8a2287ba 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -335,7 +335,8 @@ static u32 dw_mci_prep_stop_abort(struct dw_mci *host, struct mmc_command *cmd) cmdr == MMC_WRITE_BLOCK || cmdr == MMC_WRITE_MULTIPLE_BLOCK || cmdr == MMC_SEND_TUNING_BLOCK || - cmdr == MMC_SEND_TUNING_BLOCK_HS200) { + cmdr == MMC_SEND_TUNING_BLOCK_HS200 || + cmdr == MMC_GEN_CMD) { stop->opcode = MMC_STOP_TRANSMISSION; stop->arg = 0; stop->flags = MMC_RSP_R1B | MMC_CMD_AC; @@ -1283,6 +1284,37 @@ static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool force_clkinit) mci_writel(host, CTYPE, (slot->ctype << slot->id)); } +static void dw_mci_set_data_timeout(struct dw_mci *host, + unsigned int timeout_ns) +{ + const struct dw_mci_drv_data *drv_data = host->drv_data; + u32 clk_div, tmout; + u64 tmp; + + if (drv_data && drv_data->set_data_timeout) + return drv_data->set_data_timeout(host, timeout_ns); + + clk_div = (mci_readl(host, CLKDIV) & 0xFF) * 2; + if (clk_div == 0) + clk_div = 1; + + tmp = DIV_ROUND_UP_ULL((u64)timeout_ns * host->bus_hz, NSEC_PER_SEC); + tmp = DIV_ROUND_UP_ULL(tmp, clk_div); + + /* TMOUT[7:0] (RESPONSE_TIMEOUT) */ + tmout = 0xFF; /* Set maximum */ + + /* TMOUT[31:8] (DATA_TIMEOUT) */ + if (!tmp || tmp > 0xFFFFFF) + tmout |= (0xFFFFFF << 8); + else + tmout |= (tmp & 0xFFFFFF) << 8; + + mci_writel(host, TMOUT, tmout); + dev_dbg(host->dev, "timeout_ns: %u => TMOUT[31:8]: %#08x", + timeout_ns, tmout >> 8); +} + static void __dw_mci_start_request(struct dw_mci *host, struct dw_mci_slot *slot, struct mmc_command *cmd) @@ -1303,7 +1335,7 @@ static void __dw_mci_start_request(struct dw_mci *host, data = cmd->data; if (data) { - mci_writel(host, TMOUT, 0xFFFFFFFF); + dw_mci_set_data_timeout(host, data->timeout_ns); mci_writel(host, BYTCNT, data->blksz*data->blocks); mci_writel(host, BLKSIZ, data->blksz); } @@ -1967,12 +1999,16 @@ static int dw_mci_data_complete(struct dw_mci *host, struct mmc_data *data) static void dw_mci_set_drto(struct dw_mci *host) { + const struct dw_mci_drv_data *drv_data = host->drv_data; unsigned int drto_clks; unsigned int drto_div; unsigned int drto_ms; unsigned long irqflags; - drto_clks = mci_readl(host, TMOUT) >> 8; + if (drv_data && drv_data->get_drto_clks) + drto_clks = drv_data->get_drto_clks(host); + else + drto_clks = mci_readl(host, TMOUT) >> 8; drto_div = (mci_readl(host, CLKDIV) & 0xff) * 2; if (drto_div == 0) drto_div = 1; @@ -1980,6 +2016,8 @@ static void dw_mci_set_drto(struct dw_mci *host) drto_ms = DIV_ROUND_UP_ULL((u64)MSEC_PER_SEC * drto_clks * drto_div, host->bus_hz); + dev_dbg(host->dev, "drto_ms: %u\n", drto_ms); + /* add a bit spare time */ drto_ms += 10; @@ -2724,11 +2762,20 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id) if (pending & DW_MCI_DATA_ERROR_FLAGS) { spin_lock(&host->irq_lock); + if (host->quirks & DW_MMC_QUIRK_EXTENDED_TMOUT) + del_timer(&host->dto_timer); + /* if there is an error report DATA_ERROR */ mci_writel(host, RINTSTS, DW_MCI_DATA_ERROR_FLAGS); host->data_status = pending; smp_wmb(); /* drain writebuffer */ set_bit(EVENT_DATA_ERROR, &host->pending_events); + + if (host->quirks & DW_MMC_QUIRK_EXTENDED_TMOUT) + /* In case of error, we cannot expect a DTO */ + set_bit(EVENT_DATA_COMPLETE, + &host->pending_events); + tasklet_schedule(&host->tasklet); spin_unlock(&host->irq_lock); @@ -2828,6 +2875,9 @@ static int dw_mci_init_slot_caps(struct dw_mci_slot *slot) if (host->pdata->pm_caps) mmc->pm_caps = host->pdata->pm_caps; + if (drv_data) + mmc->caps |= drv_data->common_caps; + if (host->dev->of_node) { ctrl_id = of_alias_get_id(host->dev->of_node, "mshc"); if (ctrl_id < 0) diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h index ce05d81477d9..7f1e38621d13 100644 --- a/drivers/mmc/host/dw_mmc.h +++ b/drivers/mmc/host/dw_mmc.h @@ -118,6 +118,7 @@ struct dw_mci_dma_slave { * @part_buf: Simple buffer for partial fifo reads/writes. * @push_data: Pointer to FIFO push function. * @pull_data: Pointer to FIFO pull function. + * @quirks: Set of quirks that apply to specific versions of the IP. * @vqmmc_enabled: Status of vqmmc, should be true or false. * @irq_flags: The flags to be passed to request_irq. * @irq: The irq value to be passed to request_irq. @@ -223,6 +224,7 @@ struct dw_mci { void (*push_data)(struct dw_mci *host, void *buf, int cnt); void (*pull_data)(struct dw_mci *host, void *buf, int cnt); + u32 quirks; bool vqmmc_enabled; unsigned long irq_flags; /* IRQ flags */ int irq; @@ -274,6 +276,9 @@ struct dw_mci_board { struct dma_pdata *data; }; +/* Support for longer data read timeout */ +#define DW_MMC_QUIRK_EXTENDED_TMOUT BIT(0) + #define DW_MMC_240A 0x240a #define DW_MMC_280A 0x280a @@ -550,10 +555,14 @@ struct dw_mci_slot { * dw_mci driver data - dw-mshc implementation specific driver data. * @caps: mmc subsystem specified capabilities of the controller(s). * @num_caps: number of capabilities specified by @caps. + * @common_caps: mmc subsystem specified capabilities applicable to all of + * the controllers * @init: early implementation specific initialization. * @set_ios: handle bus specific extensions. * @parse_dt: parse implementation specific device tree properties. * @execute_tuning: implementation specific tuning procedure. + * @set_data_timeout: implementation specific timeout. + * @get_drto_clks: implementation specific cycle count for data read timeout. * * Provide controller implementation specific extensions. The usage of this * data structure is fully optional and usage of each member in this structure @@ -562,6 +571,7 @@ struct dw_mci_slot { struct dw_mci_drv_data { unsigned long *caps; u32 num_caps; + u32 common_caps; int (*init)(struct dw_mci *host); void (*set_ios)(struct dw_mci *host, struct mmc_ios *ios); int (*parse_dt)(struct dw_mci *host); @@ -570,5 +580,8 @@ struct dw_mci_drv_data { struct mmc_ios *ios); int (*switch_voltage)(struct mmc_host *mmc, struct mmc_ios *ios); + void (*set_data_timeout)(struct dw_mci *host, + unsigned int timeout_ns); + u32 (*get_drto_clks)(struct dw_mci *host); }; #endif /* _DW_MMC_H_ */ diff --git a/drivers/mmc/host/jz4740_mmc.c b/drivers/mmc/host/jz4740_mmc.c index 80a2c270d502..7ab1b38a7be5 100644 --- a/drivers/mmc/host/jz4740_mmc.c +++ b/drivers/mmc/host/jz4740_mmc.c @@ -217,11 +217,23 @@ static void jz4740_mmc_release_dma_channels(struct jz4740_mmc_host *host) return; dma_release_channel(host->dma_tx); - dma_release_channel(host->dma_rx); + if (host->dma_rx) + dma_release_channel(host->dma_rx); } static int jz4740_mmc_acquire_dma_channels(struct jz4740_mmc_host *host) { + struct device *dev = mmc_dev(host->mmc); + + host->dma_tx = dma_request_chan(dev, "tx-rx"); + if (!IS_ERR(host->dma_tx)) + return 0; + + if (PTR_ERR(host->dma_tx) != -ENODEV) { + dev_err(dev, "Failed to get dma tx-rx channel\n"); + return PTR_ERR(host->dma_tx); + } + host->dma_tx = dma_request_chan(mmc_dev(host->mmc), "tx"); if (IS_ERR(host->dma_tx)) { dev_err(mmc_dev(host->mmc), "Failed to get dma_tx channel\n"); @@ -241,7 +253,10 @@ static int jz4740_mmc_acquire_dma_channels(struct jz4740_mmc_host *host) static inline struct dma_chan *jz4740_mmc_get_dma_chan(struct jz4740_mmc_host *host, struct mmc_data *data) { - return (data->flags & MMC_DATA_READ) ? host->dma_rx : host->dma_tx; + if ((data->flags & MMC_DATA_READ) && host->dma_rx) + return host->dma_rx; + else + return host->dma_tx; } static void jz4740_mmc_dma_unmap(struct jz4740_mmc_host *host, @@ -1103,18 +1118,18 @@ static int jz4740_mmc_remove(struct platform_device *pdev) return 0; } -static int __maybe_unused jz4740_mmc_suspend(struct device *dev) +static int jz4740_mmc_suspend(struct device *dev) { return pinctrl_pm_select_sleep_state(dev); } -static int __maybe_unused jz4740_mmc_resume(struct device *dev) +static int jz4740_mmc_resume(struct device *dev) { return pinctrl_select_default_state(dev); } -static SIMPLE_DEV_PM_OPS(jz4740_mmc_pm_ops, jz4740_mmc_suspend, - jz4740_mmc_resume); +static DEFINE_SIMPLE_DEV_PM_OPS(jz4740_mmc_pm_ops, jz4740_mmc_suspend, + jz4740_mmc_resume); static struct platform_driver jz4740_mmc_driver = { .probe = jz4740_mmc_probe, @@ -1123,7 +1138,7 @@ static struct platform_driver jz4740_mmc_driver = { .name = "jz4740-mmc", .probe_type = PROBE_PREFER_ASYNCHRONOUS, .of_match_table = of_match_ptr(jz4740_mmc_of_match), - .pm = pm_ptr(&jz4740_mmc_pm_ops), + .pm = pm_sleep_ptr(&jz4740_mmc_pm_ops), }, }; diff --git a/drivers/mmc/host/meson-mx-sdhc-clkc.c b/drivers/mmc/host/meson-mx-sdhc-clkc.c index e1f29b279123..19200b7079a6 100644 --- a/drivers/mmc/host/meson-mx-sdhc-clkc.c +++ b/drivers/mmc/host/meson-mx-sdhc-clkc.c @@ -12,8 +12,6 @@ #include "meson-mx-sdhc.h" -#define MESON_SDHC_NUM_BUILTIN_CLKS 6 - struct meson_mx_sdhc_clkc { struct clk_mux src_sel; struct clk_divider div; diff --git a/drivers/mmc/host/meson-mx-sdhc-mmc.c b/drivers/mmc/host/meson-mx-sdhc-mmc.c index 7cd9c0ec2fcf..28aa78aa08f3 100644 --- a/drivers/mmc/host/meson-mx-sdhc-mmc.c +++ b/drivers/mmc/host/meson-mx-sdhc-mmc.c @@ -135,6 +135,7 @@ static void meson_mx_sdhc_start_cmd(struct mmc_host *mmc, struct mmc_command *cmd) { struct meson_mx_sdhc_host *host = mmc_priv(mmc); + bool manual_stop = false; u32 ictl, send; int pack_len; @@ -172,12 +173,27 @@ static void meson_mx_sdhc_start_cmd(struct mmc_host *mmc, else /* software flush: */ ictl |= MESON_SDHC_ICTL_DATA_XFER_OK; + + /* + * Mimic the logic from the vendor driver where (only) + * SD_IO_RW_EXTENDED commands with more than one block set the + * MESON_SDHC_MISC_MANUAL_STOP bit. This fixes the firmware + * download in the brcmfmac driver for a BCM43362/1 card. + * Without this sdio_memcpy_toio() (with a size of 219557 + * bytes) times out if MESON_SDHC_MISC_MANUAL_STOP is not set. + */ + manual_stop = cmd->data->blocks > 1 && + cmd->opcode == SD_IO_RW_EXTENDED; } else { pack_len = 0; ictl |= MESON_SDHC_ICTL_RESP_OK; } + regmap_update_bits(host->regmap, MESON_SDHC_MISC, + MESON_SDHC_MISC_MANUAL_STOP, + manual_stop ? MESON_SDHC_MISC_MANUAL_STOP : 0); + if (cmd->opcode == MMC_STOP_TRANSMISSION) send |= MESON_SDHC_SEND_DATA_STOP; @@ -838,6 +854,11 @@ static int meson_mx_sdhc_probe(struct platform_device *pdev) goto err_disable_pclk; irq = platform_get_irq(pdev, 0); + if (irq < 0) { + ret = irq; + goto err_disable_pclk; + } + ret = devm_request_threaded_irq(dev, irq, meson_mx_sdhc_irq, meson_mx_sdhc_irq_thread, IRQF_ONESHOT, NULL, host); diff --git a/drivers/mmc/host/meson-mx-sdio.c b/drivers/mmc/host/meson-mx-sdio.c index d4a48916bfb6..3a19a05ef55a 100644 --- a/drivers/mmc/host/meson-mx-sdio.c +++ b/drivers/mmc/host/meson-mx-sdio.c @@ -662,6 +662,11 @@ static int meson_mx_mmc_probe(struct platform_device *pdev) } irq = platform_get_irq(pdev, 0); + if (irq < 0) { + ret = irq; + goto error_free_mmc; + } + ret = devm_request_threaded_irq(host->controller_dev, irq, meson_mx_mmc_irq, meson_mx_mmc_irq_thread, IRQF_ONESHOT, diff --git a/drivers/mmc/host/mmc_spi.c b/drivers/mmc/host/mmc_spi.c index b431cdd27353..a576181e9db0 100644 --- a/drivers/mmc/host/mmc_spi.c +++ b/drivers/mmc/host/mmc_spi.c @@ -547,7 +547,7 @@ mmc_spi_command_send(struct mmc_spi_host *host, static void mmc_spi_setup_data_message( struct mmc_spi_host *host, - int multiple, + bool multiple, enum dma_data_direction direction) { struct spi_transfer *t; @@ -859,14 +859,14 @@ mmc_spi_data_do(struct mmc_spi_host *host, struct mmc_command *cmd, struct spi_device *spi = host->spi; struct device *dma_dev = host->dma_dev; struct spi_transfer *t; - enum dma_data_direction direction; + enum dma_data_direction direction = mmc_get_dma_dir(data); struct scatterlist *sg; unsigned n_sg; - int multiple = (data->blocks > 1); + bool multiple = (data->blocks > 1); + const char *write_or_read = (direction == DMA_TO_DEVICE) ? "write" : "read"; u32 clock_rate; unsigned long timeout; - direction = mmc_get_dma_dir(data); mmc_spi_setup_data_message(host, multiple, direction); t = &host->t; @@ -921,9 +921,7 @@ mmc_spi_data_do(struct mmc_spi_host *host, struct mmc_command *cmd, while (length) { t->len = min(length, blk_size); - dev_dbg(&host->spi->dev, " %s block, %d bytes\n", - (direction == DMA_TO_DEVICE) ? "write" : "read", - t->len); + dev_dbg(&spi->dev, " %s block, %d bytes\n", write_or_read, t->len); if (direction == DMA_TO_DEVICE) status = mmc_spi_writeblock(host, t, timeout); @@ -948,9 +946,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", - status); + dev_dbg(&spi->dev, "%s status %d\n", write_or_read, status); break; } } diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index c9cacd4d5b22..45b8608c935c 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -280,7 +280,7 @@ static struct variant_data variant_stm32_sdmmc = { static struct variant_data variant_stm32_sdmmcv2 = { .fifosize = 16 * 4, .fifohalfsize = 8 * 4, - .f_max = 208000000, + .f_max = 267000000, .stm32_clkdiv = true, .cmdreg_cpsm_enable = MCI_CPSM_STM32_ENABLE, .cmdreg_lrsp_crc = MCI_CPSM_STM32_LRSP_CRC, @@ -2435,6 +2435,11 @@ static const struct amba_id mmci_ids[] = { .mask = 0xf0ffffff, .data = &variant_stm32_sdmmcv2, }, + { + .id = 0x20253180, + .mask = 0xf0ffffff, + .data = &variant_stm32_sdmmcv2, + }, /* Qualcomm variants */ { .id = 0x00051180, diff --git a/drivers/mmc/host/mmci_stm32_sdmmc.c b/drivers/mmc/host/mmci_stm32_sdmmc.c index fdaa11f92fe6..9c13f2c31365 100644 --- a/drivers/mmc/host/mmci_stm32_sdmmc.c +++ b/drivers/mmc/host/mmci_stm32_sdmmc.c @@ -241,11 +241,12 @@ static void mmci_sdmmc_set_clkreg(struct mmci_host *host, unsigned int desired) /* * SDMMC_FBCK is selected when an external Delay Block is needed - * with SDR104. + * with SDR104 or HS200. */ if (host->mmc->ios.timing >= MMC_TIMING_UHS_SDR50) { clk |= MCI_STM32_CLK_BUSSPEED; - if (host->mmc->ios.timing == MMC_TIMING_UHS_SDR104) { + if (host->mmc->ios.timing == MMC_TIMING_UHS_SDR104 || + host->mmc->ios.timing == MMC_TIMING_MMC_HS200) { clk &= ~MCI_STM32_CLK_SEL_MSK; clk |= MCI_STM32_CLK_SELFBCK; } @@ -441,6 +442,8 @@ static int sdmmc_dlyb_phase_tuning(struct mmci_host *host, u32 opcode) return -EINVAL; } + writel_relaxed(0, dlyb->base + DLYB_CR); + phase = end_of_len - max_len / 2; sdmmc_dlyb_set_cfgr(dlyb, dlyb->unit, phase, false); diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c index 632775217d35..65037e1d7723 100644 --- a/drivers/mmc/host/mtk-sd.c +++ b/drivers/mmc/host/mtk-sd.c @@ -5,6 +5,7 @@ */ #include <linux/module.h> +#include <linux/bitops.h> #include <linux/clk.h> #include <linux/delay.h> #include <linux/dma-mapping.h> @@ -98,226 +99,226 @@ /*--------------------------------------------------------------------------*/ /* MSDC_CFG mask */ -#define MSDC_CFG_MODE (0x1 << 0) /* RW */ -#define MSDC_CFG_CKPDN (0x1 << 1) /* RW */ -#define MSDC_CFG_RST (0x1 << 2) /* RW */ -#define MSDC_CFG_PIO (0x1 << 3) /* RW */ -#define MSDC_CFG_CKDRVEN (0x1 << 4) /* RW */ -#define MSDC_CFG_BV18SDT (0x1 << 5) /* RW */ -#define MSDC_CFG_BV18PSS (0x1 << 6) /* R */ -#define MSDC_CFG_CKSTB (0x1 << 7) /* R */ -#define MSDC_CFG_CKDIV (0xff << 8) /* RW */ -#define MSDC_CFG_CKMOD (0x3 << 16) /* RW */ -#define MSDC_CFG_HS400_CK_MODE (0x1 << 18) /* RW */ -#define MSDC_CFG_HS400_CK_MODE_EXTRA (0x1 << 22) /* RW */ -#define MSDC_CFG_CKDIV_EXTRA (0xfff << 8) /* RW */ -#define MSDC_CFG_CKMOD_EXTRA (0x3 << 20) /* RW */ +#define MSDC_CFG_MODE BIT(0) /* RW */ +#define MSDC_CFG_CKPDN BIT(1) /* RW */ +#define MSDC_CFG_RST BIT(2) /* RW */ +#define MSDC_CFG_PIO BIT(3) /* RW */ +#define MSDC_CFG_CKDRVEN BIT(4) /* RW */ +#define MSDC_CFG_BV18SDT BIT(5) /* RW */ +#define MSDC_CFG_BV18PSS BIT(6) /* R */ +#define MSDC_CFG_CKSTB BIT(7) /* R */ +#define MSDC_CFG_CKDIV GENMASK(15, 8) /* RW */ +#define MSDC_CFG_CKMOD GENMASK(17, 16) /* RW */ +#define MSDC_CFG_HS400_CK_MODE BIT(18) /* RW */ +#define MSDC_CFG_HS400_CK_MODE_EXTRA BIT(22) /* RW */ +#define MSDC_CFG_CKDIV_EXTRA GENMASK(19, 8) /* RW */ +#define MSDC_CFG_CKMOD_EXTRA GENMASK(21, 20) /* RW */ /* MSDC_IOCON mask */ -#define MSDC_IOCON_SDR104CKS (0x1 << 0) /* RW */ -#define MSDC_IOCON_RSPL (0x1 << 1) /* RW */ -#define MSDC_IOCON_DSPL (0x1 << 2) /* RW */ -#define MSDC_IOCON_DDLSEL (0x1 << 3) /* RW */ -#define MSDC_IOCON_DDR50CKD (0x1 << 4) /* RW */ -#define MSDC_IOCON_DSPLSEL (0x1 << 5) /* RW */ -#define MSDC_IOCON_W_DSPL (0x1 << 8) /* RW */ -#define MSDC_IOCON_D0SPL (0x1 << 16) /* RW */ -#define MSDC_IOCON_D1SPL (0x1 << 17) /* RW */ -#define MSDC_IOCON_D2SPL (0x1 << 18) /* RW */ -#define MSDC_IOCON_D3SPL (0x1 << 19) /* RW */ -#define MSDC_IOCON_D4SPL (0x1 << 20) /* RW */ -#define MSDC_IOCON_D5SPL (0x1 << 21) /* RW */ -#define MSDC_IOCON_D6SPL (0x1 << 22) /* RW */ -#define MSDC_IOCON_D7SPL (0x1 << 23) /* RW */ -#define MSDC_IOCON_RISCSZ (0x3 << 24) /* RW */ +#define MSDC_IOCON_SDR104CKS BIT(0) /* RW */ +#define MSDC_IOCON_RSPL BIT(1) /* RW */ +#define MSDC_IOCON_DSPL BIT(2) /* RW */ +#define MSDC_IOCON_DDLSEL BIT(3) /* RW */ +#define MSDC_IOCON_DDR50CKD BIT(4) /* RW */ +#define MSDC_IOCON_DSPLSEL BIT(5) /* RW */ +#define MSDC_IOCON_W_DSPL BIT(8) /* RW */ +#define MSDC_IOCON_D0SPL BIT(16) /* RW */ +#define MSDC_IOCON_D1SPL BIT(17) /* RW */ +#define MSDC_IOCON_D2SPL BIT(18) /* RW */ +#define MSDC_IOCON_D3SPL BIT(19) /* RW */ +#define MSDC_IOCON_D4SPL BIT(20) /* RW */ +#define MSDC_IOCON_D5SPL BIT(21) /* RW */ +#define MSDC_IOCON_D6SPL BIT(22) /* RW */ +#define MSDC_IOCON_D7SPL BIT(23) /* RW */ +#define MSDC_IOCON_RISCSZ GENMASK(25, 24) /* RW */ /* MSDC_PS mask */ -#define MSDC_PS_CDEN (0x1 << 0) /* RW */ -#define MSDC_PS_CDSTS (0x1 << 1) /* R */ -#define MSDC_PS_CDDEBOUNCE (0xf << 12) /* RW */ -#define MSDC_PS_DAT (0xff << 16) /* R */ -#define MSDC_PS_DATA1 (0x1 << 17) /* R */ -#define MSDC_PS_CMD (0x1 << 24) /* R */ -#define MSDC_PS_WP (0x1 << 31) /* R */ +#define MSDC_PS_CDEN BIT(0) /* RW */ +#define MSDC_PS_CDSTS BIT(1) /* R */ +#define MSDC_PS_CDDEBOUNCE GENMASK(15, 12) /* RW */ +#define MSDC_PS_DAT GENMASK(23, 16) /* R */ +#define MSDC_PS_DATA1 BIT(17) /* R */ +#define MSDC_PS_CMD BIT(24) /* R */ +#define MSDC_PS_WP BIT(31) /* R */ /* MSDC_INT mask */ -#define MSDC_INT_MMCIRQ (0x1 << 0) /* W1C */ -#define MSDC_INT_CDSC (0x1 << 1) /* W1C */ -#define MSDC_INT_ACMDRDY (0x1 << 3) /* W1C */ -#define MSDC_INT_ACMDTMO (0x1 << 4) /* W1C */ -#define MSDC_INT_ACMDCRCERR (0x1 << 5) /* W1C */ -#define MSDC_INT_DMAQ_EMPTY (0x1 << 6) /* W1C */ -#define MSDC_INT_SDIOIRQ (0x1 << 7) /* W1C */ -#define MSDC_INT_CMDRDY (0x1 << 8) /* W1C */ -#define MSDC_INT_CMDTMO (0x1 << 9) /* W1C */ -#define MSDC_INT_RSPCRCERR (0x1 << 10) /* W1C */ -#define MSDC_INT_CSTA (0x1 << 11) /* R */ -#define MSDC_INT_XFER_COMPL (0x1 << 12) /* W1C */ -#define MSDC_INT_DXFER_DONE (0x1 << 13) /* W1C */ -#define MSDC_INT_DATTMO (0x1 << 14) /* W1C */ -#define MSDC_INT_DATCRCERR (0x1 << 15) /* W1C */ -#define MSDC_INT_ACMD19_DONE (0x1 << 16) /* W1C */ -#define MSDC_INT_DMA_BDCSERR (0x1 << 17) /* W1C */ -#define MSDC_INT_DMA_GPDCSERR (0x1 << 18) /* W1C */ -#define MSDC_INT_DMA_PROTECT (0x1 << 19) /* W1C */ -#define MSDC_INT_CMDQ (0x1 << 28) /* W1C */ +#define MSDC_INT_MMCIRQ BIT(0) /* W1C */ +#define MSDC_INT_CDSC BIT(1) /* W1C */ +#define MSDC_INT_ACMDRDY BIT(3) /* W1C */ +#define MSDC_INT_ACMDTMO BIT(4) /* W1C */ +#define MSDC_INT_ACMDCRCERR BIT(5) /* W1C */ +#define MSDC_INT_DMAQ_EMPTY BIT(6) /* W1C */ +#define MSDC_INT_SDIOIRQ BIT(7) /* W1C */ +#define MSDC_INT_CMDRDY BIT(8) /* W1C */ +#define MSDC_INT_CMDTMO BIT(9) /* W1C */ +#define MSDC_INT_RSPCRCERR BIT(10) /* W1C */ +#define MSDC_INT_CSTA BIT(11) /* R */ +#define MSDC_INT_XFER_COMPL BIT(12) /* W1C */ +#define MSDC_INT_DXFER_DONE BIT(13) /* W1C */ +#define MSDC_INT_DATTMO BIT(14) /* W1C */ +#define MSDC_INT_DATCRCERR BIT(15) /* W1C */ +#define MSDC_INT_ACMD19_DONE BIT(16) /* W1C */ +#define MSDC_INT_DMA_BDCSERR BIT(17) /* W1C */ +#define MSDC_INT_DMA_GPDCSERR BIT(18) /* W1C */ +#define MSDC_INT_DMA_PROTECT BIT(19) /* W1C */ +#define MSDC_INT_CMDQ BIT(28) /* W1C */ /* MSDC_INTEN mask */ -#define MSDC_INTEN_MMCIRQ (0x1 << 0) /* RW */ -#define MSDC_INTEN_CDSC (0x1 << 1) /* RW */ -#define MSDC_INTEN_ACMDRDY (0x1 << 3) /* RW */ -#define MSDC_INTEN_ACMDTMO (0x1 << 4) /* RW */ -#define MSDC_INTEN_ACMDCRCERR (0x1 << 5) /* RW */ -#define MSDC_INTEN_DMAQ_EMPTY (0x1 << 6) /* RW */ -#define MSDC_INTEN_SDIOIRQ (0x1 << 7) /* RW */ -#define MSDC_INTEN_CMDRDY (0x1 << 8) /* RW */ -#define MSDC_INTEN_CMDTMO (0x1 << 9) /* RW */ -#define MSDC_INTEN_RSPCRCERR (0x1 << 10) /* RW */ -#define MSDC_INTEN_CSTA (0x1 << 11) /* RW */ -#define MSDC_INTEN_XFER_COMPL (0x1 << 12) /* RW */ -#define MSDC_INTEN_DXFER_DONE (0x1 << 13) /* RW */ -#define MSDC_INTEN_DATTMO (0x1 << 14) /* RW */ -#define MSDC_INTEN_DATCRCERR (0x1 << 15) /* RW */ -#define MSDC_INTEN_ACMD19_DONE (0x1 << 16) /* RW */ -#define MSDC_INTEN_DMA_BDCSERR (0x1 << 17) /* RW */ -#define MSDC_INTEN_DMA_GPDCSERR (0x1 << 18) /* RW */ -#define MSDC_INTEN_DMA_PROTECT (0x1 << 19) /* RW */ +#define MSDC_INTEN_MMCIRQ BIT(0) /* RW */ +#define MSDC_INTEN_CDSC BIT(1) /* RW */ +#define MSDC_INTEN_ACMDRDY BIT(3) /* RW */ +#define MSDC_INTEN_ACMDTMO BIT(4) /* RW */ +#define MSDC_INTEN_ACMDCRCERR BIT(5) /* RW */ +#define MSDC_INTEN_DMAQ_EMPTY BIT(6) /* RW */ +#define MSDC_INTEN_SDIOIRQ BIT(7) /* RW */ +#define MSDC_INTEN_CMDRDY BIT(8) /* RW */ +#define MSDC_INTEN_CMDTMO BIT(9) /* RW */ +#define MSDC_INTEN_RSPCRCERR BIT(10) /* RW */ +#define MSDC_INTEN_CSTA BIT(11) /* RW */ +#define MSDC_INTEN_XFER_COMPL BIT(12) /* RW */ +#define MSDC_INTEN_DXFER_DONE BIT(13) /* RW */ +#define MSDC_INTEN_DATTMO BIT(14) /* RW */ +#define MSDC_INTEN_DATCRCERR BIT(15) /* RW */ +#define MSDC_INTEN_ACMD19_DONE BIT(16) /* RW */ +#define MSDC_INTEN_DMA_BDCSERR BIT(17) /* RW */ +#define MSDC_INTEN_DMA_GPDCSERR BIT(18) /* RW */ +#define MSDC_INTEN_DMA_PROTECT BIT(19) /* RW */ /* MSDC_FIFOCS mask */ -#define MSDC_FIFOCS_RXCNT (0xff << 0) /* R */ -#define MSDC_FIFOCS_TXCNT (0xff << 16) /* R */ -#define MSDC_FIFOCS_CLR (0x1 << 31) /* RW */ +#define MSDC_FIFOCS_RXCNT GENMASK(7, 0) /* R */ +#define MSDC_FIFOCS_TXCNT GENMASK(23, 16) /* R */ +#define MSDC_FIFOCS_CLR BIT(31) /* RW */ /* SDC_CFG mask */ -#define SDC_CFG_SDIOINTWKUP (0x1 << 0) /* RW */ -#define SDC_CFG_INSWKUP (0x1 << 1) /* RW */ -#define SDC_CFG_WRDTOC (0x1fff << 2) /* RW */ -#define SDC_CFG_BUSWIDTH (0x3 << 16) /* RW */ -#define SDC_CFG_SDIO (0x1 << 19) /* RW */ -#define SDC_CFG_SDIOIDE (0x1 << 20) /* RW */ -#define SDC_CFG_INTATGAP (0x1 << 21) /* RW */ -#define SDC_CFG_DTOC (0xff << 24) /* RW */ +#define SDC_CFG_SDIOINTWKUP BIT(0) /* RW */ +#define SDC_CFG_INSWKUP BIT(1) /* RW */ +#define SDC_CFG_WRDTOC GENMASK(14, 2) /* RW */ +#define SDC_CFG_BUSWIDTH GENMASK(17, 16) /* RW */ +#define SDC_CFG_SDIO BIT(19) /* RW */ +#define SDC_CFG_SDIOIDE BIT(20) /* RW */ +#define SDC_CFG_INTATGAP BIT(21) /* RW */ +#define SDC_CFG_DTOC GENMASK(31, 24) /* RW */ /* SDC_STS mask */ -#define SDC_STS_SDCBUSY (0x1 << 0) /* RW */ -#define SDC_STS_CMDBUSY (0x1 << 1) /* RW */ -#define SDC_STS_SWR_COMPL (0x1 << 31) /* RW */ +#define SDC_STS_SDCBUSY BIT(0) /* RW */ +#define SDC_STS_CMDBUSY BIT(1) /* RW */ +#define SDC_STS_SWR_COMPL BIT(31) /* RW */ -#define SDC_DAT1_IRQ_TRIGGER (0x1 << 19) /* RW */ +#define SDC_DAT1_IRQ_TRIGGER BIT(19) /* RW */ /* SDC_ADV_CFG0 mask */ -#define SDC_RX_ENHANCE_EN (0x1 << 20) /* RW */ +#define SDC_RX_ENHANCE_EN BIT(20) /* RW */ /* DMA_SA_H4BIT mask */ -#define DMA_ADDR_HIGH_4BIT (0xf << 0) /* RW */ +#define DMA_ADDR_HIGH_4BIT GENMASK(3, 0) /* RW */ /* MSDC_DMA_CTRL mask */ -#define MSDC_DMA_CTRL_START (0x1 << 0) /* W */ -#define MSDC_DMA_CTRL_STOP (0x1 << 1) /* W */ -#define MSDC_DMA_CTRL_RESUME (0x1 << 2) /* W */ -#define MSDC_DMA_CTRL_MODE (0x1 << 8) /* RW */ -#define MSDC_DMA_CTRL_LASTBUF (0x1 << 10) /* RW */ -#define MSDC_DMA_CTRL_BRUSTSZ (0x7 << 12) /* RW */ +#define MSDC_DMA_CTRL_START BIT(0) /* W */ +#define MSDC_DMA_CTRL_STOP BIT(1) /* W */ +#define MSDC_DMA_CTRL_RESUME BIT(2) /* W */ +#define MSDC_DMA_CTRL_MODE BIT(8) /* RW */ +#define MSDC_DMA_CTRL_LASTBUF BIT(10) /* RW */ +#define MSDC_DMA_CTRL_BRUSTSZ GENMASK(14, 12) /* RW */ /* MSDC_DMA_CFG mask */ -#define MSDC_DMA_CFG_STS (0x1 << 0) /* R */ -#define MSDC_DMA_CFG_DECSEN (0x1 << 1) /* RW */ -#define MSDC_DMA_CFG_AHBHPROT2 (0x2 << 8) /* RW */ -#define MSDC_DMA_CFG_ACTIVEEN (0x2 << 12) /* RW */ -#define MSDC_DMA_CFG_CS12B16B (0x1 << 16) /* RW */ +#define MSDC_DMA_CFG_STS BIT(0) /* R */ +#define MSDC_DMA_CFG_DECSEN BIT(1) /* RW */ +#define MSDC_DMA_CFG_AHBHPROT2 BIT(9) /* RW */ +#define MSDC_DMA_CFG_ACTIVEEN BIT(13) /* RW */ +#define MSDC_DMA_CFG_CS12B16B BIT(16) /* RW */ /* MSDC_PATCH_BIT mask */ -#define MSDC_PATCH_BIT_ODDSUPP (0x1 << 1) /* RW */ -#define MSDC_INT_DAT_LATCH_CK_SEL (0x7 << 7) -#define MSDC_CKGEN_MSDC_DLY_SEL (0x1f << 10) -#define MSDC_PATCH_BIT_IODSSEL (0x1 << 16) /* RW */ -#define MSDC_PATCH_BIT_IOINTSEL (0x1 << 17) /* RW */ -#define MSDC_PATCH_BIT_BUSYDLY (0xf << 18) /* RW */ -#define MSDC_PATCH_BIT_WDOD (0xf << 22) /* RW */ -#define MSDC_PATCH_BIT_IDRTSEL (0x1 << 26) /* RW */ -#define MSDC_PATCH_BIT_CMDFSEL (0x1 << 27) /* RW */ -#define MSDC_PATCH_BIT_INTDLSEL (0x1 << 28) /* RW */ -#define MSDC_PATCH_BIT_SPCPUSH (0x1 << 29) /* RW */ -#define MSDC_PATCH_BIT_DECRCTMO (0x1 << 30) /* RW */ - -#define MSDC_PATCH_BIT1_CMDTA (0x7 << 3) /* RW */ -#define MSDC_PB1_BUSY_CHECK_SEL (0x1 << 7) /* RW */ -#define MSDC_PATCH_BIT1_STOP_DLY (0xf << 8) /* RW */ - -#define MSDC_PATCH_BIT2_CFGRESP (0x1 << 15) /* RW */ -#define MSDC_PATCH_BIT2_CFGCRCSTS (0x1 << 28) /* RW */ -#define MSDC_PB2_SUPPORT_64G (0x1 << 1) /* RW */ -#define MSDC_PB2_RESPWAIT (0x3 << 2) /* RW */ -#define MSDC_PB2_RESPSTSENSEL (0x7 << 16) /* RW */ -#define MSDC_PB2_CRCSTSENSEL (0x7 << 29) /* RW */ - -#define MSDC_PAD_TUNE_DATWRDLY (0x1f << 0) /* RW */ -#define MSDC_PAD_TUNE_DATRRDLY (0x1f << 8) /* RW */ -#define MSDC_PAD_TUNE_CMDRDLY (0x1f << 16) /* RW */ -#define MSDC_PAD_TUNE_CMDRRDLY (0x1f << 22) /* RW */ -#define MSDC_PAD_TUNE_CLKTDLY (0x1f << 27) /* RW */ -#define MSDC_PAD_TUNE_RXDLYSEL (0x1 << 15) /* RW */ -#define MSDC_PAD_TUNE_RD_SEL (0x1 << 13) /* RW */ -#define MSDC_PAD_TUNE_CMD_SEL (0x1 << 21) /* RW */ - -#define PAD_DS_TUNE_DLY_SEL (0x1 << 0) /* RW */ -#define PAD_DS_TUNE_DLY1 (0x1f << 2) /* RW */ -#define PAD_DS_TUNE_DLY2 (0x1f << 7) /* RW */ -#define PAD_DS_TUNE_DLY3 (0x1f << 12) /* RW */ - -#define PAD_CMD_TUNE_RX_DLY3 (0x1f << 1) /* RW */ +#define MSDC_PATCH_BIT_ODDSUPP BIT(1) /* RW */ +#define MSDC_INT_DAT_LATCH_CK_SEL GENMASK(9, 7) +#define MSDC_CKGEN_MSDC_DLY_SEL GENMASK(14, 10) +#define MSDC_PATCH_BIT_IODSSEL BIT(16) /* RW */ +#define MSDC_PATCH_BIT_IOINTSEL BIT(17) /* RW */ +#define MSDC_PATCH_BIT_BUSYDLY GENMASK(21, 18) /* RW */ +#define MSDC_PATCH_BIT_WDOD GENMASK(25, 22) /* RW */ +#define MSDC_PATCH_BIT_IDRTSEL BIT(26) /* RW */ +#define MSDC_PATCH_BIT_CMDFSEL BIT(27) /* RW */ +#define MSDC_PATCH_BIT_INTDLSEL BIT(28) /* RW */ +#define MSDC_PATCH_BIT_SPCPUSH BIT(29) /* RW */ +#define MSDC_PATCH_BIT_DECRCTMO BIT(30) /* RW */ + +#define MSDC_PATCH_BIT1_CMDTA GENMASK(5, 3) /* RW */ +#define MSDC_PB1_BUSY_CHECK_SEL BIT(7) /* RW */ +#define MSDC_PATCH_BIT1_STOP_DLY GENMASK(11, 8) /* RW */ + +#define MSDC_PATCH_BIT2_CFGRESP BIT(15) /* RW */ +#define MSDC_PATCH_BIT2_CFGCRCSTS BIT(28) /* RW */ +#define MSDC_PB2_SUPPORT_64G BIT(1) /* RW */ +#define MSDC_PB2_RESPWAIT GENMASK(3, 2) /* RW */ +#define MSDC_PB2_RESPSTSENSEL GENMASK(18, 16) /* RW */ +#define MSDC_PB2_CRCSTSENSEL GENMASK(31, 29) /* RW */ + +#define MSDC_PAD_TUNE_DATWRDLY GENMASK(4, 0) /* RW */ +#define MSDC_PAD_TUNE_DATRRDLY GENMASK(12, 8) /* RW */ +#define MSDC_PAD_TUNE_CMDRDLY GENMASK(20, 16) /* RW */ +#define MSDC_PAD_TUNE_CMDRRDLY GENMASK(26, 22) /* RW */ +#define MSDC_PAD_TUNE_CLKTDLY GENMASK(31, 27) /* RW */ +#define MSDC_PAD_TUNE_RXDLYSEL BIT(15) /* RW */ +#define MSDC_PAD_TUNE_RD_SEL BIT(13) /* RW */ +#define MSDC_PAD_TUNE_CMD_SEL BIT(21) /* RW */ + +#define PAD_DS_TUNE_DLY_SEL BIT(0) /* RW */ +#define PAD_DS_TUNE_DLY1 GENMASK(6, 2) /* RW */ +#define PAD_DS_TUNE_DLY2 GENMASK(11, 7) /* RW */ +#define PAD_DS_TUNE_DLY3 GENMASK(16, 12) /* RW */ + +#define PAD_CMD_TUNE_RX_DLY3 GENMASK(5, 1) /* RW */ /* EMMC51_CFG0 mask */ -#define CMDQ_RDAT_CNT (0x3ff << 12) /* RW */ +#define CMDQ_RDAT_CNT GENMASK(21, 12) /* RW */ -#define EMMC50_CFG_PADCMD_LATCHCK (0x1 << 0) /* RW */ -#define EMMC50_CFG_CRCSTS_EDGE (0x1 << 3) /* RW */ -#define EMMC50_CFG_CFCSTS_SEL (0x1 << 4) /* RW */ -#define EMMC50_CFG_CMD_RESP_SEL (0x1 << 9) /* RW */ +#define EMMC50_CFG_PADCMD_LATCHCK BIT(0) /* RW */ +#define EMMC50_CFG_CRCSTS_EDGE BIT(3) /* RW */ +#define EMMC50_CFG_CFCSTS_SEL BIT(4) /* RW */ +#define EMMC50_CFG_CMD_RESP_SEL BIT(9) /* RW */ /* EMMC50_CFG1 mask */ -#define EMMC50_CFG1_DS_CFG (0x1 << 28) /* RW */ +#define EMMC50_CFG1_DS_CFG BIT(28) /* RW */ -#define EMMC50_CFG3_OUTS_WR (0x1f << 0) /* RW */ +#define EMMC50_CFG3_OUTS_WR GENMASK(4, 0) /* RW */ -#define SDC_FIFO_CFG_WRVALIDSEL (0x1 << 24) /* RW */ -#define SDC_FIFO_CFG_RDVALIDSEL (0x1 << 25) /* RW */ +#define SDC_FIFO_CFG_WRVALIDSEL BIT(24) /* RW */ +#define SDC_FIFO_CFG_RDVALIDSEL BIT(25) /* RW */ /* CQHCI_SETTING */ -#define CQHCI_RD_CMD_WND_SEL (0x1 << 14) /* RW */ -#define CQHCI_WR_CMD_WND_SEL (0x1 << 15) /* RW */ +#define CQHCI_RD_CMD_WND_SEL BIT(14) /* RW */ +#define CQHCI_WR_CMD_WND_SEL BIT(15) /* RW */ /* EMMC_TOP_CONTROL mask */ -#define PAD_RXDLY_SEL (0x1 << 0) /* RW */ -#define DELAY_EN (0x1 << 1) /* RW */ -#define PAD_DAT_RD_RXDLY2 (0x1f << 2) /* RW */ -#define PAD_DAT_RD_RXDLY (0x1f << 7) /* RW */ -#define PAD_DAT_RD_RXDLY2_SEL (0x1 << 12) /* RW */ -#define PAD_DAT_RD_RXDLY_SEL (0x1 << 13) /* RW */ -#define DATA_K_VALUE_SEL (0x1 << 14) /* RW */ -#define SDC_RX_ENH_EN (0x1 << 15) /* TW */ +#define PAD_RXDLY_SEL BIT(0) /* RW */ +#define DELAY_EN BIT(1) /* RW */ +#define PAD_DAT_RD_RXDLY2 GENMASK(6, 2) /* RW */ +#define PAD_DAT_RD_RXDLY GENMASK(11, 7) /* RW */ +#define PAD_DAT_RD_RXDLY2_SEL BIT(12) /* RW */ +#define PAD_DAT_RD_RXDLY_SEL BIT(13) /* RW */ +#define DATA_K_VALUE_SEL BIT(14) /* RW */ +#define SDC_RX_ENH_EN BIT(15) /* TW */ /* EMMC_TOP_CMD mask */ -#define PAD_CMD_RXDLY2 (0x1f << 0) /* RW */ -#define PAD_CMD_RXDLY (0x1f << 5) /* RW */ -#define PAD_CMD_RD_RXDLY2_SEL (0x1 << 10) /* RW */ -#define PAD_CMD_RD_RXDLY_SEL (0x1 << 11) /* RW */ -#define PAD_CMD_TX_DLY (0x1f << 12) /* RW */ +#define PAD_CMD_RXDLY2 GENMASK(4, 0) /* RW */ +#define PAD_CMD_RXDLY GENMASK(9, 5) /* RW */ +#define PAD_CMD_RD_RXDLY2_SEL BIT(10) /* RW */ +#define PAD_CMD_RD_RXDLY_SEL BIT(11) /* RW */ +#define PAD_CMD_TX_DLY GENMASK(16, 12) /* RW */ /* EMMC50_PAD_DS_TUNE mask */ -#define PAD_DS_DLY_SEL (0x1 << 16) /* RW */ -#define PAD_DS_DLY1 (0x1f << 10) /* RW */ -#define PAD_DS_DLY3 (0x1f << 0) /* RW */ +#define PAD_DS_DLY_SEL BIT(16) /* RW */ +#define PAD_DS_DLY1 GENMASK(14, 10) /* RW */ +#define PAD_DS_DLY3 GENMASK(4, 0) /* RW */ -#define REQ_CMD_EIO (0x1 << 0) -#define REQ_CMD_TMO (0x1 << 1) -#define REQ_DAT_ERR (0x1 << 2) -#define REQ_STOP_EIO (0x1 << 3) -#define REQ_STOP_TMO (0x1 << 4) -#define REQ_CMD_BUSY (0x1 << 5) +#define REQ_CMD_EIO BIT(0) +#define REQ_CMD_TMO BIT(1) +#define REQ_DAT_ERR BIT(2) +#define REQ_STOP_EIO BIT(3) +#define REQ_STOP_TMO BIT(4) +#define REQ_CMD_BUSY BIT(5) -#define MSDC_PREPARE_FLAG (0x1 << 0) -#define MSDC_ASYNC_FLAG (0x1 << 1) -#define MSDC_MMAP_FLAG (0x1 << 2) +#define MSDC_PREPARE_FLAG BIT(0) +#define MSDC_ASYNC_FLAG BIT(1) +#define MSDC_MMAP_FLAG BIT(2) #define MTK_MMC_AUTOSUSPEND_DELAY 50 #define CMD_TIMEOUT (HZ/10 * 5) /* 100ms x5 */ @@ -331,17 +332,17 @@ /*--------------------------------------------------------------------------*/ struct mt_gpdma_desc { u32 gpd_info; -#define GPDMA_DESC_HWO (0x1 << 0) -#define GPDMA_DESC_BDP (0x1 << 1) -#define GPDMA_DESC_CHECKSUM (0xff << 8) /* bit8 ~ bit15 */ -#define GPDMA_DESC_INT (0x1 << 16) -#define GPDMA_DESC_NEXT_H4 (0xf << 24) -#define GPDMA_DESC_PTR_H4 (0xf << 28) +#define GPDMA_DESC_HWO BIT(0) +#define GPDMA_DESC_BDP BIT(1) +#define GPDMA_DESC_CHECKSUM GENMASK(15, 8) +#define GPDMA_DESC_INT BIT(16) +#define GPDMA_DESC_NEXT_H4 GENMASK(27, 24) +#define GPDMA_DESC_PTR_H4 GENMASK(31, 28) u32 next; u32 ptr; u32 gpd_data_len; -#define GPDMA_DESC_BUFLEN (0xffff) /* bit0 ~ bit15 */ -#define GPDMA_DESC_EXTLEN (0xff << 16) /* bit16 ~ bit23 */ +#define GPDMA_DESC_BUFLEN GENMASK(15, 0) +#define GPDMA_DESC_EXTLEN GENMASK(23, 16) u32 arg; u32 blknum; u32 cmd; @@ -349,17 +350,17 @@ struct mt_gpdma_desc { struct mt_bdma_desc { u32 bd_info; -#define BDMA_DESC_EOL (0x1 << 0) -#define BDMA_DESC_CHECKSUM (0xff << 8) /* bit8 ~ bit15 */ -#define BDMA_DESC_BLKPAD (0x1 << 17) -#define BDMA_DESC_DWPAD (0x1 << 18) -#define BDMA_DESC_NEXT_H4 (0xf << 24) -#define BDMA_DESC_PTR_H4 (0xf << 28) +#define BDMA_DESC_EOL BIT(0) +#define BDMA_DESC_CHECKSUM GENMASK(15, 8) +#define BDMA_DESC_BLKPAD BIT(17) +#define BDMA_DESC_DWPAD BIT(18) +#define BDMA_DESC_NEXT_H4 GENMASK(27, 24) +#define BDMA_DESC_PTR_H4 GENMASK(31, 28) u32 next; u32 ptr; u32 bd_data_len; -#define BDMA_DESC_BUFLEN (0xffff) /* bit0 ~ bit15 */ -#define BDMA_DESC_BUFLEN_EXT (0xffffff) /* bit0 ~ bit23 */ +#define BDMA_DESC_BUFLEN GENMASK(15, 0) +#define BDMA_DESC_BUFLEN_EXT GENMASK(23, 0) }; struct msdc_dma { @@ -636,12 +637,11 @@ static void msdc_reset_hw(struct msdc_host *host) u32 val; sdr_set_bits(host->base + MSDC_CFG, MSDC_CFG_RST); - while (readl(host->base + MSDC_CFG) & MSDC_CFG_RST) - cpu_relax(); + readl_poll_timeout(host->base + MSDC_CFG, val, !(val & MSDC_CFG_RST), 0, 0); sdr_set_bits(host->base + MSDC_FIFOCS, MSDC_FIFOCS_CLR); - while (readl(host->base + MSDC_FIFOCS) & MSDC_FIFOCS_CLR) - cpu_relax(); + readl_poll_timeout(host->base + MSDC_FIFOCS, val, + !(val & MSDC_FIFOCS_CLR), 0, 0); val = readl(host->base + MSDC_INT); writel(val, host->base + MSDC_INT); @@ -725,7 +725,7 @@ static inline void msdc_dma_setup(struct msdc_host *host, struct msdc_dma *dma, sdr_set_field(host->base + MSDC_DMA_CFG, MSDC_DMA_CFG_DECSEN, 1); dma_ctrl = readl_relaxed(host->base + MSDC_DMA_CTRL); dma_ctrl &= ~(MSDC_DMA_CTRL_BRUSTSZ | MSDC_DMA_CTRL_MODE); - dma_ctrl |= (MSDC_BURST_64B << 12 | 1 << 8); + dma_ctrl |= (MSDC_BURST_64B << 12 | BIT(8)); writel_relaxed(dma_ctrl, host->base + MSDC_DMA_CTRL); if (host->dev_comp->support_64g) sdr_set_field(host->base + DMA_SA_H4BIT, DMA_ADDR_HIGH_4BIT, @@ -769,7 +769,7 @@ static u64 msdc_timeout_cal(struct msdc_host *host, u64 ns, u64 clks) do_div(timeout, clk_ns); timeout += clks; /* in 1048576 sclk cycle unit */ - timeout = DIV_ROUND_UP(timeout, (0x1 << 20)); + timeout = DIV_ROUND_UP(timeout, BIT(20)); if (host->dev_comp->clk_div_bits == 8) sdr_get_field(host->base + MSDC_CFG, MSDC_CFG_CKMOD, &mode); @@ -814,8 +814,9 @@ static void msdc_gate_clock(struct msdc_host *host) clk_disable_unprepare(host->h_clk); } -static void msdc_ungate_clock(struct msdc_host *host) +static int msdc_ungate_clock(struct msdc_host *host) { + u32 val; int ret; clk_prepare_enable(host->h_clk); @@ -825,11 +826,11 @@ static void msdc_ungate_clock(struct msdc_host *host) ret = clk_bulk_prepare_enable(MSDC_NR_CLOCKS, host->bulk_clks); if (ret) { dev_err(host->dev, "Cannot enable pclk/axi/ahb clock gates\n"); - return; + return ret; } - while (!(readl(host->base + MSDC_CFG) & MSDC_CFG_CKSTB)) - cpu_relax(); + return readl_poll_timeout(host->base + MSDC_CFG, val, + (val & MSDC_CFG_CKSTB), 1, 20000); } static void msdc_set_mclk(struct msdc_host *host, unsigned char timing, u32 hz) @@ -840,6 +841,7 @@ static void msdc_set_mclk(struct msdc_host *host, unsigned char timing, u32 hz) u32 div; u32 sclk; u32 tune_reg = host->dev_comp->pad_tune_reg; + u32 val; if (!hz) { dev_dbg(host->dev, "set mclk to 0\n"); @@ -899,14 +901,8 @@ static void msdc_set_mclk(struct msdc_host *host, unsigned char timing, u32 hz) } } sdr_clr_bits(host->base + MSDC_CFG, MSDC_CFG_CKPDN); - /* - * As src_clk/HCLK use the same bit to gate/ungate, - * So if want to only gate src_clk, need gate its parent(mux). - */ - if (host->src_clk_cg) - clk_disable_unprepare(host->src_clk_cg); - else - clk_disable_unprepare(clk_get_parent(host->src_clk)); + + clk_disable_unprepare(host->src_clk_cg); if (host->dev_comp->clk_div_bits == 8) sdr_set_field(host->base + MSDC_CFG, MSDC_CFG_CKMOD | MSDC_CFG_CKDIV, @@ -915,13 +911,9 @@ static void msdc_set_mclk(struct msdc_host *host, unsigned char timing, u32 hz) sdr_set_field(host->base + MSDC_CFG, MSDC_CFG_CKMOD_EXTRA | MSDC_CFG_CKDIV_EXTRA, (mode << 12) | div); - if (host->src_clk_cg) - clk_prepare_enable(host->src_clk_cg); - else - clk_prepare_enable(clk_get_parent(host->src_clk)); - while (!(readl(host->base + MSDC_CFG) & MSDC_CFG_CKSTB)) - cpu_relax(); + clk_prepare_enable(host->src_clk_cg); + readl_poll_timeout(host->base + MSDC_CFG, val, (val & MSDC_CFG_CKSTB), 0, 0); sdr_set_bits(host->base + MSDC_CFG, MSDC_CFG_CKPDN); mmc->actual_clock = sclk; host->mclk = hz; @@ -1013,15 +1005,15 @@ static inline u32 msdc_cmd_prepare_raw_cmd(struct msdc_host *host, if ((opcode == SD_IO_RW_DIRECT && cmd->flags == (unsigned int) -1) || opcode == MMC_STOP_TRANSMISSION) - rawcmd |= (0x1 << 14); + rawcmd |= BIT(14); else if (opcode == SD_SWITCH_VOLTAGE) - rawcmd |= (0x1 << 30); + rawcmd |= BIT(30); else if (opcode == SD_APP_SEND_SCR || opcode == SD_APP_SEND_NUM_WR_BLKS || (opcode == SD_SWITCH && mmc_cmd_type(cmd) == MMC_CMD_ADTC) || (opcode == SD_APP_SD_STATUS && mmc_cmd_type(cmd) == MMC_CMD_ADTC) || (opcode == MMC_SEND_EXT_CSD && mmc_cmd_type(cmd) == MMC_CMD_ADTC)) - rawcmd |= (0x1 << 11); + rawcmd |= BIT(11); if (cmd->data) { struct mmc_data *data = cmd->data; @@ -1029,16 +1021,16 @@ static inline u32 msdc_cmd_prepare_raw_cmd(struct msdc_host *host, if (mmc_op_multi(opcode)) { if (mmc_card_mmc(mmc->card) && mrq->sbc && !(mrq->sbc->arg & 0xFFFF0000)) - rawcmd |= 0x2 << 28; /* AutoCMD23 */ + rawcmd |= BIT(29); /* AutoCMD23 */ } rawcmd |= ((data->blksz & 0xFFF) << 16); if (data->flags & MMC_DATA_WRITE) - rawcmd |= (0x1 << 13); + rawcmd |= BIT(13); if (data->blocks > 1) - rawcmd |= (0x2 << 11); + rawcmd |= BIT(12); else - rawcmd |= (0x1 << 11); + rawcmd |= BIT(11); /* Always use dma mode */ sdr_clr_bits(host->base + MSDC_CFG, MSDC_CFG_PIO); @@ -1231,13 +1223,13 @@ static bool msdc_cmd_done(struct msdc_host *host, int events, static inline bool msdc_cmd_is_ready(struct msdc_host *host, struct mmc_request *mrq, struct mmc_command *cmd) { - /* The max busy time we can endure is 20ms */ - unsigned long tmo = jiffies + msecs_to_jiffies(20); + u32 val; + int ret; - while ((readl(host->base + SDC_STS) & SDC_STS_CMDBUSY) && - time_before(jiffies, tmo)) - cpu_relax(); - if (readl(host->base + SDC_STS) & SDC_STS_CMDBUSY) { + /* The max busy time we can endure is 20ms */ + ret = readl_poll_timeout_atomic(host->base + SDC_STS, val, + !(val & SDC_STS_CMDBUSY), 1, 20000); + if (ret) { dev_err(host->dev, "CMD bus busy detected\n"); host->error |= REQ_CMD_BUSY; msdc_cmd_done(host, MSDC_INT_CMDTMO, mrq, cmd); @@ -1245,12 +1237,10 @@ static inline bool msdc_cmd_is_ready(struct msdc_host *host, } if (mmc_resp_type(cmd) == MMC_RSP_R1B || cmd->data) { - tmo = jiffies + msecs_to_jiffies(20); /* R1B or with data, should check SDCBUSY */ - while ((readl(host->base + SDC_STS) & SDC_STS_SDCBUSY) && - time_before(jiffies, tmo)) - cpu_relax(); - if (readl(host->base + SDC_STS) & SDC_STS_SDCBUSY) { + ret = readl_poll_timeout_atomic(host->base + SDC_STS, val, + !(val & SDC_STS_SDCBUSY), 1, 20000); + if (ret) { dev_err(host->dev, "Controller busy detected\n"); host->error |= REQ_CMD_BUSY; msdc_cmd_done(host, MSDC_INT_CMDTMO, mrq, cmd); @@ -1376,6 +1366,8 @@ static bool msdc_data_xfer_done(struct msdc_host *host, u32 events, (MSDC_INT_XFER_COMPL | MSDC_INT_DATCRCERR | MSDC_INT_DATTMO | MSDC_INT_DMA_BDCSERR | MSDC_INT_DMA_GPDCSERR | MSDC_INT_DMA_PROTECT); + u32 val; + int ret; spin_lock_irqsave(&host->lock, flags); done = !host->data; @@ -1392,8 +1384,14 @@ static bool msdc_data_xfer_done(struct msdc_host *host, u32 events, readl(host->base + MSDC_DMA_CFG)); sdr_set_field(host->base + MSDC_DMA_CTRL, MSDC_DMA_CTRL_STOP, 1); - while (readl(host->base + MSDC_DMA_CFG) & MSDC_DMA_CFG_STS) - cpu_relax(); + + ret = readl_poll_timeout_atomic(host->base + MSDC_DMA_CFG, val, + !(val & MSDC_DMA_CFG_STS), 1, 20000); + if (ret) { + dev_dbg(host->dev, "DMA stop timed out\n"); + return false; + } + sdr_clr_bits(host->base + MSDC_INTEN, data_ints_mask); dev_dbg(host->dev, "DMA stop\n"); @@ -1631,6 +1629,7 @@ static void msdc_init_hw(struct msdc_host *host) { u32 val; u32 tune_reg = host->dev_comp->pad_tune_reg; + struct mmc_host *mmc = mmc_from_priv(host); if (host->reset) { reset_control_assert(host->reset); @@ -1685,7 +1684,7 @@ static void msdc_init_hw(struct msdc_host *host) } if (host->dev_comp->busy_check) - sdr_clr_bits(host->base + MSDC_PATCH_BIT1, (1 << 7)); + sdr_clr_bits(host->base + MSDC_PATCH_BIT1, BIT(7)); if (host->dev_comp->async_fifo) { sdr_set_field(host->base + MSDC_PATCH_BIT2, @@ -1736,14 +1735,18 @@ static void msdc_init_hw(struct msdc_host *host) MSDC_PAD_TUNE_RXDLYSEL); } - /* Configure to enable SDIO mode. - * it's must otherwise sdio cmd5 failed - */ - sdr_set_bits(host->base + SDC_CFG, SDC_CFG_SDIO); + if (mmc->caps2 & MMC_CAP2_NO_SDIO) { + sdr_clr_bits(host->base + SDC_CFG, SDC_CFG_SDIO); + sdr_clr_bits(host->base + MSDC_INTEN, MSDC_INTEN_SDIOIRQ); + sdr_clr_bits(host->base + SDC_ADV_CFG0, SDC_DAT1_IRQ_TRIGGER); + } else { + /* Configure to enable SDIO mode, otherwise SDIO CMD5 fails */ + sdr_set_bits(host->base + SDC_CFG, SDC_CFG_SDIO); - /* Config SDIO device detect interrupt function */ - sdr_clr_bits(host->base + SDC_CFG, SDC_CFG_SDIOIDE); - sdr_set_bits(host->base + SDC_ADV_CFG0, SDC_DAT1_IRQ_TRIGGER); + /* Config SDIO device detect interrupt function */ + sdr_clr_bits(host->base + SDC_CFG, SDC_CFG_SDIOIDE); + sdr_set_bits(host->base + SDC_ADV_CFG0, SDC_DAT1_IRQ_TRIGGER); + } /* Configure to default data timeout */ sdr_set_field(host->base + SDC_CFG, SDC_CFG_DTOC, 3); @@ -1865,7 +1868,7 @@ static void msdc_ops_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) static u32 test_delay_bit(u32 delay, u32 bit) { bit %= PAD_DELAY_MAX; - return delay & (1 << bit); + return delay & BIT(bit); } static int get_delay_len(u32 delay, u32 start_bit) @@ -1970,9 +1973,9 @@ static int msdc_tune_response(struct mmc_host *mmc, u32 opcode) for (j = 0; j < 3; j++) { mmc_send_tuning(mmc, opcode, &cmd_err); if (!cmd_err) { - rise_delay |= (1 << i); + rise_delay |= BIT(i); } else { - rise_delay &= ~(1 << i); + rise_delay &= ~BIT(i); break; } } @@ -1994,9 +1997,9 @@ static int msdc_tune_response(struct mmc_host *mmc, u32 opcode) for (j = 0; j < 3; j++) { mmc_send_tuning(mmc, opcode, &cmd_err); if (!cmd_err) { - fall_delay |= (1 << i); + fall_delay |= BIT(i); } else { - fall_delay &= ~(1 << i); + fall_delay &= ~BIT(i); break; } } @@ -2024,7 +2027,7 @@ skip_fall: MSDC_PAD_TUNE_CMDRRDLY, i); mmc_send_tuning(mmc, opcode, &cmd_err); if (!cmd_err) - internal_delay |= (1 << i); + internal_delay |= BIT(i); } dev_dbg(host->dev, "Final internal delay: 0x%x\n", internal_delay); internal_delay_phase = get_best_delay(host, internal_delay); @@ -2069,9 +2072,9 @@ static int hs400_tune_response(struct mmc_host *mmc, u32 opcode) for (j = 0; j < 3; j++) { mmc_send_tuning(mmc, opcode, &cmd_err); if (!cmd_err) { - cmd_delay |= (1 << i); + cmd_delay |= BIT(i); } else { - cmd_delay &= ~(1 << i); + cmd_delay &= ~BIT(i); break; } } @@ -2101,7 +2104,7 @@ static int msdc_tune_data(struct mmc_host *mmc, u32 opcode) msdc_set_data_delay(host, i); ret = mmc_send_tuning(mmc, opcode, NULL); if (!ret) - rise_delay |= (1 << i); + rise_delay |= BIT(i); } final_rise_delay = get_best_delay(host, rise_delay); /* if rising edge has enough margin, then do not scan falling edge */ @@ -2115,7 +2118,7 @@ static int msdc_tune_data(struct mmc_host *mmc, u32 opcode) msdc_set_data_delay(host, i); ret = mmc_send_tuning(mmc, opcode, NULL); if (!ret) - fall_delay |= (1 << i); + fall_delay |= BIT(i); } final_fall_delay = get_best_delay(host, fall_delay); @@ -2159,7 +2162,7 @@ static int msdc_tune_together(struct mmc_host *mmc, u32 opcode) msdc_set_data_delay(host, i); ret = mmc_send_tuning(mmc, opcode, NULL); if (!ret) - rise_delay |= (1 << i); + rise_delay |= BIT(i); } final_rise_delay = get_best_delay(host, rise_delay); /* if rising edge has enough margin, then do not scan falling edge */ @@ -2175,7 +2178,7 @@ static int msdc_tune_together(struct mmc_host *mmc, u32 opcode) msdc_set_data_delay(host, i); ret = mmc_send_tuning(mmc, opcode, NULL); if (!ret) - fall_delay |= (1 << i); + fall_delay |= BIT(i); } final_fall_delay = get_best_delay(host, fall_delay); @@ -2292,7 +2295,7 @@ static int msdc_execute_hs400_tuning(struct mmc_host *mmc, struct mmc_card *card PAD_DS_TUNE_DLY1, i); ret = mmc_get_ext_csd(card, &ext_csd); if (!ret) { - result_dly1 |= (1 << i); + result_dly1 |= BIT(i); kfree(ext_csd); } } @@ -2516,7 +2519,20 @@ static int msdc_of_clock_parse(struct platform_device *pdev, /*source clock control gate is optional clock*/ host->src_clk_cg = devm_clk_get_optional(&pdev->dev, "source_cg"); if (IS_ERR(host->src_clk_cg)) - host->src_clk_cg = NULL; + return PTR_ERR(host->src_clk_cg); + + /* + * Fallback for legacy device-trees: src_clk and HCLK use the same + * bit to control gating but they are parented to a different mux, + * hence if our intention is to gate only the source, required + * during a clk mode switch to avoid hw hangs, we need to gate + * its parent (specified as a different clock only on new DTs). + */ + if (!host->src_clk_cg) { + host->src_clk_cg = clk_get_parent(host->src_clk); + if (IS_ERR(host->src_clk_cg)) + return PTR_ERR(host->src_clk_cg); + } host->sys_clk_cg = devm_clk_get_optional(&pdev->dev, "sys_cg"); if (IS_ERR(host->sys_clk_cg)) @@ -2674,7 +2690,11 @@ static int msdc_drv_probe(struct platform_device *pdev) spin_lock_init(&host->lock); platform_set_drvdata(pdev, mmc); - msdc_ungate_clock(host); + ret = msdc_ungate_clock(host); + if (ret) { + dev_err(&pdev->dev, "Cannot ungate clocks!\n"); + goto release_mem; + } msdc_init_hw(host); if (mmc->caps2 & MMC_CAP2_CQE) { @@ -2833,8 +2853,12 @@ static int __maybe_unused msdc_runtime_resume(struct device *dev) { struct mmc_host *mmc = dev_get_drvdata(dev); struct msdc_host *host = mmc_priv(mmc); + int ret; + + ret = msdc_ungate_clock(host); + if (ret) + return ret; - msdc_ungate_clock(host); msdc_restore_reg(host); return 0; } diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c index 2fe6fcdbb1b3..40b6878bea6c 100644 --- a/drivers/mmc/host/mxcmmc.c +++ b/drivers/mmc/host/mxcmmc.c @@ -1183,7 +1183,6 @@ static int mxcmci_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM_SLEEP static int mxcmci_suspend(struct device *dev) { struct mmc_host *mmc = dev_get_drvdata(dev); @@ -1210,9 +1209,8 @@ static int mxcmci_resume(struct device *dev) return ret; } -#endif -static SIMPLE_DEV_PM_OPS(mxcmci_pm_ops, mxcmci_suspend, mxcmci_resume); +static DEFINE_SIMPLE_DEV_PM_OPS(mxcmci_pm_ops, mxcmci_suspend, mxcmci_resume); static struct platform_driver mxcmci_driver = { .probe = mxcmci_probe, @@ -1220,7 +1218,7 @@ static struct platform_driver mxcmci_driver = { .driver = { .name = DRIVER_NAME, .probe_type = PROBE_PREFER_ASYNCHRONOUS, - .pm = &mxcmci_pm_ops, + .pm = pm_sleep_ptr(&mxcmci_pm_ops), .of_match_table = mxcmci_of_match, } }; diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 9dafcbf969d9..fca30add563e 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -1499,41 +1499,6 @@ static void omap_hsmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) omap_hsmmc_set_bus_mode(host); } -static void omap_hsmmc_init_card(struct mmc_host *mmc, struct mmc_card *card) -{ - struct omap_hsmmc_host *host = mmc_priv(mmc); - - if (card->type == MMC_TYPE_SDIO || card->type == MMC_TYPE_SD_COMBO) { - struct device_node *np = mmc_dev(mmc)->of_node; - - /* - * REVISIT: should be moved to sdio core and made more - * general e.g. by expanding the DT bindings of child nodes - * to provide a mechanism to provide this information: - * Documentation/devicetree/bindings/mmc/mmc-card.yaml - */ - - np = of_get_compatible_child(np, "ti,wl1251"); - if (np) { - /* - * We have TI wl1251 attached to MMC3. Pass this - * information to the SDIO core because it can't be - * probed by normal methods. - */ - - dev_info(host->dev, "found wl1251\n"); - card->quirks |= MMC_QUIRK_NONSTD_SDIO; - card->cccr.wide_bus = 1; - card->cis.vendor = 0x104c; - card->cis.device = 0x9066; - card->cis.blksize = 512; - card->cis.max_dtr = 24000000; - card->ocr = 0x80; - of_node_put(np); - } - } -} - static void omap_hsmmc_enable_sdio_irq(struct mmc_host *mmc, int enable) { struct omap_hsmmc_host *host = mmc_priv(mmc); @@ -1660,7 +1625,6 @@ static struct mmc_host_ops omap_hsmmc_ops = { .set_ios = omap_hsmmc_set_ios, .get_cd = mmc_gpio_get_cd, .get_ro = mmc_gpio_get_ro, - .init_card = omap_hsmmc_init_card, .enable_sdio_irq = omap_hsmmc_enable_sdio_irq, }; diff --git a/drivers/mmc/host/renesas_sdhi.h b/drivers/mmc/host/renesas_sdhi.h index 0c45e82ff0de..66d308e73e17 100644 --- a/drivers/mmc/host/renesas_sdhi.h +++ b/drivers/mmc/host/renesas_sdhi.h @@ -18,6 +18,8 @@ struct renesas_sdhi_scc { u32 tap_hs400_4tap; /* sampling clock position for HS400 (4 TAP) */ }; +#define SDHI_FLAG_NEED_CLKH_FALLBACK BIT(0) + struct renesas_sdhi_of_data { unsigned long tmio_flags; u32 tmio_ocr_mask; @@ -31,6 +33,7 @@ struct renesas_sdhi_of_data { int taps_num; unsigned int max_blk_count; unsigned short max_segs; + unsigned long sdhi_flags; }; #define SDHI_CALIB_TABLE_MAX 32 @@ -57,6 +60,7 @@ struct tmio_mmc_dma { struct renesas_sdhi { struct clk *clk; + struct clk *clkh; struct clk *clk_cd; struct tmio_mmc_data mmc_data; struct tmio_mmc_dma dma_priv; diff --git a/drivers/mmc/host/renesas_sdhi_core.c b/drivers/mmc/host/renesas_sdhi_core.c index f5b2684ad805..2797a9c0f17d 100644 --- a/drivers/mmc/host/renesas_sdhi_core.c +++ b/drivers/mmc/host/renesas_sdhi_core.c @@ -127,10 +127,12 @@ static int renesas_sdhi_clk_enable(struct tmio_mmc_host *host) } static unsigned int renesas_sdhi_clk_update(struct tmio_mmc_host *host, - unsigned int new_clock) + unsigned int wanted_clock) { struct renesas_sdhi *priv = host_to_priv(host); + struct clk *ref_clk = priv->clk; unsigned int freq, diff, best_freq = 0, diff_min = ~0; + unsigned int new_clock, clkh_shift = 0; int i; /* @@ -141,6 +143,16 @@ static unsigned int renesas_sdhi_clk_update(struct tmio_mmc_host *host, if (!(host->pdata->flags & TMIO_MMC_MIN_RCAR2) || mmc_doing_tune(host->mmc)) return clk_get_rate(priv->clk); + if (priv->clkh) { + bool use_4tap = priv->quirks && priv->quirks->hs400_4taps; + bool need_slow_clkh = (host->mmc->ios.timing == MMC_TIMING_UHS_SDR104) || + (host->mmc->ios.timing == MMC_TIMING_MMC_HS400); + clkh_shift = use_4tap && need_slow_clkh ? 1 : 2; + ref_clk = priv->clkh; + } + + new_clock = wanted_clock << clkh_shift; + /* * We want the bus clock to be as close as possible to, but no * greater than, new_clock. As we can divide by 1 << i for @@ -148,11 +160,10 @@ static unsigned int renesas_sdhi_clk_update(struct tmio_mmc_host *host, * possible, but no greater than, new_clock << i. */ for (i = min(9, ilog2(UINT_MAX / new_clock)); i >= 0; i--) { - freq = clk_round_rate(priv->clk, new_clock << i); + freq = clk_round_rate(ref_clk, new_clock << i); if (freq > (new_clock << i)) { /* Too fast; look for a slightly slower option */ - freq = clk_round_rate(priv->clk, - (new_clock << i) / 4 * 3); + freq = clk_round_rate(ref_clk, (new_clock << i) / 4 * 3); if (freq > (new_clock << i)) continue; } @@ -164,7 +175,10 @@ static unsigned int renesas_sdhi_clk_update(struct tmio_mmc_host *host, } } - clk_set_rate(priv->clk, best_freq); + clk_set_rate(ref_clk, best_freq); + + if (priv->clkh) + clk_set_rate(priv->clk, best_freq >> clkh_shift); return clk_get_rate(priv->clk); } @@ -628,7 +642,7 @@ static int renesas_sdhi_select_tuning(struct tmio_mmc_host *host) * is at least SH_MOBILE_SDHI_MIN_TAP_ROW probes long then use the * center index as the tap, otherwise bail out. */ - bitmap_for_each_set_region(bitmap, rs, re, 0, taps_size) { + for_each_set_bitrange(rs, re, bitmap, taps_size) { if (re - rs > tap_cnt) { tap_end = re; tap_start = rs; @@ -904,11 +918,12 @@ int renesas_sdhi_probe(struct platform_device *pdev, dma_priv = &priv->dma_priv; priv->clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(priv->clk)) { - ret = PTR_ERR(priv->clk); - dev_err(&pdev->dev, "cannot get clock: %d\n", ret); - return ret; - } + if (IS_ERR(priv->clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(priv->clk), "cannot get clock"); + + priv->clkh = devm_clk_get_optional(&pdev->dev, "clkh"); + if (IS_ERR(priv->clkh)) + return dev_err_probe(&pdev->dev, PTR_ERR(priv->clkh), "cannot get clkh"); /* * Some controllers provide a 2nd clock just to run the internal card @@ -921,9 +936,9 @@ int renesas_sdhi_probe(struct platform_device *pdev, * to the card detect circuit. That leaves us with if separate clocks * are presented, we must treat them both as virtually 1 clock. */ - priv->clk_cd = devm_clk_get(&pdev->dev, "cd"); + priv->clk_cd = devm_clk_get_optional(&pdev->dev, "cd"); if (IS_ERR(priv->clk_cd)) - priv->clk_cd = NULL; + return dev_err_probe(&pdev->dev, PTR_ERR(priv->clk_cd), "cannot get cd clock"); priv->pinctrl = devm_pinctrl_get(&pdev->dev); if (!IS_ERR(priv->pinctrl)) { @@ -947,6 +962,10 @@ int renesas_sdhi_probe(struct platform_device *pdev, mmc_data->max_segs = of_data->max_segs; dma_priv->dma_buswidth = of_data->dma_buswidth; host->bus_shift = of_data->bus_shift; + /* Fallback for old DTs */ + if (!priv->clkh && of_data->sdhi_flags & SDHI_FLAG_NEED_CLKH_FALLBACK) + priv->clkh = clk_get_parent(clk_get_parent(priv->clk)); + } host->write16_hook = renesas_sdhi_write16_hook; @@ -1044,7 +1063,7 @@ int renesas_sdhi_probe(struct platform_device *pdev, host->mmc->caps2 & (MMC_CAP2_HS200_1_8V_SDR | MMC_CAP2_HS400_1_8V))) { const struct renesas_sdhi_scc *taps = of_data->taps; - bool use_4tap = priv->quirks && priv->quirks->hs400_4taps; + bool use_4tap = quirks && quirks->hs400_4taps; bool hit = false; for (i = 0; i < of_data->taps_num; i++) { diff --git a/drivers/mmc/host/renesas_sdhi_internal_dmac.c b/drivers/mmc/host/renesas_sdhi_internal_dmac.c index 7660f7ea74dd..9d2c600fd4ce 100644 --- a/drivers/mmc/host/renesas_sdhi_internal_dmac.c +++ b/drivers/mmc/host/renesas_sdhi_internal_dmac.c @@ -125,6 +125,22 @@ static const struct renesas_sdhi_of_data of_data_rcar_gen3 = { /* DMAC can handle 32bit blk count but only 1 segment */ .max_blk_count = UINT_MAX / TMIO_MAX_BLK_SIZE, .max_segs = 1, + .sdhi_flags = SDHI_FLAG_NEED_CLKH_FALLBACK, +}; + +static const struct renesas_sdhi_of_data of_data_rcar_gen3_no_fallback = { + .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_CLK_ACTUAL | + TMIO_MMC_HAVE_CBSY | TMIO_MMC_MIN_RCAR2, + .capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ | + MMC_CAP_CMD23 | MMC_CAP_WAIT_WHILE_BUSY, + .capabilities2 = MMC_CAP2_NO_WRITE_PROTECT | MMC_CAP2_MERGE_CAPABLE, + .bus_shift = 2, + .scc_offset = 0x1000, + .taps = rcar_gen3_scc_taps, + .taps_num = ARRAY_SIZE(rcar_gen3_scc_taps), + /* DMAC can handle 32bit blk count but only 1 segment */ + .max_blk_count = UINT_MAX / TMIO_MAX_BLK_SIZE, + .max_segs = 1, }; static const u8 r8a7796_es13_calib_table[2][SDHI_CALIB_TABLE_MAX] = { @@ -214,6 +230,10 @@ static const struct renesas_sdhi_of_data_with_quirks of_r8a77965_compatible = { .quirks = &sdhi_quirks_r8a77965, }; +static const struct renesas_sdhi_of_data_with_quirks of_r8a77970_compatible = { + .of_data = &of_data_rcar_gen3_no_fallback, +}; + static const struct renesas_sdhi_of_data_with_quirks of_r8a77980_compatible = { .of_data = &of_data_rcar_gen3, .quirks = &sdhi_quirks_nohs400, @@ -235,6 +255,7 @@ static const struct of_device_id renesas_sdhi_internal_dmac_of_match[] = { { .compatible = "renesas,sdhi-r8a7796", .data = &of_rcar_gen3_compatible, }, { .compatible = "renesas,sdhi-r8a77961", .data = &of_r8a77961_compatible, }, { .compatible = "renesas,sdhi-r8a77965", .data = &of_r8a77965_compatible, }, + { .compatible = "renesas,sdhi-r8a77970", .data = &of_r8a77970_compatible, }, { .compatible = "renesas,sdhi-r8a77980", .data = &of_r8a77980_compatible, }, { .compatible = "renesas,sdhi-r8a77990", .data = &of_r8a77990_compatible, }, { .compatible = "renesas,rcar-gen3-sdhi", .data = &of_rcar_gen3_compatible, }, diff --git a/drivers/mmc/host/sdhci-acpi.c b/drivers/mmc/host/sdhci-acpi.c index f1ef0d28b0dd..c0350e9c03f3 100644 --- a/drivers/mmc/host/sdhci-acpi.c +++ b/drivers/mmc/host/sdhci-acpi.c @@ -31,10 +31,8 @@ #include <linux/mmc/slot-gpio.h> #ifdef CONFIG_X86 -#include <asm/cpu_device_id.h> -#include <asm/intel-family.h> +#include <linux/platform_data/x86/soc.h> #include <asm/iosf_mbi.h> -#include <linux/pci.h> #endif #include "sdhci.h" @@ -240,26 +238,6 @@ static const struct sdhci_acpi_chip sdhci_acpi_chip_int = { #ifdef CONFIG_X86 -static bool sdhci_acpi_byt(void) -{ - static const struct x86_cpu_id byt[] = { - X86_MATCH_INTEL_FAM6_MODEL(ATOM_SILVERMONT, NULL), - {} - }; - - return x86_match_cpu(byt); -} - -static bool sdhci_acpi_cht(void) -{ - static const struct x86_cpu_id cht[] = { - X86_MATCH_INTEL_FAM6_MODEL(ATOM_AIRMONT, NULL), - {} - }; - - return x86_match_cpu(cht); -} - #define BYT_IOSF_SCCEP 0x63 #define BYT_IOSF_OCP_NETCTRL0 0x1078 #define BYT_IOSF_OCP_TIMEOUT_BASE GENMASK(10, 8) @@ -268,7 +246,7 @@ static void sdhci_acpi_byt_setting(struct device *dev) { u32 val = 0; - if (!sdhci_acpi_byt()) + if (!soc_intel_is_byt()) return; if (iosf_mbi_read(BYT_IOSF_SCCEP, MBI_CR_READ, BYT_IOSF_OCP_NETCTRL0, @@ -293,7 +271,7 @@ static void sdhci_acpi_byt_setting(struct device *dev) static bool sdhci_acpi_byt_defer(struct device *dev) { - if (!sdhci_acpi_byt()) + if (!soc_intel_is_byt()) return false; if (!iosf_mbi_available()) @@ -304,43 +282,6 @@ static bool sdhci_acpi_byt_defer(struct device *dev) return false; } -static bool sdhci_acpi_cht_pci_wifi(unsigned int vendor, unsigned int device, - unsigned int slot, unsigned int parent_slot) -{ - struct pci_dev *dev, *parent, *from = NULL; - - while (1) { - dev = pci_get_device(vendor, device, from); - pci_dev_put(from); - if (!dev) - break; - parent = pci_upstream_bridge(dev); - if (ACPI_COMPANION(&dev->dev) && PCI_SLOT(dev->devfn) == slot && - parent && PCI_SLOT(parent->devfn) == parent_slot && - !pci_upstream_bridge(parent)) { - pci_dev_put(dev); - return true; - } - from = dev; - } - - return false; -} - -/* - * GPDwin uses PCI wifi which conflicts with SDIO's use of - * acpi_device_fix_up_power() on child device nodes. Identifying GPDwin is - * problematic, but since SDIO is only used for wifi, the presence of the PCI - * wifi card in the expected slot with an ACPI companion node, is used to - * indicate that acpi_device_fix_up_power() should be avoided. - */ -static inline bool sdhci_acpi_no_fixup_child_power(struct acpi_device *adev) -{ - return sdhci_acpi_cht() && - acpi_dev_hid_uid_match(adev, "80860F14", "2") && - sdhci_acpi_cht_pci_wifi(0x14e4, 0x43ec, 0, 28); -} - #else static inline void sdhci_acpi_byt_setting(struct device *dev) @@ -352,11 +293,6 @@ static inline bool sdhci_acpi_byt_defer(struct device *dev) return false; } -static inline bool sdhci_acpi_no_fixup_child_power(struct acpi_device *adev) -{ - return false; -} - #endif static int bxt_get_cd(struct mmc_host *mmc) @@ -861,11 +797,9 @@ static int sdhci_acpi_probe(struct platform_device *pdev) /* Power on the SDHCI controller and its children */ acpi_device_fix_up_power(device); - if (!sdhci_acpi_no_fixup_child_power(device)) { - list_for_each_entry(child, &device->children, node) - if (child->status.present && child->status.enabled) - acpi_device_fix_up_power(child); - } + list_for_each_entry(child, &device->children, node) + if (child->status.present && child->status.enabled) + acpi_device_fix_up_power(child); if (sdhci_acpi_byt_defer(dev)) return -EPROBE_DEFER; diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c index 764ee1b761d9..55981b0f0b10 100644 --- a/drivers/mmc/host/sdhci-esdhc-imx.c +++ b/drivers/mmc/host/sdhci-esdhc-imx.c @@ -305,6 +305,9 @@ static struct esdhc_soc_data usdhc_imx7ulp_data = { | ESDHC_FLAG_PMQOS | ESDHC_FLAG_HS400 | ESDHC_FLAG_STATE_LOST_IN_LPMODE, }; +static struct esdhc_soc_data usdhc_imxrt1050_data = { + .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_HS200 | ESDHC_FLAG_ERR004536, +}; static struct esdhc_soc_data usdhc_imx8qxp_data = { .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING @@ -355,6 +358,7 @@ static const struct of_device_id imx_esdhc_dt_ids[] = { { .compatible = "fsl,imx7ulp-usdhc", .data = &usdhc_imx7ulp_data, }, { .compatible = "fsl,imx8qxp-usdhc", .data = &usdhc_imx8qxp_data, }, { .compatible = "fsl,imx8mm-usdhc", .data = &usdhc_imx8mm_data, }, + { .compatible = "fsl,imxrt1050-usdhc", .data = &usdhc_imxrt1050_data, }, { .compatible = "nxp,s32g2-usdhc", .data = &usdhc_s32g2_data, }, { /* sentinel */ } }; diff --git a/drivers/mmc/host/sdhci-pci-core.c b/drivers/mmc/host/sdhci-pci-core.c index 6f9877546830..ed53276f6ad9 100644 --- a/drivers/mmc/host/sdhci-pci-core.c +++ b/drivers/mmc/host/sdhci-pci-core.c @@ -1866,6 +1866,7 @@ static const struct pci_device_id pci_ids[] = { SDHCI_PCI_DEVICE(INTEL, JSL_SD, intel_byt_sd), SDHCI_PCI_DEVICE(INTEL, LKF_EMMC, intel_glk_emmc), SDHCI_PCI_DEVICE(INTEL, LKF_SD, intel_byt_sd), + SDHCI_PCI_DEVICE(INTEL, ADL_EMMC, intel_glk_emmc), 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-gli.c b/drivers/mmc/host/sdhci-pci-gli.c index 4fd99c1e82ba..97035d77c18c 100644 --- a/drivers/mmc/host/sdhci-pci-gli.c +++ b/drivers/mmc/host/sdhci-pci-gli.c @@ -12,6 +12,7 @@ #include <linux/pci.h> #include <linux/mmc/mmc.h> #include <linux/delay.h> +#include <linux/of.h> #include "sdhci.h" #include "sdhci-pci.h" #include "cqhci.h" @@ -116,6 +117,8 @@ #define PCI_GLI_9755_PECONF 0x44 #define PCI_GLI_9755_LFCLK GENMASK(14, 12) #define PCI_GLI_9755_DMACLK BIT(29) +#define PCI_GLI_9755_INVERT_CD BIT(30) +#define PCI_GLI_9755_INVERT_WP BIT(31) #define PCI_GLI_9755_CFG2 0x48 #define PCI_GLI_9755_CFG2_L1DLY GENMASK(28, 24) @@ -570,6 +573,14 @@ static void gl9755_hw_setting(struct sdhci_pci_slot *slot) gl9755_wt_on(pdev); pci_read_config_dword(pdev, PCI_GLI_9755_PECONF, &value); + /* + * Apple ARM64 platforms using these chips may have + * inverted CD/WP detection. + */ + if (of_property_read_bool(pdev->dev.of_node, "cd-inverted")) + value |= PCI_GLI_9755_INVERT_CD; + if (of_property_read_bool(pdev->dev.of_node, "wp-inverted")) + value |= PCI_GLI_9755_INVERT_WP; value &= ~PCI_GLI_9755_LFCLK; value &= ~PCI_GLI_9755_DMACLK; pci_write_config_dword(pdev, PCI_GLI_9755_PECONF, value); @@ -891,7 +902,28 @@ static int gli_probe_slot_gl9763e(struct sdhci_pci_slot *slot) return 0; } +#define REG_OFFSET_IN_BITS(reg) ((reg) << 3 & 0x18) + +static u16 sdhci_gli_readw(struct sdhci_host *host, int reg) +{ + u32 val = readl(host->ioaddr + (reg & ~3)); + u16 word; + + word = (val >> REG_OFFSET_IN_BITS(reg)) & 0xffff; + return word; +} + +static u8 sdhci_gli_readb(struct sdhci_host *host, int reg) +{ + u32 val = readl(host->ioaddr + (reg & ~3)); + u8 byte = (val >> REG_OFFSET_IN_BITS(reg)) & 0xff; + + return byte; +} + static const struct sdhci_ops sdhci_gl9755_ops = { + .read_w = sdhci_gli_readw, + .read_b = sdhci_gli_readb, .set_clock = sdhci_gl9755_set_clock, .enable_dma = sdhci_pci_enable_dma, .set_bus_width = sdhci_set_bus_width, @@ -911,6 +943,8 @@ const struct sdhci_pci_fixes sdhci_gl9755 = { }; static const struct sdhci_ops sdhci_gl9750_ops = { + .read_w = sdhci_gli_readw, + .read_b = sdhci_gli_readb, .read_l = sdhci_gl9750_readl, .set_clock = sdhci_gl9750_set_clock, .enable_dma = sdhci_pci_enable_dma, diff --git a/drivers/mmc/host/sdhci-pci-o2micro.c b/drivers/mmc/host/sdhci-pci-o2micro.c index f045c1ee4667..92c20cb8074a 100644 --- a/drivers/mmc/host/sdhci-pci-o2micro.c +++ b/drivers/mmc/host/sdhci-pci-o2micro.c @@ -12,6 +12,7 @@ #include <linux/mmc/mmc.h> #include <linux/delay.h> #include <linux/iopoll.h> +#include <linux/bitfield.h> #include "sdhci.h" #include "sdhci-pci.h" @@ -43,12 +44,16 @@ #define O2_SD_CAP_REG0 0x334 #define O2_SD_UHS1_CAP_SETTING 0x33C #define O2_SD_DELAY_CTRL 0x350 +#define O2_SD_OUTPUT_CLK_SOURCE_SWITCH 0x354 #define O2_SD_UHS2_L1_CTRL 0x35C #define O2_SD_FUNC_REG3 0x3E0 #define O2_SD_FUNC_REG4 0x3E4 #define O2_SD_LED_ENABLE BIT(6) #define O2_SD_FREG0_LEDOFF BIT(13) +#define O2_SD_SEL_DLL BIT(16) #define O2_SD_FREG4_ENABLE_CLK_SET BIT(22) +#define O2_SD_PHASE_MASK GENMASK(23, 20) +#define O2_SD_FIX_PHASE FIELD_PREP(O2_SD_PHASE_MASK, 0x9) #define O2_SD_VENDOR_SETTING 0x110 #define O2_SD_VENDOR_SETTING2 0x1C8 @@ -301,9 +306,13 @@ static int sdhci_o2_dll_recovery(struct sdhci_host *host) static int sdhci_o2_execute_tuning(struct mmc_host *mmc, u32 opcode) { struct sdhci_host *host = mmc_priv(mmc); + struct sdhci_pci_slot *slot = sdhci_priv(host); + struct sdhci_pci_chip *chip = slot->chip; int current_bus_width = 0; u32 scratch32 = 0; u16 scratch = 0; + u8 scratch_8 = 0; + u32 reg_val; /* * This handler only implements the eMMC tuning that is specific to @@ -322,6 +331,32 @@ static int sdhci_o2_execute_tuning(struct mmc_host *mmc, u32 opcode) scratch |= O2_SD_PWR_FORCE_L0; sdhci_writew(host, scratch, O2_SD_MISC_CTRL); + /* Stop clk */ + reg_val = sdhci_readw(host, SDHCI_CLOCK_CONTROL); + reg_val &= ~SDHCI_CLOCK_CARD_EN; + sdhci_writew(host, reg_val, SDHCI_CLOCK_CONTROL); + + /* UnLock WP */ + pci_read_config_byte(chip->pdev, O2_SD_LOCK_WP, &scratch_8); + scratch_8 &= 0x7f; + pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch_8); + + /* Set pcr 0x354[16] to choose dll clock, and set the default phase */ + pci_read_config_dword(chip->pdev, O2_SD_OUTPUT_CLK_SOURCE_SWITCH, ®_val); + reg_val &= ~(O2_SD_SEL_DLL | O2_SD_PHASE_MASK); + reg_val |= (O2_SD_SEL_DLL | O2_SD_FIX_PHASE); + pci_write_config_dword(chip->pdev, O2_SD_OUTPUT_CLK_SOURCE_SWITCH, reg_val); + + /* Lock WP */ + pci_read_config_byte(chip->pdev, O2_SD_LOCK_WP, &scratch_8); + scratch_8 |= 0x80; + pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch_8); + + /* Start clk */ + reg_val = sdhci_readw(host, SDHCI_CLOCK_CONTROL); + reg_val |= SDHCI_CLOCK_CARD_EN; + sdhci_writew(host, reg_val, SDHCI_CLOCK_CONTROL); + /* wait DLL lock, timeout value 5ms */ if (readx_poll_timeout(sdhci_o2_pll_dll_wdt_control, host, scratch32, (scratch32 & O2_DLL_LOCK_STATUS), 1, 5000)) @@ -533,23 +568,32 @@ static void sdhci_pci_o2_set_clock(struct sdhci_host *host, unsigned int clock) if (clock == 0) return; - if ((host->timing == MMC_TIMING_UHS_SDR104) && (clock == 200000000)) { - pci_read_config_byte(chip->pdev, O2_SD_LOCK_WP, &scratch); - - scratch &= 0x7f; - pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch); + /* UnLock WP */ + pci_read_config_byte(chip->pdev, O2_SD_LOCK_WP, &scratch); + scratch &= 0x7f; + pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch); + if ((host->timing == MMC_TIMING_UHS_SDR104) && (clock == 200000000)) { pci_read_config_dword(chip->pdev, O2_SD_PLL_SETTING, &scratch_32); if ((scratch_32 & 0xFFFF0000) != 0x2c280000) o2_pci_set_baseclk(chip, 0x2c280000); + } else { + pci_read_config_dword(chip->pdev, O2_SD_PLL_SETTING, &scratch_32); - pci_read_config_byte(chip->pdev, O2_SD_LOCK_WP, &scratch); - - scratch |= 0x80; - pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch); + if ((scratch_32 & 0xFFFF0000) != 0x25100000) + o2_pci_set_baseclk(chip, 0x25100000); } + pci_read_config_dword(chip->pdev, O2_SD_OUTPUT_CLK_SOURCE_SWITCH, &scratch_32); + scratch_32 &= ~(O2_SD_SEL_DLL | O2_SD_PHASE_MASK); + pci_write_config_dword(chip->pdev, O2_SD_OUTPUT_CLK_SOURCE_SWITCH, scratch_32); + + /* Lock WP */ + pci_read_config_byte(chip->pdev, O2_SD_LOCK_WP, &scratch); + scratch |= 0x80; + pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch); + clk = sdhci_calc_clk(host, clock, &host->mmc->actual_clock); sdhci_o2_enable_clk(host, clk); } diff --git a/drivers/mmc/host/sdhci-pci.h b/drivers/mmc/host/sdhci-pci.h index 5e3193278ff9..3661a224fb04 100644 --- a/drivers/mmc/host/sdhci-pci.h +++ b/drivers/mmc/host/sdhci-pci.h @@ -59,6 +59,7 @@ #define PCI_DEVICE_ID_INTEL_JSL_SD 0x4df8 #define PCI_DEVICE_ID_INTEL_LKF_EMMC 0x98c4 #define PCI_DEVICE_ID_INTEL_LKF_SD 0x98f8 +#define PCI_DEVICE_ID_INTEL_ADL_EMMC 0x54c4 #define PCI_DEVICE_ID_SYSKONNECT_8000 0x8000 #define PCI_DEVICE_ID_VIA_95D0 0x95d0 diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c index a5001875876b..35ebba067e87 100644 --- a/drivers/mmc/host/sdhci-tegra.c +++ b/drivers/mmc/host/sdhci-tegra.c @@ -15,6 +15,8 @@ #include <linux/of.h> #include <linux/of_device.h> #include <linux/pinctrl/consumer.h> +#include <linux/pm_opp.h> +#include <linux/pm_runtime.h> #include <linux/regulator/consumer.h> #include <linux/reset.h> #include <linux/mmc/card.h> @@ -24,6 +26,8 @@ #include <linux/gpio/consumer.h> #include <linux/ktime.h> +#include <soc/tegra/common.h> + #include "sdhci-pltfm.h" #include "cqhci.h" @@ -356,23 +360,6 @@ static void tegra_sdhci_set_tap(struct sdhci_host *host, unsigned int tap) } } -static void tegra_sdhci_hs400_enhanced_strobe(struct mmc_host *mmc, - struct mmc_ios *ios) -{ - struct sdhci_host *host = mmc_priv(mmc); - u32 val; - - val = sdhci_readl(host, SDHCI_TEGRA_VENDOR_SYS_SW_CTRL); - - if (ios->enhanced_strobe) - val |= SDHCI_TEGRA_SYS_SW_CTRL_ENHANCED_STROBE; - else - val &= ~SDHCI_TEGRA_SYS_SW_CTRL_ENHANCED_STROBE; - - sdhci_writel(host, val, SDHCI_TEGRA_VENDOR_SYS_SW_CTRL); - -} - static void tegra_sdhci_reset(struct sdhci_host *host, u8 mask) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); @@ -760,7 +747,9 @@ static void tegra_sdhci_set_clock(struct sdhci_host *host, unsigned int clock) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); + struct device *dev = mmc_dev(host->mmc); unsigned long host_clk; + int err; if (!clock) return sdhci_set_clock(host, clock); @@ -778,7 +767,12 @@ static void tegra_sdhci_set_clock(struct sdhci_host *host, unsigned int clock) * from clk_get_rate() is used. */ host_clk = tegra_host->ddr_signaling ? clock * 2 : clock; - clk_set_rate(pltfm_host->clk, host_clk); + + err = dev_pm_opp_set_rate(dev, host_clk); + if (err) + dev_err(dev, "failed to set clk rate to %luHz: %d\n", + host_clk, err); + tegra_host->curr_clk_rate = host_clk; if (tegra_host->ddr_signaling) host->max_clk = host_clk; @@ -793,6 +787,32 @@ static void tegra_sdhci_set_clock(struct sdhci_host *host, unsigned int clock) } } +static void tegra_sdhci_hs400_enhanced_strobe(struct mmc_host *mmc, + struct mmc_ios *ios) +{ + struct sdhci_host *host = mmc_priv(mmc); + u32 val; + + val = sdhci_readl(host, SDHCI_TEGRA_VENDOR_SYS_SW_CTRL); + + if (ios->enhanced_strobe) { + val |= SDHCI_TEGRA_SYS_SW_CTRL_ENHANCED_STROBE; + /* + * When CMD13 is sent from mmc_select_hs400es() after + * switching to HS400ES mode, the bus is operating at + * either MMC_HIGH_26_MAX_DTR or MMC_HIGH_52_MAX_DTR. + * To meet Tegra SDHCI requirement at HS400ES mode, force SDHCI + * interface clock to MMC_HS200_MAX_DTR (200 MHz) so that host + * controller CAR clock and the interface clock are rate matched. + */ + tegra_sdhci_set_clock(host, MMC_HS200_MAX_DTR); + } else { + val &= ~SDHCI_TEGRA_SYS_SW_CTRL_ENHANCED_STROBE; + } + + sdhci_writel(host, val, SDHCI_TEGRA_VENDOR_SYS_SW_CTRL); +} + static unsigned int tegra_sdhci_get_max_clock(struct sdhci_host *host) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); @@ -1705,7 +1725,6 @@ static int sdhci_tegra_probe(struct platform_device *pdev) "failed to get clock\n"); goto err_clk_get; } - clk_prepare_enable(clk); pltfm_host->clk = clk; tegra_host->rst = devm_reset_control_get_exclusive(&pdev->dev, @@ -1716,15 +1735,24 @@ static int sdhci_tegra_probe(struct platform_device *pdev) goto err_rst_get; } - rc = reset_control_assert(tegra_host->rst); + rc = devm_tegra_core_dev_init_opp_table_common(&pdev->dev); if (rc) goto err_rst_get; + pm_runtime_enable(&pdev->dev); + rc = pm_runtime_resume_and_get(&pdev->dev); + if (rc) + goto err_pm_get; + + rc = reset_control_assert(tegra_host->rst); + if (rc) + goto err_rst_assert; + usleep_range(2000, 4000); rc = reset_control_deassert(tegra_host->rst); if (rc) - goto err_rst_get; + goto err_rst_assert; usleep_range(2000, 4000); @@ -1736,8 +1764,11 @@ static int sdhci_tegra_probe(struct platform_device *pdev) err_add_host: reset_control_assert(tegra_host->rst); +err_rst_assert: + pm_runtime_put_sync_suspend(&pdev->dev); +err_pm_get: + pm_runtime_disable(&pdev->dev); err_rst_get: - clk_disable_unprepare(pltfm_host->clk); err_clk_get: clk_disable_unprepare(tegra_host->tmclk); err_power_req: @@ -1756,19 +1787,38 @@ static int sdhci_tegra_remove(struct platform_device *pdev) reset_control_assert(tegra_host->rst); usleep_range(2000, 4000); - clk_disable_unprepare(pltfm_host->clk); - clk_disable_unprepare(tegra_host->tmclk); + pm_runtime_put_sync_suspend(&pdev->dev); + pm_runtime_force_suspend(&pdev->dev); + + clk_disable_unprepare(tegra_host->tmclk); sdhci_pltfm_free(pdev); return 0; } -#ifdef CONFIG_PM_SLEEP -static int __maybe_unused sdhci_tegra_suspend(struct device *dev) +static int __maybe_unused sdhci_tegra_runtime_suspend(struct device *dev) +{ + struct sdhci_host *host = dev_get_drvdata(dev); + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + + clk_disable_unprepare(pltfm_host->clk); + + return 0; +} + +static int __maybe_unused sdhci_tegra_runtime_resume(struct device *dev) { struct sdhci_host *host = dev_get_drvdata(dev); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + + return clk_prepare_enable(pltfm_host->clk); +} + +#ifdef CONFIG_PM_SLEEP +static int sdhci_tegra_suspend(struct device *dev) +{ + struct sdhci_host *host = dev_get_drvdata(dev); int ret; if (host->mmc->caps2 & MMC_CAP2_CQE) { @@ -1783,17 +1833,22 @@ static int __maybe_unused sdhci_tegra_suspend(struct device *dev) return ret; } - clk_disable_unprepare(pltfm_host->clk); + ret = pm_runtime_force_suspend(dev); + if (ret) { + sdhci_resume_host(host); + cqhci_resume(host->mmc); + return ret; + } + return 0; } -static int __maybe_unused sdhci_tegra_resume(struct device *dev) +static int 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); + ret = pm_runtime_force_resume(dev); if (ret) return ret; @@ -1812,13 +1867,16 @@ static int __maybe_unused sdhci_tegra_resume(struct device *dev) suspend_host: sdhci_suspend_host(host); disable_clk: - clk_disable_unprepare(pltfm_host->clk); + pm_runtime_force_suspend(dev); return ret; } #endif -static SIMPLE_DEV_PM_OPS(sdhci_tegra_dev_pm_ops, sdhci_tegra_suspend, - sdhci_tegra_resume); +static const struct dev_pm_ops sdhci_tegra_dev_pm_ops = { + SET_RUNTIME_PM_OPS(sdhci_tegra_runtime_suspend, sdhci_tegra_runtime_resume, + NULL) + SET_SYSTEM_SLEEP_PM_OPS(sdhci_tegra_suspend, sdhci_tegra_resume) +}; static struct platform_driver sdhci_tegra_driver = { .driver = { diff --git a/drivers/mmc/host/tmio_mmc_core.c b/drivers/mmc/host/tmio_mmc_core.c index e2affa52ef46..a5850d83908b 100644 --- a/drivers/mmc/host/tmio_mmc_core.c +++ b/drivers/mmc/host/tmio_mmc_core.c @@ -960,14 +960,8 @@ static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) case MMC_POWER_OFF: tmio_mmc_power_off(host); /* For R-Car Gen2+, we need to reset SDHI specific SCC */ - if (host->pdata->flags & TMIO_MMC_MIN_RCAR2) { - host->reset(host); - - if (host->native_hotplug) - tmio_mmc_enable_mmc_irqs(host, - TMIO_STAT_CARD_REMOVE | - TMIO_STAT_CARD_INSERT); - } + if (host->pdata->flags & TMIO_MMC_MIN_RCAR2) + tmio_mmc_reset(host); host->set_clock(host, 0); break; @@ -1175,6 +1169,7 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host) if (mmc_can_gpio_cd(mmc)) _host->ops.get_cd = mmc_gpio_get_cd; + /* must be set before tmio_mmc_reset() */ _host->native_hotplug = !(mmc_can_gpio_cd(mmc) || mmc->caps & MMC_CAP_NEEDS_POLL || !mmc_card_is_removable(mmc)); @@ -1295,10 +1290,6 @@ int tmio_mmc_host_runtime_resume(struct device *dev) if (host->clk_cache) host->set_clock(host, host->clk_cache); - if (host->native_hotplug) - tmio_mmc_enable_mmc_irqs(host, - TMIO_STAT_CARD_REMOVE | TMIO_STAT_CARD_INSERT); - tmio_mmc_enable_dma(host, true); return 0; |