diff options
author | Stephen Rothwell <sfr@canb.auug.org.au> | 2017-06-01 12:22:18 +1000 |
---|---|---|
committer | Stephen Rothwell <sfr@canb.auug.org.au> | 2017-06-01 12:22:18 +1000 |
commit | f84a6fb1258b80b934049b5c2e2bdd77ea66ee12 (patch) | |
tree | f875ba2a8f001728dea3195498ebb73223be9b13 | |
parent | 9dcc345be8ae847d99673625d2b3ba0fec5bb482 (diff) | |
parent | 6e75316c15df8333506377743c75fcd626193849 (diff) |
Merge remote-tracking branch 'mmc/next'
41 files changed, 1032 insertions, 1382 deletions
diff --git a/Documentation/devicetree/bindings/mmc/rockchip-dw-mshc.txt b/Documentation/devicetree/bindings/mmc/rockchip-dw-mshc.txt index 520d61dad6dd..18e33cbe7eec 100644 --- a/Documentation/devicetree/bindings/mmc/rockchip-dw-mshc.txt +++ b/Documentation/devicetree/bindings/mmc/rockchip-dw-mshc.txt @@ -15,6 +15,7 @@ Required Properties: - "rockchip,rk3288-dw-mshc": for Rockchip RK3288 - "rockchip,rv1108-dw-mshc", "rockchip,rk3288-dw-mshc": for Rockchip RV1108 - "rockchip,rk3036-dw-mshc", "rockchip,rk3288-dw-mshc": for Rockchip RK3036 + - "rockchip,rk3328-dw-mshc", "rockchip,rk3288-dw-mshc": for Rockchip RK3328 - "rockchip,rk3368-dw-mshc", "rockchip,rk3288-dw-mshc": for Rockchip RK3368 - "rockchip,rk3399-dw-mshc", "rockchip,rk3288-dw-mshc": for Rockchip RK3399 diff --git a/drivers/mmc/core/Kconfig b/drivers/mmc/core/Kconfig index fc1ecdaaa9ca..42e89060cd41 100644 --- a/drivers/mmc/core/Kconfig +++ b/drivers/mmc/core/Kconfig @@ -61,24 +61,6 @@ config MMC_BLOCK_MINORS If unsure, say 8 here. -config MMC_BLOCK_BOUNCE - bool "Use bounce buffer for simple hosts" - depends on MMC_BLOCK - default y - help - SD/MMC is a high latency protocol where it is crucial to - send large requests in order to get high performance. Many - controllers, however, are restricted to continuous memory - (i.e. they can't do scatter-gather), something the kernel - rarely can provide. - - Say Y here to help these restricted hosts by bouncing - requests back and forth from a large buffer. You will get - a big performance gain at the cost of up to 64 KiB of - physical memory. - - If unsure, say Y here. - config SDIO_UART tristate "SDIO UART/GPS class support" depends on TTY diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index 8273b078686d..64f9fda92229 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -127,14 +127,6 @@ MODULE_PARM_DESC(perdev_minors, "Minors numbers to allocate per device"); static inline int mmc_blk_part_switch(struct mmc_card *card, struct mmc_blk_data *md); -static int get_card_status(struct mmc_card *card, u32 *status, int retries); - -static void mmc_blk_requeue(struct request_queue *q, struct request *req) -{ - spin_lock_irq(q->queue_lock); - blk_requeue_request(q, req); - spin_unlock_irq(q->queue_lock); -} static struct mmc_blk_data *mmc_blk_get(struct gendisk *disk) { @@ -197,6 +189,8 @@ static ssize_t power_ro_lock_store(struct device *dev, int ret; struct mmc_blk_data *md, *part_md; struct mmc_card *card; + struct mmc_queue *mq; + struct request *req; unsigned long set; if (kstrtoul(buf, 0, &set)) @@ -206,20 +200,14 @@ static ssize_t power_ro_lock_store(struct device *dev, return count; md = mmc_blk_get(dev_to_disk(dev)); + mq = &md->queue; card = md->queue.card; - mmc_get_card(card); - - ret = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BOOT_WP, - card->ext_csd.boot_ro_lock | - EXT_CSD_BOOT_WP_B_PWR_WP_EN, - card->ext_csd.part_time); - if (ret) - pr_err("%s: Locking boot partition ro until next power on failed: %d\n", md->disk->disk_name, ret); - else - card->ext_csd.boot_ro_lock |= EXT_CSD_BOOT_WP_B_PWR_WP_EN; - - mmc_put_card(card); + /* Dispatch locking to the block layer */ + req = blk_get_request(mq->queue, REQ_OP_DRV_OUT, __GFP_RECLAIM); + req_to_mmc_queue_req(req)->drv_op = MMC_DRV_OP_BOOT_WP; + blk_execute_rq(mq->queue, NULL, req, 0); + ret = req_to_mmc_queue_req(req)->drv_op_result; if (!ret) { pr_info("%s: Locking boot partition ro until next power on\n", @@ -392,7 +380,7 @@ static int ioctl_rpmb_card_status_poll(struct mmc_card *card, u32 *status, return -EINVAL; do { - err = get_card_status(card, status, 5); + err = __mmc_send_status(card, status, 5); if (err) break; @@ -450,7 +438,7 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md, struct mmc_request mrq = {}; struct scatterlist sg; int err; - int is_rpmb = false; + bool is_rpmb = false; u32 status = 0; if (!card || !md || !idata) @@ -570,9 +558,12 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev, struct mmc_ioc_cmd __user *ic_ptr) { struct mmc_blk_ioc_data *idata; + struct mmc_blk_ioc_data *idatas[1]; struct mmc_blk_data *md; + struct mmc_queue *mq; struct mmc_card *card; int err = 0, ioc_err = 0; + struct request *req; /* * The caller must have CAP_SYS_RAWIO, and must be calling this on the @@ -598,17 +589,21 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev, goto cmd_done; } - mmc_get_card(card); - - ioc_err = __mmc_blk_ioctl_cmd(card, md, idata); - - /* Always switch back to main area after RPMB access */ - if (md->area_type & MMC_BLK_DATA_AREA_RPMB) - mmc_blk_part_switch(card, dev_get_drvdata(&card->dev)); - - mmc_put_card(card); - + /* + * Dispatch the ioctl() into the block request queue. + */ + mq = &md->queue; + req = blk_get_request(mq->queue, + idata->ic.write_flag ? REQ_OP_DRV_OUT : REQ_OP_DRV_IN, + __GFP_RECLAIM); + idatas[0] = idata; + req_to_mmc_queue_req(req)->drv_op = MMC_DRV_OP_IOCTL; + req_to_mmc_queue_req(req)->idata = idatas; + req_to_mmc_queue_req(req)->ioc_count = 1; + blk_execute_rq(mq->queue, NULL, req, 0); + ioc_err = req_to_mmc_queue_req(req)->drv_op_result; err = mmc_blk_ioctl_copy_to_user(ic_ptr, idata); + blk_put_request(req); cmd_done: mmc_blk_put(md); @@ -625,8 +620,10 @@ static int mmc_blk_ioctl_multi_cmd(struct block_device *bdev, struct mmc_ioc_cmd __user *cmds = user->cmds; struct mmc_card *card; struct mmc_blk_data *md; + struct mmc_queue *mq; int i, err = 0, ioc_err = 0; __u64 num_of_cmds; + struct request *req; /* * The caller must have CAP_SYS_RAWIO, and must be calling this on the @@ -668,21 +665,26 @@ static int mmc_blk_ioctl_multi_cmd(struct block_device *bdev, goto cmd_done; } - mmc_get_card(card); - - for (i = 0; i < num_of_cmds && !ioc_err; i++) - ioc_err = __mmc_blk_ioctl_cmd(card, md, idata[i]); - - /* Always switch back to main area after RPMB access */ - if (md->area_type & MMC_BLK_DATA_AREA_RPMB) - mmc_blk_part_switch(card, dev_get_drvdata(&card->dev)); - mmc_put_card(card); + /* + * Dispatch the ioctl()s into the block request queue. + */ + mq = &md->queue; + req = blk_get_request(mq->queue, + idata[0]->ic.write_flag ? REQ_OP_DRV_OUT : REQ_OP_DRV_IN, + __GFP_RECLAIM); + req_to_mmc_queue_req(req)->drv_op = MMC_DRV_OP_IOCTL; + req_to_mmc_queue_req(req)->idata = idata; + req_to_mmc_queue_req(req)->ioc_count = num_of_cmds; + blk_execute_rq(mq->queue, NULL, req, 0); + ioc_err = req_to_mmc_queue_req(req)->drv_op_result; /* copy to user if data and response */ for (i = 0; i < num_of_cmds && !err; i++) err = mmc_blk_ioctl_copy_to_user(&cmds[i], idata[i]); + blk_put_request(req); + cmd_done: mmc_blk_put(md); cmd_err: @@ -852,21 +854,6 @@ static int mmc_sd_num_wr_blocks(struct mmc_card *card, u32 *written_blocks) return 0; } -static int get_card_status(struct mmc_card *card, u32 *status, int retries) -{ - struct mmc_command cmd = {}; - int err; - - cmd.opcode = MMC_SEND_STATUS; - if (!mmc_host_is_spi(card->host)) - cmd.arg = card->rca << 16; - cmd.flags = MMC_RSP_SPI_R2 | MMC_RSP_R1 | MMC_CMD_AC; - err = mmc_wait_for_cmd(card->host, &cmd, retries); - if (err == 0) - *status = cmd.resp[0]; - return err; -} - static int card_busy_detect(struct mmc_card *card, unsigned int timeout_ms, bool hw_busy_detect, struct request *req, bool *gen_err) { @@ -875,7 +862,7 @@ static int card_busy_detect(struct mmc_card *card, unsigned int timeout_ms, u32 status; do { - err = get_card_status(card, &status, 5); + err = __mmc_send_status(card, &status, 5); if (err) { pr_err("%s: error %d requesting status\n", req->rq_disk->disk_name, err); @@ -1043,7 +1030,7 @@ static int mmc_blk_cmd_recovery(struct mmc_card *card, struct request *req, * we can't be sure the returned status is for the r/w command. */ for (retry = 2; retry >= 0; retry--) { - err = get_card_status(card, &status, 0); + err = __mmc_send_status(card, &status, 0); if (!err) break; @@ -1178,6 +1165,54 @@ int mmc_access_rpmb(struct mmc_queue *mq) return false; } +/* + * The non-block commands come back from the block layer after it queued it and + * processed it with all other requests and then they get issued in this + * function. + */ +static void mmc_blk_issue_drv_op(struct mmc_queue *mq, struct request *req) +{ + struct mmc_queue_req *mq_rq; + struct mmc_card *card = mq->card; + struct mmc_blk_data *md = mq->blkdata; + int ret; + int i; + + mq_rq = req_to_mmc_queue_req(req); + + switch (mq_rq->drv_op) { + case MMC_DRV_OP_IOCTL: + for (i = 0; i < mq_rq->ioc_count; i++) { + ret = __mmc_blk_ioctl_cmd(card, md, mq_rq->idata[i]); + if (ret) + break; + } + /* Always switch back to main area after RPMB access */ + if (md->area_type & MMC_BLK_DATA_AREA_RPMB) + mmc_blk_part_switch(card, dev_get_drvdata(&card->dev)); + break; + case MMC_DRV_OP_BOOT_WP: + ret = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BOOT_WP, + card->ext_csd.boot_ro_lock | + EXT_CSD_BOOT_WP_B_PWR_WP_EN, + card->ext_csd.part_time); + if (ret) + pr_err("%s: Locking boot partition ro until next power on failed: %d\n", + md->disk->disk_name, ret); + else + card->ext_csd.boot_ro_lock |= + EXT_CSD_BOOT_WP_B_PWR_WP_EN; + break; + default: + pr_err("%s: unknown driver specific operation\n", + md->disk->disk_name); + ret = -EINVAL; + break; + } + mq_rq->drv_op_result = ret; + blk_end_request_all(req, ret); +} + static void mmc_blk_issue_discard_rq(struct mmc_queue *mq, struct request *req) { struct mmc_blk_data *md = mq->blkdata; @@ -1333,7 +1368,7 @@ static enum mmc_blk_status mmc_blk_err_check(struct mmc_card *card, struct mmc_queue_req *mq_mrq = container_of(areq, struct mmc_queue_req, areq); struct mmc_blk_request *brq = &mq_mrq->brq; - struct request *req = mq_mrq->req; + struct request *req = mmc_queue_req_to_req(mq_mrq); int need_retune = card->host->need_retune; bool ecc_err = false; bool gen_err = false; @@ -1440,7 +1475,7 @@ static void mmc_blk_data_prep(struct mmc_queue *mq, struct mmc_queue_req *mqrq, struct mmc_blk_data *md = mq->blkdata; struct mmc_card *card = md->queue.card; struct mmc_blk_request *brq = &mqrq->brq; - struct request *req = mqrq->req; + struct request *req = mmc_queue_req_to_req(mqrq); /* * Reliable writes are used to implement Forced Unit Access and @@ -1545,7 +1580,7 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq, { u32 readcmd, writecmd; struct mmc_blk_request *brq = &mqrq->brq; - struct request *req = mqrq->req; + struct request *req = mmc_queue_req_to_req(mqrq); struct mmc_blk_data *md = mq->blkdata; bool do_rel_wr, do_data_tag; @@ -1642,7 +1677,7 @@ static void mmc_blk_rw_cmd_abort(struct mmc_queue *mq, struct mmc_card *card, if (mmc_card_removed(card)) req->rq_flags |= RQF_QUIET; while (blk_end_request(req, -EIO, blk_rq_cur_bytes(req))); - mmc_queue_req_free(mq, mqrq); + mq->qcnt--; } /** @@ -1662,7 +1697,7 @@ static void mmc_blk_rw_try_restart(struct mmc_queue *mq, struct request *req, if (mmc_card_removed(mq->card)) { req->rq_flags |= RQF_QUIET; blk_end_request_all(req, -EIO); - mmc_queue_req_free(mq, mqrq); + mq->qcnt--; /* FIXME: just set to 0? */ return; } /* Else proceed and try to restart the current async request */ @@ -1685,12 +1720,8 @@ static void mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *new_req) bool req_pending = true; if (new_req) { - mqrq_cur = mmc_queue_req_find(mq, new_req); - if (!mqrq_cur) { - WARN_ON(1); - mmc_blk_requeue(mq->queue, new_req); - new_req = NULL; - } + mqrq_cur = req_to_mmc_queue_req(new_req); + mq->qcnt++; } if (!mq->qcnt) @@ -1731,7 +1762,7 @@ static void mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *new_req) */ mq_rq = container_of(old_areq, struct mmc_queue_req, areq); brq = &mq_rq->brq; - old_req = mq_rq->req; + old_req = mmc_queue_req_to_req(mq_rq); type = rq_data_dir(old_req) == READ ? MMC_BLK_READ : MMC_BLK_WRITE; mmc_queue_bounce_post(mq_rq); @@ -1764,12 +1795,12 @@ static void mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *new_req) if (req_pending) mmc_blk_rw_cmd_abort(mq, card, old_req, mq_rq); else - mmc_queue_req_free(mq, mq_rq); + mq->qcnt--; mmc_blk_rw_try_restart(mq, new_req, mqrq_cur); return; } if (!req_pending) { - mmc_queue_req_free(mq, mq_rq); + mq->qcnt--; mmc_blk_rw_try_restart(mq, new_req, mqrq_cur); return; } @@ -1814,7 +1845,7 @@ static void mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *new_req) req_pending = blk_end_request(old_req, -EIO, brq->data.blksz); if (!req_pending) { - mmc_queue_req_free(mq, mq_rq); + mq->qcnt--; mmc_blk_rw_try_restart(mq, new_req, mqrq_cur); return; } @@ -1844,7 +1875,7 @@ static void mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *new_req) } } while (req_pending); - mmc_queue_req_free(mq, mq_rq); + mq->qcnt--; } void mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) @@ -1865,23 +1896,54 @@ void mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) goto out; } - if (req && req_op(req) == REQ_OP_DISCARD) { - /* complete ongoing async transfer before issuing discard */ - if (mq->qcnt) - mmc_blk_issue_rw_rq(mq, NULL); - mmc_blk_issue_discard_rq(mq, req); - } else if (req && req_op(req) == REQ_OP_SECURE_ERASE) { - /* complete ongoing async transfer before issuing secure erase*/ - if (mq->qcnt) - mmc_blk_issue_rw_rq(mq, NULL); - mmc_blk_issue_secdiscard_rq(mq, req); - } else if (req && req_op(req) == REQ_OP_FLUSH) { - /* complete ongoing async transfer before issuing flush */ - if (mq->qcnt) - mmc_blk_issue_rw_rq(mq, NULL); - mmc_blk_issue_flush(mq, req); + if (req) { + switch (req_op(req)) { + case REQ_OP_DRV_IN: + case REQ_OP_DRV_OUT: + /* + * Complete ongoing async transfer before issuing + * ioctl()s + */ + if (mq->qcnt) + mmc_blk_issue_rw_rq(mq, NULL); + mmc_blk_issue_drv_op(mq, req); + break; + case REQ_OP_DISCARD: + /* + * Complete ongoing async transfer before issuing + * discard. + */ + if (mq->qcnt) + mmc_blk_issue_rw_rq(mq, NULL); + mmc_blk_issue_discard_rq(mq, req); + break; + case REQ_OP_SECURE_ERASE: + /* + * Complete ongoing async transfer before issuing + * secure erase. + */ + if (mq->qcnt) + mmc_blk_issue_rw_rq(mq, NULL); + mmc_blk_issue_secdiscard_rq(mq, req); + break; + case REQ_OP_FLUSH: + /* + * Complete ongoing async transfer before issuing + * flush. + */ + if (mq->qcnt) + mmc_blk_issue_rw_rq(mq, NULL); + mmc_blk_issue_flush(mq, req); + break; + default: + /* Normal request, just issue it */ + mmc_blk_issue_rw_rq(mq, req); + card->host->context_info.is_waiting_last_req = false; + break; + } } else { - mmc_blk_issue_rw_rq(mq, req); + /* No request, flushing the pipeline with NULL */ + mmc_blk_issue_rw_rq(mq, NULL); card->host->context_info.is_waiting_last_req = false; } @@ -2166,7 +2228,6 @@ static int mmc_blk_probe(struct mmc_card *card) { struct mmc_blk_data *md, *part_md; char cap_str[10]; - int ret; /* * Check that the card supports the command class(es) we need. @@ -2176,15 +2237,9 @@ static int mmc_blk_probe(struct mmc_card *card) mmc_fixup_device(card, mmc_blk_fixups); - ret = mmc_queue_alloc_shared_queue(card); - if (ret) - return ret; - md = mmc_blk_alloc(card); - if (IS_ERR(md)) { - mmc_queue_free_shared_queue(card); + if (IS_ERR(md)) return PTR_ERR(md); - } string_get_size((u64)get_capacity(md->disk), 512, STRING_UNITS_2, cap_str, sizeof(cap_str)); @@ -2222,7 +2277,6 @@ static int mmc_blk_probe(struct mmc_card *card) out: mmc_blk_remove_parts(card, md); mmc_blk_remove_req(md); - mmc_queue_free_shared_queue(card); return 0; } @@ -2240,7 +2294,6 @@ static void mmc_blk_remove(struct mmc_card *card) pm_runtime_put_noidle(&card->dev); mmc_blk_remove_req(md); dev_set_drvdata(&card->dev, NULL); - mmc_queue_free_shared_queue(card); } static int _mmc_blk_suspend(struct mmc_card *card) diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 82c45ddfa202..ad8caf49c038 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -2597,6 +2597,8 @@ EXPORT_SYMBOL(mmc_set_blockcount); static void mmc_hw_reset_for_init(struct mmc_host *host) { + mmc_pwrseq_reset(host); + if (!(host->caps & MMC_CAP_HW_RESET) || !host->ops->hw_reset) return; host->ops->hw_reset(host); diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index 3f8c85d5aa09..1503412f826c 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -30,6 +30,7 @@ #include "host.h" #include "slot-gpio.h" #include "pwrseq.h" +#include "sdio_ops.h" #define cls_dev_to_mmc_host(d) container_of(d, struct mmc_host, class_dev) @@ -176,19 +177,17 @@ static void mmc_retune_timer(unsigned long data) */ int mmc_of_parse(struct mmc_host *host) { - struct device_node *np; + struct device *dev = host->parent; u32 bus_width; int ret; bool cd_cap_invert, cd_gpio_invert = false; bool ro_cap_invert, ro_gpio_invert = false; - if (!host->parent || !host->parent->of_node) + if (!dev || !dev_fwnode(dev)) return 0; - np = host->parent->of_node; - /* "bus-width" is translated to MMC_CAP_*_BIT_DATA flags */ - if (of_property_read_u32(np, "bus-width", &bus_width) < 0) { + if (device_property_read_u32(dev, "bus-width", &bus_width) < 0) { dev_dbg(host->parent, "\"bus-width\" property is missing, assuming 1 bit.\n"); bus_width = 1; @@ -210,7 +209,7 @@ int mmc_of_parse(struct mmc_host *host) } /* f_max is obtained from the optional "max-frequency" property */ - of_property_read_u32(np, "max-frequency", &host->f_max); + device_property_read_u32(dev, "max-frequency", &host->f_max); /* * Configure CD and WP pins. They are both by default active low to @@ -225,12 +224,12 @@ int mmc_of_parse(struct mmc_host *host) */ /* Parse Card Detection */ - if (of_property_read_bool(np, "non-removable")) { + if (device_property_read_bool(dev, "non-removable")) { host->caps |= MMC_CAP_NONREMOVABLE; } else { - cd_cap_invert = of_property_read_bool(np, "cd-inverted"); + cd_cap_invert = device_property_read_bool(dev, "cd-inverted"); - if (of_property_read_bool(np, "broken-cd")) + if (device_property_read_bool(dev, "broken-cd")) host->caps |= MMC_CAP_NEEDS_POLL; ret = mmc_gpiod_request_cd(host, "cd", 0, true, @@ -256,7 +255,7 @@ int mmc_of_parse(struct mmc_host *host) } /* Parse Write Protection */ - ro_cap_invert = of_property_read_bool(np, "wp-inverted"); + ro_cap_invert = device_property_read_bool(dev, "wp-inverted"); ret = mmc_gpiod_request_ro(host, "wp", 0, false, 0, &ro_gpio_invert); if (!ret) @@ -264,64 +263,64 @@ int mmc_of_parse(struct mmc_host *host) else if (ret != -ENOENT && ret != -ENOSYS) return ret; - if (of_property_read_bool(np, "disable-wp")) + if (device_property_read_bool(dev, "disable-wp")) host->caps2 |= MMC_CAP2_NO_WRITE_PROTECT; /* See the comment on CD inversion above */ if (ro_cap_invert ^ ro_gpio_invert) host->caps2 |= MMC_CAP2_RO_ACTIVE_HIGH; - if (of_property_read_bool(np, "cap-sd-highspeed")) + if (device_property_read_bool(dev, "cap-sd-highspeed")) host->caps |= MMC_CAP_SD_HIGHSPEED; - if (of_property_read_bool(np, "cap-mmc-highspeed")) + if (device_property_read_bool(dev, "cap-mmc-highspeed")) host->caps |= MMC_CAP_MMC_HIGHSPEED; - if (of_property_read_bool(np, "sd-uhs-sdr12")) + if (device_property_read_bool(dev, "sd-uhs-sdr12")) host->caps |= MMC_CAP_UHS_SDR12; - if (of_property_read_bool(np, "sd-uhs-sdr25")) + if (device_property_read_bool(dev, "sd-uhs-sdr25")) host->caps |= MMC_CAP_UHS_SDR25; - if (of_property_read_bool(np, "sd-uhs-sdr50")) + if (device_property_read_bool(dev, "sd-uhs-sdr50")) host->caps |= MMC_CAP_UHS_SDR50; - if (of_property_read_bool(np, "sd-uhs-sdr104")) + if (device_property_read_bool(dev, "sd-uhs-sdr104")) host->caps |= MMC_CAP_UHS_SDR104; - if (of_property_read_bool(np, "sd-uhs-ddr50")) + if (device_property_read_bool(dev, "sd-uhs-ddr50")) host->caps |= MMC_CAP_UHS_DDR50; - if (of_property_read_bool(np, "cap-power-off-card")) + if (device_property_read_bool(dev, "cap-power-off-card")) host->caps |= MMC_CAP_POWER_OFF_CARD; - if (of_property_read_bool(np, "cap-mmc-hw-reset")) + if (device_property_read_bool(dev, "cap-mmc-hw-reset")) host->caps |= MMC_CAP_HW_RESET; - if (of_property_read_bool(np, "cap-sdio-irq")) + if (device_property_read_bool(dev, "cap-sdio-irq")) host->caps |= MMC_CAP_SDIO_IRQ; - if (of_property_read_bool(np, "full-pwr-cycle")) + if (device_property_read_bool(dev, "full-pwr-cycle")) host->caps2 |= MMC_CAP2_FULL_PWR_CYCLE; - if (of_property_read_bool(np, "keep-power-in-suspend")) + if (device_property_read_bool(dev, "keep-power-in-suspend")) host->pm_caps |= MMC_PM_KEEP_POWER; - if (of_property_read_bool(np, "wakeup-source") || - of_property_read_bool(np, "enable-sdio-wakeup")) /* legacy */ + if (device_property_read_bool(dev, "wakeup-source") || + device_property_read_bool(dev, "enable-sdio-wakeup")) /* legacy */ host->pm_caps |= MMC_PM_WAKE_SDIO_IRQ; - if (of_property_read_bool(np, "mmc-ddr-3_3v")) + if (device_property_read_bool(dev, "mmc-ddr-3_3v")) host->caps |= MMC_CAP_3_3V_DDR; - if (of_property_read_bool(np, "mmc-ddr-1_8v")) + if (device_property_read_bool(dev, "mmc-ddr-1_8v")) host->caps |= MMC_CAP_1_8V_DDR; - if (of_property_read_bool(np, "mmc-ddr-1_2v")) + if (device_property_read_bool(dev, "mmc-ddr-1_2v")) host->caps |= MMC_CAP_1_2V_DDR; - if (of_property_read_bool(np, "mmc-hs200-1_8v")) + if (device_property_read_bool(dev, "mmc-hs200-1_8v")) host->caps2 |= MMC_CAP2_HS200_1_8V_SDR; - if (of_property_read_bool(np, "mmc-hs200-1_2v")) + if (device_property_read_bool(dev, "mmc-hs200-1_2v")) host->caps2 |= MMC_CAP2_HS200_1_2V_SDR; - if (of_property_read_bool(np, "mmc-hs400-1_8v")) + if (device_property_read_bool(dev, "mmc-hs400-1_8v")) host->caps2 |= MMC_CAP2_HS400_1_8V | MMC_CAP2_HS200_1_8V_SDR; - if (of_property_read_bool(np, "mmc-hs400-1_2v")) + if (device_property_read_bool(dev, "mmc-hs400-1_2v")) host->caps2 |= MMC_CAP2_HS400_1_2V | MMC_CAP2_HS200_1_2V_SDR; - if (of_property_read_bool(np, "mmc-hs400-enhanced-strobe")) + if (device_property_read_bool(dev, "mmc-hs400-enhanced-strobe")) host->caps2 |= MMC_CAP2_HS400_ES; - if (of_property_read_bool(np, "no-sdio")) + if (device_property_read_bool(dev, "no-sdio")) host->caps2 |= MMC_CAP2_NO_SDIO; - if (of_property_read_bool(np, "no-sd")) + if (device_property_read_bool(dev, "no-sd")) host->caps2 |= MMC_CAP2_NO_SD; - if (of_property_read_bool(np, "no-mmc")) + if (device_property_read_bool(dev, "no-mmc")) host->caps2 |= MMC_CAP2_NO_MMC; - host->dsr_req = !of_property_read_u32(np, "dsr", &host->dsr); + host->dsr_req = !device_property_read_u32(dev, "dsr", &host->dsr); if (host->dsr_req && (host->dsr & ~0xffff)) { dev_err(host->parent, "device tree specified broken value for DSR: 0x%x, ignoring\n", @@ -379,6 +378,7 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev) spin_lock_init(&host->lock); init_waitqueue_head(&host->wq); INIT_DELAYED_WORK(&host->detect, mmc_rescan); + INIT_DELAYED_WORK(&host->sdio_irq_work, sdio_irq_work); setup_timer(&host->retune_timer, mmc_retune_timer, (unsigned long)host); /* diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 2c87dede5841..e3b6bea98fac 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -27,6 +27,7 @@ #include "mmc_ops.h" #include "quirks.h" #include "sd_ops.h" +#include "pwrseq.h" #define DEFAULT_CMD6_TIMEOUT_MS 500 @@ -2127,6 +2128,7 @@ static int mmc_reset(struct mmc_host *host) } else { /* Do a brute force power cycle */ mmc_power_cycle(host, card->ocr); + mmc_pwrseq_reset(host); } return mmc_init_card(host, card->ocr, card); } diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c index 78f75f00efc5..ae1fc4818240 100644 --- a/drivers/mmc/core/mmc_ops.c +++ b/drivers/mmc/core/mmc_ops.c @@ -54,7 +54,7 @@ static const u8 tuning_blk_pattern_8bit[] = { 0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, }; -int mmc_send_status(struct mmc_card *card, u32 *status) +int __mmc_send_status(struct mmc_card *card, u32 *status, unsigned int retries) { int err; struct mmc_command cmd = {}; @@ -64,7 +64,7 @@ int mmc_send_status(struct mmc_card *card, u32 *status) cmd.arg = card->rca << 16; cmd.flags = MMC_RSP_SPI_R2 | MMC_RSP_R1 | MMC_CMD_AC; - err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES); + err = mmc_wait_for_cmd(card->host, &cmd, retries); if (err) return err; @@ -76,6 +76,12 @@ int mmc_send_status(struct mmc_card *card, u32 *status) return 0; } +EXPORT_SYMBOL_GPL(__mmc_send_status); + +int mmc_send_status(struct mmc_card *card, u32 *status) +{ + return __mmc_send_status(card, status, MMC_CMD_RETRIES); +} static int _mmc_select_card(struct mmc_host *host, struct mmc_card *card) { diff --git a/drivers/mmc/core/mmc_ops.h b/drivers/mmc/core/mmc_ops.h index 978bd2e60f8a..b8d05529a6ce 100644 --- a/drivers/mmc/core/mmc_ops.h +++ b/drivers/mmc/core/mmc_ops.h @@ -25,6 +25,7 @@ int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr); int mmc_all_send_cid(struct mmc_host *host, u32 *cid); int mmc_set_relative_addr(struct mmc_card *card); int mmc_send_csd(struct mmc_card *card, u32 *csd); +int __mmc_send_status(struct mmc_card *card, u32 *status, unsigned int retries); int mmc_send_status(struct mmc_card *card, u32 *status); int mmc_send_cid(struct mmc_host *host, u32 *cid); int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp); diff --git a/drivers/mmc/core/mmc_test.c b/drivers/mmc/core/mmc_test.c index fd1b4b8510b9..7a304a6e5bf1 100644 --- a/drivers/mmc/core/mmc_test.c +++ b/drivers/mmc/core/mmc_test.c @@ -3220,8 +3220,6 @@ static int __mmc_test_register_dbgfs_file(struct mmc_card *card, df = kmalloc(sizeof(*df), GFP_KERNEL); if (!df) { debugfs_remove(file); - dev_err(&card->dev, - "Can't allocate memory for internal usage.\n"); return -ENOMEM; } diff --git a/drivers/mmc/core/pwrseq.c b/drivers/mmc/core/pwrseq.c index 9386c4771814..e3ad30fa8307 100644 --- a/drivers/mmc/core/pwrseq.c +++ b/drivers/mmc/core/pwrseq.c @@ -76,6 +76,14 @@ void mmc_pwrseq_power_off(struct mmc_host *host) pwrseq->ops->power_off(host); } +void mmc_pwrseq_reset(struct mmc_host *host) +{ + struct mmc_pwrseq *pwrseq = host->pwrseq; + + if (pwrseq && pwrseq->ops->reset) + pwrseq->ops->reset(host); +} + void mmc_pwrseq_free(struct mmc_host *host) { struct mmc_pwrseq *pwrseq = host->pwrseq; diff --git a/drivers/mmc/core/pwrseq.h b/drivers/mmc/core/pwrseq.h index 39c911aa6ebb..819386f4ec61 100644 --- a/drivers/mmc/core/pwrseq.h +++ b/drivers/mmc/core/pwrseq.h @@ -18,6 +18,7 @@ struct mmc_pwrseq_ops { void (*pre_power_on)(struct mmc_host *host); void (*post_power_on)(struct mmc_host *host); void (*power_off)(struct mmc_host *host); + void (*reset)(struct mmc_host *host); }; struct mmc_pwrseq { @@ -36,6 +37,7 @@ int mmc_pwrseq_alloc(struct mmc_host *host); void mmc_pwrseq_pre_power_on(struct mmc_host *host); void mmc_pwrseq_post_power_on(struct mmc_host *host); void mmc_pwrseq_power_off(struct mmc_host *host); +void mmc_pwrseq_reset(struct mmc_host *host); void mmc_pwrseq_free(struct mmc_host *host); #else @@ -49,6 +51,7 @@ static inline int mmc_pwrseq_alloc(struct mmc_host *host) { return 0; } static inline void mmc_pwrseq_pre_power_on(struct mmc_host *host) {} static inline void mmc_pwrseq_post_power_on(struct mmc_host *host) {} static inline void mmc_pwrseq_power_off(struct mmc_host *host) {} +static inline void mmc_pwrseq_reset(struct mmc_host *host) {} static inline void mmc_pwrseq_free(struct mmc_host *host) {} #endif diff --git a/drivers/mmc/core/pwrseq_emmc.c b/drivers/mmc/core/pwrseq_emmc.c index adc9c0c614fb..efb8a7965dd4 100644 --- a/drivers/mmc/core/pwrseq_emmc.c +++ b/drivers/mmc/core/pwrseq_emmc.c @@ -56,7 +56,7 @@ static int mmc_pwrseq_emmc_reset_nb(struct notifier_block *this, } static const struct mmc_pwrseq_ops mmc_pwrseq_emmc_ops = { - .post_power_on = mmc_pwrseq_emmc_reset, + .reset = mmc_pwrseq_emmc_reset, }; static int mmc_pwrseq_emmc_probe(struct platform_device *pdev) diff --git a/drivers/mmc/core/queue.c b/drivers/mmc/core/queue.c index 5c37b6be3e7b..4bf9978b707a 100644 --- a/drivers/mmc/core/queue.c +++ b/drivers/mmc/core/queue.c @@ -40,35 +40,6 @@ static int mmc_prep_request(struct request_queue *q, struct request *req) return BLKPREP_OK; } -struct mmc_queue_req *mmc_queue_req_find(struct mmc_queue *mq, - struct request *req) -{ - struct mmc_queue_req *mqrq; - int i = ffz(mq->qslots); - - if (i >= mq->qdepth) - return NULL; - - mqrq = &mq->mqrq[i]; - WARN_ON(mqrq->req || mq->qcnt >= mq->qdepth || - test_bit(mqrq->task_id, &mq->qslots)); - mqrq->req = req; - mq->qcnt += 1; - __set_bit(mqrq->task_id, &mq->qslots); - - return mqrq; -} - -void mmc_queue_req_free(struct mmc_queue *mq, - struct mmc_queue_req *mqrq) -{ - WARN_ON(!mqrq->req || mq->qcnt < 1 || - !test_bit(mqrq->task_id, &mq->qslots)); - mqrq->req = NULL; - mq->qcnt -= 1; - __clear_bit(mqrq->task_id, &mq->qslots); -} - static int mmc_queue_thread(void *d) { struct mmc_queue *mq = d; @@ -149,11 +120,11 @@ static void mmc_request_fn(struct request_queue *q) wake_up_process(mq->thread); } -static struct scatterlist *mmc_alloc_sg(int sg_len) +static struct scatterlist *mmc_alloc_sg(int sg_len, gfp_t gfp) { struct scatterlist *sg; - sg = kmalloc_array(sg_len, sizeof(*sg), GFP_KERNEL); + sg = kmalloc_array(sg_len, sizeof(*sg), gfp); if (sg) sg_init_table(sg, sg_len); @@ -179,86 +150,11 @@ static void mmc_queue_setup_discard(struct request_queue *q, queue_flag_set_unlocked(QUEUE_FLAG_SECERASE, q); } -static void mmc_queue_req_free_bufs(struct mmc_queue_req *mqrq) -{ - kfree(mqrq->bounce_sg); - mqrq->bounce_sg = NULL; - - kfree(mqrq->sg); - mqrq->sg = NULL; - - kfree(mqrq->bounce_buf); - mqrq->bounce_buf = NULL; -} - -static void mmc_queue_reqs_free_bufs(struct mmc_queue_req *mqrq, int qdepth) -{ - int i; - - for (i = 0; i < qdepth; i++) - mmc_queue_req_free_bufs(&mqrq[i]); -} - -static void mmc_queue_free_mqrqs(struct mmc_queue_req *mqrq, int qdepth) -{ - mmc_queue_reqs_free_bufs(mqrq, qdepth); - kfree(mqrq); -} - -static struct mmc_queue_req *mmc_queue_alloc_mqrqs(int qdepth) -{ - struct mmc_queue_req *mqrq; - int i; - - mqrq = kcalloc(qdepth, sizeof(*mqrq), GFP_KERNEL); - if (mqrq) { - for (i = 0; i < qdepth; i++) - mqrq[i].task_id = i; - } - - return mqrq; -} - -#ifdef CONFIG_MMC_BLOCK_BOUNCE -static int mmc_queue_alloc_bounce_bufs(struct mmc_queue_req *mqrq, int qdepth, - unsigned int bouncesz) -{ - int i; - - for (i = 0; i < qdepth; i++) { - mqrq[i].bounce_buf = kmalloc(bouncesz, GFP_KERNEL); - if (!mqrq[i].bounce_buf) - return -ENOMEM; - - mqrq[i].sg = mmc_alloc_sg(1); - if (!mqrq[i].sg) - return -ENOMEM; - - mqrq[i].bounce_sg = mmc_alloc_sg(bouncesz / 512); - if (!mqrq[i].bounce_sg) - return -ENOMEM; - } - - return 0; -} - -static bool mmc_queue_alloc_bounce(struct mmc_queue_req *mqrq, int qdepth, - unsigned int bouncesz) -{ - int ret; - - ret = mmc_queue_alloc_bounce_bufs(mqrq, qdepth, bouncesz); - if (ret) - mmc_queue_reqs_free_bufs(mqrq, qdepth); - - return !ret; -} - static unsigned int mmc_queue_calc_bouncesz(struct mmc_host *host) { unsigned int bouncesz = MMC_QUEUE_BOUNCESZ; - if (host->max_segs != 1) + if (host->max_segs != 1 || (host->caps & MMC_CAP_NO_BOUNCE_BUFF)) return 0; if (bouncesz > host->max_req_size) @@ -273,84 +169,58 @@ static unsigned int mmc_queue_calc_bouncesz(struct mmc_host *host) return bouncesz; } -#else -static inline bool mmc_queue_alloc_bounce(struct mmc_queue_req *mqrq, - int qdepth, unsigned int bouncesz) -{ - return false; -} - -static unsigned int mmc_queue_calc_bouncesz(struct mmc_host *host) -{ - return 0; -} -#endif -static int mmc_queue_alloc_sgs(struct mmc_queue_req *mqrq, int qdepth, - int max_segs) +/** + * mmc_init_request() - initialize the MMC-specific per-request data + * @q: the request queue + * @req: the request + * @gfp: memory allocation policy + */ +static int mmc_init_request(struct request_queue *q, struct request *req, + gfp_t gfp) { - int i; + struct mmc_queue_req *mq_rq = req_to_mmc_queue_req(req); + struct mmc_queue *mq = q->queuedata; + struct mmc_card *card = mq->card; + struct mmc_host *host = card->host; - for (i = 0; i < qdepth; i++) { - mqrq[i].sg = mmc_alloc_sg(max_segs); - if (!mqrq[i].sg) + if (card->bouncesz) { + mq_rq->bounce_buf = kmalloc(card->bouncesz, gfp); + if (!mq_rq->bounce_buf) + return -ENOMEM; + if (card->bouncesz > 512) { + mq_rq->sg = mmc_alloc_sg(1, gfp); + if (!mq_rq->sg) + return -ENOMEM; + mq_rq->bounce_sg = mmc_alloc_sg(card->bouncesz / 512, + gfp); + if (!mq_rq->bounce_sg) + return -ENOMEM; + } + } else { + mq_rq->bounce_buf = NULL; + mq_rq->bounce_sg = NULL; + mq_rq->sg = mmc_alloc_sg(host->max_segs, gfp); + if (!mq_rq->sg) return -ENOMEM; } return 0; } -void mmc_queue_free_shared_queue(struct mmc_card *card) -{ - if (card->mqrq) { - mmc_queue_free_mqrqs(card->mqrq, card->qdepth); - card->mqrq = NULL; - } -} - -static int __mmc_queue_alloc_shared_queue(struct mmc_card *card, int qdepth) +static void mmc_exit_request(struct request_queue *q, struct request *req) { - struct mmc_host *host = card->host; - struct mmc_queue_req *mqrq; - unsigned int bouncesz; - int ret = 0; - - if (card->mqrq) - return -EINVAL; + struct mmc_queue_req *mq_rq = req_to_mmc_queue_req(req); - mqrq = mmc_queue_alloc_mqrqs(qdepth); - if (!mqrq) - return -ENOMEM; + /* It is OK to kfree(NULL) so this will be smooth */ + kfree(mq_rq->bounce_sg); + mq_rq->bounce_sg = NULL; - card->mqrq = mqrq; - card->qdepth = qdepth; + kfree(mq_rq->bounce_buf); + mq_rq->bounce_buf = NULL; - bouncesz = mmc_queue_calc_bouncesz(host); - - if (bouncesz && !mmc_queue_alloc_bounce(mqrq, qdepth, bouncesz)) { - bouncesz = 0; - pr_warn("%s: unable to allocate bounce buffers\n", - mmc_card_name(card)); - } - - card->bouncesz = bouncesz; - - if (!bouncesz) { - ret = mmc_queue_alloc_sgs(mqrq, qdepth, host->max_segs); - if (ret) - goto out_err; - } - - return ret; - -out_err: - mmc_queue_free_shared_queue(card); - return ret; -} - -int mmc_queue_alloc_shared_queue(struct mmc_card *card) -{ - return __mmc_queue_alloc_shared_queue(card, 2); + kfree(mq_rq->sg); + mq_rq->sg = NULL; } /** @@ -373,13 +243,21 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, limit = (u64)dma_max_pfn(mmc_dev(host)) << PAGE_SHIFT; mq->card = card; - mq->queue = blk_init_queue(mmc_request_fn, lock); + mq->queue = blk_alloc_queue(GFP_KERNEL); if (!mq->queue) return -ENOMEM; - - mq->mqrq = card->mqrq; - mq->qdepth = card->qdepth; + mq->queue->queue_lock = lock; + mq->queue->request_fn = mmc_request_fn; + mq->queue->init_rq_fn = mmc_init_request; + mq->queue->exit_rq_fn = mmc_exit_request; + mq->queue->cmd_size = sizeof(struct mmc_queue_req); mq->queue->queuedata = mq; + mq->qcnt = 0; + ret = blk_init_allocated_queue(mq->queue); + if (ret) { + blk_cleanup_queue(mq->queue); + return ret; + } blk_queue_prep_rq(mq->queue, mmc_prep_request); queue_flag_set_unlocked(QUEUE_FLAG_NONROT, mq->queue); @@ -387,6 +265,7 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, if (mmc_can_erase(card)) mmc_queue_setup_discard(mq->queue, card); + card->bouncesz = mmc_queue_calc_bouncesz(host); if (card->bouncesz) { blk_queue_bounce_limit(mq->queue, BLK_BOUNCE_ANY); blk_queue_max_hw_sectors(mq->queue, card->bouncesz / 512); @@ -413,7 +292,6 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, return 0; cleanup_queue: - mq->mqrq = NULL; blk_cleanup_queue(mq->queue); return ret; } @@ -434,8 +312,8 @@ void mmc_cleanup_queue(struct mmc_queue *mq) q->queuedata = NULL; blk_start_queue(q); spin_unlock_irqrestore(q->queue_lock, flags); + blk_cleanup_queue(mq->queue); - mq->mqrq = NULL; mq->card = NULL; } EXPORT_SYMBOL(mmc_cleanup_queue); @@ -492,12 +370,13 @@ unsigned int mmc_queue_map_sg(struct mmc_queue *mq, struct mmc_queue_req *mqrq) unsigned int sg_len; size_t buflen; struct scatterlist *sg; + struct request *req = mmc_queue_req_to_req(mqrq); int i; if (!mqrq->bounce_buf) - return blk_rq_map_sg(mq->queue, mqrq->req, mqrq->sg); + return blk_rq_map_sg(mq->queue, req, mqrq->sg); - sg_len = blk_rq_map_sg(mq->queue, mqrq->req, mqrq->bounce_sg); + sg_len = blk_rq_map_sg(mq->queue, req, mqrq->bounce_sg); mqrq->bounce_sg_len = sg_len; @@ -519,7 +398,7 @@ void mmc_queue_bounce_pre(struct mmc_queue_req *mqrq) if (!mqrq->bounce_buf) return; - if (rq_data_dir(mqrq->req) != WRITE) + if (rq_data_dir(mmc_queue_req_to_req(mqrq)) != WRITE) return; sg_copy_to_buffer(mqrq->bounce_sg, mqrq->bounce_sg_len, @@ -535,7 +414,7 @@ void mmc_queue_bounce_post(struct mmc_queue_req *mqrq) if (!mqrq->bounce_buf) return; - if (rq_data_dir(mqrq->req) != READ) + if (rq_data_dir(mmc_queue_req_to_req(mqrq)) != READ) return; sg_copy_from_buffer(mqrq->bounce_sg, mqrq->bounce_sg_len, diff --git a/drivers/mmc/core/queue.h b/drivers/mmc/core/queue.h index 871796c3f406..361b46408e0f 100644 --- a/drivers/mmc/core/queue.h +++ b/drivers/mmc/core/queue.h @@ -3,19 +3,25 @@ #include <linux/types.h> #include <linux/blkdev.h> +#include <linux/blk-mq.h> #include <linux/mmc/core.h> #include <linux/mmc/host.h> -static inline bool mmc_req_is_special(struct request *req) +static inline struct mmc_queue_req *req_to_mmc_queue_req(struct request *rq) { - return req && - (req_op(req) == REQ_OP_FLUSH || - req_op(req) == REQ_OP_DISCARD || - req_op(req) == REQ_OP_SECURE_ERASE); + return blk_mq_rq_to_pdu(rq); +} + +struct mmc_queue_req; + +static inline struct request *mmc_queue_req_to_req(struct mmc_queue_req *mqr) +{ + return blk_mq_rq_from_pdu(mqr); } struct task_struct; struct mmc_blk_data; +struct mmc_blk_ioc_data; struct mmc_blk_request { struct mmc_request mrq; @@ -26,15 +32,27 @@ struct mmc_blk_request { int retune_retry_done; }; +/** + * enum mmc_drv_op - enumerates the operations in the mmc_queue_req + * @MMC_DRV_OP_IOCTL: ioctl operation + * @MMC_DRV_OP_BOOT_WP: write protect boot partitions + */ +enum mmc_drv_op { + MMC_DRV_OP_IOCTL, + MMC_DRV_OP_BOOT_WP, +}; + struct mmc_queue_req { - struct request *req; struct mmc_blk_request brq; struct scatterlist *sg; char *bounce_buf; struct scatterlist *bounce_sg; unsigned int bounce_sg_len; struct mmc_async_req areq; - int task_id; + enum mmc_drv_op drv_op; + int drv_op_result; + struct mmc_blk_ioc_data **idata; + unsigned int ioc_count; }; struct mmc_queue { @@ -45,14 +63,15 @@ struct mmc_queue { bool asleep; struct mmc_blk_data *blkdata; struct request_queue *queue; - struct mmc_queue_req *mqrq; - int qdepth; + /* + * FIXME: this counter is not a very reliable way of keeping + * track of how many requests that are ongoing. Switch to just + * letting the block core keep track of requests and per-request + * associated mmc_queue_req data. + */ int qcnt; - unsigned long qslots; }; -extern int mmc_queue_alloc_shared_queue(struct mmc_card *card); -extern void mmc_queue_free_shared_queue(struct mmc_card *card); extern int mmc_init_queue(struct mmc_queue *, struct mmc_card *, spinlock_t *, const char *); extern void mmc_cleanup_queue(struct mmc_queue *); @@ -66,8 +85,4 @@ extern void mmc_queue_bounce_post(struct mmc_queue_req *); extern int mmc_access_rpmb(struct mmc_queue *); -extern struct mmc_queue_req *mmc_queue_req_find(struct mmc_queue *, - struct request *); -extern void mmc_queue_req_free(struct mmc_queue *, struct mmc_queue_req *); - #endif diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index d109634fbfce..1d7542daecbe 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -294,12 +294,8 @@ static int mmc_read_switch(struct mmc_card *card) err = -EIO; status = kmalloc(64, GFP_KERNEL); - if (!status) { - pr_err("%s: could not allocate a buffer for " - "switch capabilities.\n", - mmc_hostname(card->host)); + if (!status) return -ENOMEM; - } /* * Find out the card's support bits with a mode 0 operation. @@ -359,11 +355,8 @@ int mmc_sd_switch_hs(struct mmc_card *card) return 0; status = kmalloc(64, GFP_KERNEL); - if (!status) { - pr_err("%s: could not allocate a buffer for " - "switch capabilities.\n", mmc_hostname(card->host)); + if (!status) return -ENOMEM; - } err = mmc_sd_switch(card, 1, 0, 1, status); if (err) @@ -596,11 +589,8 @@ static int mmc_sd_init_uhs_card(struct mmc_card *card) return 0; status = kmalloc(64, GFP_KERNEL); - if (!status) { - pr_err("%s: could not allocate a buffer for " - "switch capabilities.\n", mmc_hostname(card->host)); + if (!status) return -ENOMEM; - } /* Set 4-bit bus width */ if ((card->host->caps & MMC_CAP_4_BIT_DATA) && diff --git a/drivers/mmc/core/sdio_irq.c b/drivers/mmc/core/sdio_irq.c index 6d4b72080d51..c771843e4c15 100644 --- a/drivers/mmc/core/sdio_irq.c +++ b/drivers/mmc/core/sdio_irq.c @@ -95,12 +95,30 @@ static int process_sdio_pending_irqs(struct mmc_host *host) void sdio_run_irqs(struct mmc_host *host) { mmc_claim_host(host); - host->sdio_irq_pending = true; - process_sdio_pending_irqs(host); + if (host->sdio_irqs) { + host->sdio_irq_pending = true; + process_sdio_pending_irqs(host); + if (host->ops->ack_sdio_irq) + host->ops->ack_sdio_irq(host); + } mmc_release_host(host); } EXPORT_SYMBOL_GPL(sdio_run_irqs); +void sdio_irq_work(struct work_struct *work) +{ + struct mmc_host *host = + container_of(work, struct mmc_host, sdio_irq_work.work); + + sdio_run_irqs(host); +} + +void sdio_signal_irq(struct mmc_host *host) +{ + queue_delayed_work(system_wq, &host->sdio_irq_work, 0); +} +EXPORT_SYMBOL_GPL(sdio_signal_irq); + static int sdio_irq_thread(void *_host) { struct mmc_host *host = _host; diff --git a/drivers/mmc/core/sdio_ops.h b/drivers/mmc/core/sdio_ops.h index ee35cb4d170e..96945cafbf0b 100644 --- a/drivers/mmc/core/sdio_ops.h +++ b/drivers/mmc/core/sdio_ops.h @@ -17,6 +17,7 @@ struct mmc_host; struct mmc_card; +struct work_struct; int mmc_send_io_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr); int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn, @@ -25,6 +26,7 @@ int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn, unsigned addr, int incr_addr, u8 *buf, unsigned blocks, unsigned blksz); int sdio_reset(struct mmc_host *host); unsigned int mmc_align_data_size(struct mmc_card *card, unsigned int sz); +void sdio_irq_work(struct work_struct *work); static inline bool sdio_is_io_busy(u32 opcode, u32 arg) { diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index 2db84dd664d7..5755b69f2f72 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -408,11 +408,11 @@ config MMC_AU1X config MMC_ATMELMCI tristate "Atmel SD/MMC Driver (Multimedia Card Interface)" - depends on AVR32 || ARCH_AT91 + depends on ARCH_AT91 help - This selects the Atmel Multimedia Card Interface driver. If - you have an AT32 (AVR32) or AT91 platform with a Multimedia - Card slot, say Y or M here. + This selects the Atmel Multimedia Card Interface driver. + If you have an AT91 platform with a Multimedia Card slot, + say Y or M here. If unsure, say N. @@ -571,13 +571,13 @@ config MMC_TMIO T7L66XB and also HTC ASIC3 config MMC_SDHI - tristate "SH-Mobile SDHI SD/SDIO controller support" + tristate "Renesas SDHI SD/SDIO controller support" depends on SUPERH || ARM || ARM64 depends on SUPERH || ARCH_RENESAS || COMPILE_TEST select MMC_TMIO_CORE help This provides support for the SDHI SD/SDIO controller found in - SuperH and ARM SH-Mobile SoCs + Renesas SuperH, ARM and ARM64 based SoCs config MMC_CB710 tristate "ENE CB710 MMC/SD Interface support" diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile index 926347c2eeb4..4d4547116311 100644 --- a/drivers/mmc/host/Makefile +++ b/drivers/mmc/host/Makefile @@ -36,9 +36,7 @@ obj-$(CONFIG_MMC_S3C) += s3cmci.o obj-$(CONFIG_MMC_SDRICOH_CS) += sdricoh_cs.o obj-$(CONFIG_MMC_TMIO) += tmio_mmc.o obj-$(CONFIG_MMC_TMIO_CORE) += tmio_mmc_core.o -tmio_mmc_core-y := tmio_mmc_pio.o -tmio_mmc_core-$(subst m,y,$(CONFIG_MMC_SDHI)) += tmio_mmc_dma.o -obj-$(CONFIG_MMC_SDHI) += sh_mobile_sdhi.o +obj-$(CONFIG_MMC_SDHI) += renesas_sdhi_core.o renesas_sdhi_sys_dmac.o obj-$(CONFIG_MMC_CB710) += cb710-mmc.o obj-$(CONFIG_MMC_VIA_SDMMC) += via-sdmmc.o obj-$(CONFIG_SDH_BFIN) += bfin_sdh.o diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c index 388e4a3f13e6..97de2d32ba84 100644 --- a/drivers/mmc/host/atmel-mci.c +++ b/drivers/mmc/host/atmel-mci.c @@ -44,7 +44,7 @@ #include <asm/unaligned.h> /* - * Superset of MCI IP registers integrated in Atmel AVR32 and AT91 Processors + * Superset of MCI IP registers integrated in Atmel AT91 Processor * Registers and bitfields marked with [2] are only available in MCI2 */ @@ -172,13 +172,6 @@ #define atmci_writel(port, reg, value) \ __raw_writel((value), (port)->regs + reg) -/* On AVR chips the Peripheral DMA Controller is not connected to MCI. */ -#ifdef CONFIG_AVR32 -# define ATMCI_PDC_CONNECTED 0 -#else -# define ATMCI_PDC_CONNECTED 1 -#endif - #define AUTOSUSPEND_DELAY 50 #define ATMCI_DATA_ERROR_FLAGS (ATMCI_DCRCE | ATMCI_DTOE | ATMCI_OVRE | ATMCI_UNRE) @@ -667,10 +660,8 @@ atmci_of_init(struct platform_device *pdev) } pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); - if (!pdata) { - dev_err(&pdev->dev, "could not allocate memory for pdata\n"); + if (!pdata) return ERR_PTR(-ENOMEM); - } for_each_child_of_node(np, cnp) { if (of_property_read_u32(cnp, "reg", &slot_id)) { @@ -1549,21 +1540,8 @@ static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, ios->vdd); break; default: - /* - * TODO: None of the currently available AVR32-based - * boards allow MMC power to be turned off. Implement - * power control when this can be tested properly. - * - * We also need to hook this into the clock management - * somehow so that newly inserted cards aren't - * subjected to a fast clock before we have a chance - * to figure out what the maximum rate is. Currently, - * there's no way to avoid this, and there never will - * be for boards that don't support power control. - */ break; } - } static int atmci_get_ro(struct mmc_host *mmc) @@ -2464,7 +2442,7 @@ static void atmci_get_cap(struct atmel_mci *host) "version: 0x%x\n", version); host->caps.has_dma_conf_reg = 0; - host->caps.has_pdc = ATMCI_PDC_CONNECTED; + host->caps.has_pdc = 1; host->caps.has_cfg_reg = 0; host->caps.has_cstor_reg = 0; host->caps.has_highspeed = 0; diff --git a/drivers/mmc/host/bcm2835.c b/drivers/mmc/host/bcm2835.c index 1f343a477b3d..abba9a2a78b8 100644 --- a/drivers/mmc/host/bcm2835.c +++ b/drivers/mmc/host/bcm2835.c @@ -1172,7 +1172,10 @@ static void bcm2835_request(struct mmc_host *mmc, struct mmc_request *mrq) if (mrq->data && !is_power_of_2(mrq->data->blksz)) { dev_err(dev, "unsupported block size (%d bytes)\n", mrq->data->blksz); - mrq->cmd->error = -EINVAL; + + if (mrq->cmd) + mrq->cmd->error = -EINVAL; + mmc_request_done(mmc, mrq); return; } @@ -1194,7 +1197,10 @@ static void bcm2835_request(struct mmc_host *mmc, struct mmc_request *mrq) readl(host->ioaddr + SDCMD) & SDCMD_CMD_MASK, edm); bcm2835_dumpregs(host); - mrq->cmd->error = -EILSEQ; + + if (mrq->cmd) + mrq->cmd->error = -EILSEQ; + bcm2835_finish_request(host); mutex_unlock(&host->mutex); return; @@ -1207,7 +1213,7 @@ static void bcm2835_request(struct mmc_host *mmc, struct mmc_request *mrq) if (!host->use_busy) bcm2835_finish_command(host); } - } else if (bcm2835_send_command(host, mrq->cmd)) { + } else if (mrq->cmd && bcm2835_send_command(host, mrq->cmd)) { if (host->data && host->dma_desc) { /* DMA transfer starts now, PIO starts after irq */ bcm2835_start_dma(host); diff --git a/drivers/mmc/host/cavium.c b/drivers/mmc/host/cavium.c index b8aaf0fdb77c..3686d77c717b 100644 --- a/drivers/mmc/host/cavium.c +++ b/drivers/mmc/host/cavium.c @@ -1035,10 +1035,12 @@ int cvm_mmc_of_slot_probe(struct device *dev, struct cvm_mmc_host *host) * We only have a 3.3v supply, we cannot support any * of the UHS modes. We do support the high speed DDR * modes up to 52MHz. + * + * Disable bounce buffers for max_segs = 1 */ mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED | MMC_CAP_ERASE | MMC_CAP_CMD23 | MMC_CAP_POWER_OFF_CARD | - MMC_CAP_3_3V_DDR; + MMC_CAP_3_3V_DDR | MMC_CAP_NO_BOUNCE_BUFF; if (host->use_sg) mmc->max_segs = 16; diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index e45129f48174..4a0841cee39b 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -1621,16 +1621,10 @@ static void dw_mci_init_card(struct mmc_host *mmc, struct mmc_card *card) if (card->type == MMC_TYPE_SDIO || card->type == MMC_TYPE_SD_COMBO) { - if (!test_bit(DW_MMC_CARD_NO_LOW_PWR, &slot->flags)) { - pm_runtime_get_noresume(mmc->parent); - set_bit(DW_MMC_CARD_NO_LOW_PWR, &slot->flags); - } + set_bit(DW_MMC_CARD_NO_LOW_PWR, &slot->flags); clk_en_a = clk_en_a_old & ~clken_low_pwr; } else { - if (test_bit(DW_MMC_CARD_NO_LOW_PWR, &slot->flags)) { - pm_runtime_put_noidle(mmc->parent); - clear_bit(DW_MMC_CARD_NO_LOW_PWR, &slot->flags); - } + clear_bit(DW_MMC_CARD_NO_LOW_PWR, &slot->flags); clk_en_a = clk_en_a_old | clken_low_pwr; } @@ -1642,9 +1636,8 @@ static void dw_mci_init_card(struct mmc_host *mmc, struct mmc_card *card) } } -static void dw_mci_enable_sdio_irq(struct mmc_host *mmc, int enb) +static void __dw_mci_enable_sdio_irq(struct dw_mci_slot *slot, int enb) { - struct dw_mci_slot *slot = mmc_priv(mmc); struct dw_mci *host = slot->host; unsigned long irqflags; u32 int_mask; @@ -1662,6 +1655,27 @@ static void dw_mci_enable_sdio_irq(struct mmc_host *mmc, int enb) spin_unlock_irqrestore(&host->irq_lock, irqflags); } +static void dw_mci_enable_sdio_irq(struct mmc_host *mmc, int enb) +{ + struct dw_mci_slot *slot = mmc_priv(mmc); + struct dw_mci *host = slot->host; + + __dw_mci_enable_sdio_irq(slot, enb); + + /* Avoid runtime suspending the device when SDIO IRQ is enabled */ + if (enb) + pm_runtime_get_noresume(host->dev); + else + pm_runtime_put_noidle(host->dev); +} + +static void dw_mci_ack_sdio_irq(struct mmc_host *mmc) +{ + struct dw_mci_slot *slot = mmc_priv(mmc); + + __dw_mci_enable_sdio_irq(slot, 1); +} + static int dw_mci_execute_tuning(struct mmc_host *mmc, u32 opcode) { struct dw_mci_slot *slot = mmc_priv(mmc); @@ -1763,6 +1777,7 @@ static const struct mmc_host_ops dw_mci_ops = { .get_cd = dw_mci_get_cd, .hw_reset = dw_mci_hw_reset, .enable_sdio_irq = dw_mci_enable_sdio_irq, + .ack_sdio_irq = dw_mci_ack_sdio_irq, .execute_tuning = dw_mci_execute_tuning, .card_busy = dw_mci_card_busy, .start_signal_voltage_switch = dw_mci_switch_voltage, @@ -2654,7 +2669,8 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id) if (pending & SDMMC_INT_SDIO(slot->sdio_id)) { mci_writel(host, RINTSTS, SDMMC_INT_SDIO(slot->sdio_id)); - mmc_signal_sdio_irq(slot->mmc); + __dw_mci_enable_sdio_irq(slot, 0); + sdio_signal_irq(slot->mmc); } } @@ -2707,8 +2723,8 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id) host->slot[id] = slot; mmc->ops = &dw_mci_ops; - if (of_property_read_u32_array(host->dev->of_node, - "clock-freq-min-max", freq, 2)) { + if (device_property_read_u32_array(host->dev, "clock-freq-min-max", + freq, 2)) { mmc->f_min = DW_MCI_FREQ_MIN; mmc->f_max = DW_MCI_FREQ_MAX; } else { @@ -2755,6 +2771,10 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id) if (ret) goto err_host_allocated; + /* Process SDIO IRQs through the sdio_irq_work. */ + if (mmc->caps & MMC_CAP_SDIO_IRQ) + mmc->caps2 |= MMC_CAP2_SDIO_IRQ_NOTHREAD; + /* Useful defaults if platform data is unset. */ if (host->use_dma == TRANS_MODE_IDMAC) { mmc->max_segs = host->ring_size; @@ -2808,7 +2828,6 @@ static void dw_mci_init_dma(struct dw_mci *host) { int addr_config; struct device *dev = host->dev; - struct device_node *np = dev->of_node; /* * Check tansfer mode from HCON[17:16] @@ -2869,8 +2888,9 @@ static void dw_mci_init_dma(struct dw_mci *host) dev_info(host->dev, "Using internal DMA controller.\n"); } else { /* TRANS_MODE_EDMAC: check dma bindings again */ - if ((of_property_count_strings(np, "dma-names") < 0) || - (!of_find_property(np, "dmas", NULL))) { + if ((device_property_read_string_array(dev, "dma-names", + NULL, 0) < 0) || + !device_property_present(dev, "dmas")) { goto no_dma; } host->dma_ops = &dw_mci_edmac_ops; @@ -2937,7 +2957,6 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host) { struct dw_mci_board *pdata; struct device *dev = host->dev; - struct device_node *np = dev->of_node; const struct dw_mci_drv_data *drv_data = host->drv_data; int ret; u32 clock_frequency; @@ -2954,20 +2973,21 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host) } /* find out number of slots supported */ - of_property_read_u32(np, "num-slots", &pdata->num_slots); + device_property_read_u32(dev, "num-slots", &pdata->num_slots); - if (of_property_read_u32(np, "fifo-depth", &pdata->fifo_depth)) + if (device_property_read_u32(dev, "fifo-depth", &pdata->fifo_depth)) dev_info(dev, "fifo-depth property not found, using value of FIFOTH register as default\n"); - of_property_read_u32(np, "card-detect-delay", &pdata->detect_delay_ms); + device_property_read_u32(dev, "card-detect-delay", + &pdata->detect_delay_ms); - of_property_read_u32(np, "data-addr", &host->data_addr_override); + device_property_read_u32(dev, "data-addr", &host->data_addr_override); - if (of_get_property(np, "fifo-watermark-aligned", NULL)) + if (device_property_present(dev, "fifo-watermark-aligned")) host->wm_aligned = true; - if (!of_property_read_u32(np, "clock-frequency", &clock_frequency)) + if (!device_property_read_u32(dev, "clock-frequency", &clock_frequency)) pdata->bus_hz = clock_frequency; if (drv_data && drv_data->parse_dt) { diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c index 5c1e178fc5f9..5a672a5218ad 100644 --- a/drivers/mmc/host/mtk-sd.c +++ b/drivers/mmc/host/mtk-sd.c @@ -1774,7 +1774,7 @@ static int msdc_drv_remove(struct platform_device *pdev) pm_runtime_disable(host->dev); pm_runtime_put_noidle(host->dev); dma_free_coherent(&pdev->dev, - sizeof(struct mt_gpdma_desc), + 2 * sizeof(struct mt_gpdma_desc), host->dma.gpd, host->dma.gpd_addr); dma_free_coherent(&pdev->dev, MAX_BD_NUM * sizeof(struct mt_bdma_desc), host->dma.bd, host->dma.bd_addr); diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c index c763b404510f..59ab194cb009 100644 --- a/drivers/mmc/host/pxamci.c +++ b/drivers/mmc/host/pxamci.c @@ -702,7 +702,11 @@ static int pxamci_probe(struct platform_device *pdev) pxamci_init_ocr(host); - mmc->caps = 0; + /* + * This architecture used to disable bounce buffers through its + * defconfig, now it is done at runtime as a host property. + */ + mmc->caps = MMC_CAP_NO_BOUNCE_BUFF; host->cmdat = 0; if (!cpu_is_pxa25x()) { mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ; diff --git a/drivers/mmc/host/renesas_sdhi.h b/drivers/mmc/host/renesas_sdhi.h new file mode 100644 index 000000000000..eb3ea15ff92d --- /dev/null +++ b/drivers/mmc/host/renesas_sdhi.h @@ -0,0 +1,39 @@ +/* + * Renesas Mobile SDHI + * + * Copyright (C) 2017 Horms Solutions Ltd., Simon Horman + * Copyright (C) 2017 Renesas Electronics Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef RENESAS_SDHI_H +#define RENESAS_SDHI_H + +#include <linux/platform_device.h> +#include "tmio_mmc.h" + +struct renesas_sdhi_scc { + unsigned long clk_rate; /* clock rate for SDR104 */ + u32 tap; /* sampling clock position for SDR104 */ +}; + +struct renesas_sdhi_of_data { + unsigned long tmio_flags; + u32 tmio_ocr_mask; + unsigned long capabilities; + unsigned long capabilities2; + enum dma_slave_buswidth dma_buswidth; + dma_addr_t dma_rx_offset; + unsigned bus_shift; + int scc_offset; + struct renesas_sdhi_scc *taps; + int taps_num; +}; + +int renesas_sdhi_probe(struct platform_device *pdev, + const struct tmio_mmc_dma_ops *dma_ops); +int renesas_sdhi_remove(struct platform_device *pdev); +#endif diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/renesas_sdhi_core.c index bc6be0dbea39..82150a966391 100644 --- a/drivers/mmc/host/sh_mobile_sdhi.c +++ b/drivers/mmc/host/renesas_sdhi_core.c @@ -1,5 +1,5 @@ /* - * SuperH Mobile SDHI + * Renesas SDHI * * Copyright (C) 2016 Sang Engineering, Wolfram Sang * Copyright (C) 2015-16 Renesas Electronics Corporation @@ -23,8 +23,6 @@ #include <linux/kernel.h> #include <linux/clk.h> #include <linux/slab.h> -#include <linux/mod_devicetable.h> -#include <linux/module.h> #include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/mmc/host.h> @@ -35,6 +33,7 @@ #include <linux/pinctrl/pinctrl-state.h> #include <linux/regulator/consumer.h> +#include "renesas_sdhi.h" #include "tmio_mmc.h" #define EXT_ACC 0xe4 @@ -45,103 +44,9 @@ #define SDHI_VER_GEN3_SD 0xcc10 #define SDHI_VER_GEN3_SDMMC 0xcd10 -#define host_to_priv(host) container_of((host)->pdata, struct sh_mobile_sdhi, mmc_data) +#define host_to_priv(host) container_of((host)->pdata, struct renesas_sdhi, mmc_data) -struct sh_mobile_sdhi_scc { - unsigned long clk_rate; /* clock rate for SDR104 */ - u32 tap; /* sampling clock position for SDR104 */ -}; - -struct sh_mobile_sdhi_of_data { - unsigned long tmio_flags; - u32 tmio_ocr_mask; - unsigned long capabilities; - unsigned long capabilities2; - enum dma_slave_buswidth dma_buswidth; - dma_addr_t dma_rx_offset; - unsigned bus_shift; - int scc_offset; - struct sh_mobile_sdhi_scc *taps; - int taps_num; -}; - -static const struct sh_mobile_sdhi_of_data of_default_cfg = { - .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT, -}; - -static const struct sh_mobile_sdhi_of_data of_rz_compatible = { - .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_32BIT_DATA_PORT, - .tmio_ocr_mask = MMC_VDD_32_33, - .capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ, -}; - -static const struct sh_mobile_sdhi_of_data of_rcar_gen1_compatible = { - .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_WRPROTECT_DISABLE | - TMIO_MMC_CLK_ACTUAL, - .capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ, -}; - -/* Definitions for sampling clocks */ -static struct sh_mobile_sdhi_scc rcar_gen2_scc_taps[] = { - { - .clk_rate = 156000000, - .tap = 0x00000703, - }, - { - .clk_rate = 0, - .tap = 0x00000300, - }, -}; - -static const struct sh_mobile_sdhi_of_data of_rcar_gen2_compatible = { - .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_WRPROTECT_DISABLE | - TMIO_MMC_CLK_ACTUAL | TMIO_MMC_MIN_RCAR2, - .capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ, - .dma_buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES, - .dma_rx_offset = 0x2000, - .scc_offset = 0x0300, - .taps = rcar_gen2_scc_taps, - .taps_num = ARRAY_SIZE(rcar_gen2_scc_taps), -}; - -/* Definitions for sampling clocks */ -static struct sh_mobile_sdhi_scc rcar_gen3_scc_taps[] = { - { - .clk_rate = 0, - .tap = 0x00000300, - }, -}; - -static const struct sh_mobile_sdhi_of_data of_rcar_gen3_compatible = { - .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_WRPROTECT_DISABLE | - TMIO_MMC_CLK_ACTUAL | TMIO_MMC_MIN_RCAR2, - .capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ, - .bus_shift = 2, - .scc_offset = 0x1000, - .taps = rcar_gen3_scc_taps, - .taps_num = ARRAY_SIZE(rcar_gen3_scc_taps), -}; - -static const struct of_device_id sh_mobile_sdhi_of_match[] = { - { .compatible = "renesas,sdhi-shmobile" }, - { .compatible = "renesas,sdhi-sh73a0", .data = &of_default_cfg, }, - { .compatible = "renesas,sdhi-r8a73a4", .data = &of_default_cfg, }, - { .compatible = "renesas,sdhi-r8a7740", .data = &of_default_cfg, }, - { .compatible = "renesas,sdhi-r7s72100", .data = &of_rz_compatible, }, - { .compatible = "renesas,sdhi-r8a7778", .data = &of_rcar_gen1_compatible, }, - { .compatible = "renesas,sdhi-r8a7779", .data = &of_rcar_gen1_compatible, }, - { .compatible = "renesas,sdhi-r8a7790", .data = &of_rcar_gen2_compatible, }, - { .compatible = "renesas,sdhi-r8a7791", .data = &of_rcar_gen2_compatible, }, - { .compatible = "renesas,sdhi-r8a7792", .data = &of_rcar_gen2_compatible, }, - { .compatible = "renesas,sdhi-r8a7793", .data = &of_rcar_gen2_compatible, }, - { .compatible = "renesas,sdhi-r8a7794", .data = &of_rcar_gen2_compatible, }, - { .compatible = "renesas,sdhi-r8a7795", .data = &of_rcar_gen3_compatible, }, - { .compatible = "renesas,sdhi-r8a7796", .data = &of_rcar_gen3_compatible, }, - {}, -}; -MODULE_DEVICE_TABLE(of, sh_mobile_sdhi_of_match); - -struct sh_mobile_sdhi { +struct renesas_sdhi { struct clk *clk; struct clk *clk_cd; struct tmio_mmc_data mmc_data; @@ -151,13 +56,13 @@ struct sh_mobile_sdhi { void __iomem *scc_ctl; }; -static void sh_mobile_sdhi_sdbuf_width(struct tmio_mmc_host *host, int width) +static void renesas_sdhi_sdbuf_width(struct tmio_mmc_host *host, int width) { u32 val; /* * see also - * sh_mobile_sdhi_of_data :: dma_buswidth + * renesas_sdhi_of_data :: dma_buswidth */ switch (sd_ctrl_read16(host, CTL_VERSION)) { case SDHI_VER_GEN2_SDR50: @@ -183,10 +88,10 @@ static void sh_mobile_sdhi_sdbuf_width(struct tmio_mmc_host *host, int width) sd_ctrl_write16(host, EXT_ACC, val); } -static int sh_mobile_sdhi_clk_enable(struct tmio_mmc_host *host) +static int renesas_sdhi_clk_enable(struct tmio_mmc_host *host) { struct mmc_host *mmc = host->mmc; - struct sh_mobile_sdhi *priv = host_to_priv(host); + struct renesas_sdhi *priv = host_to_priv(host); int ret = clk_prepare_enable(priv->clk); if (ret < 0) return ret; @@ -213,19 +118,19 @@ static int sh_mobile_sdhi_clk_enable(struct tmio_mmc_host *host) mmc->f_min = max(clk_round_rate(priv->clk, 1) / 512, 1L); /* enable 16bit data access on SDBUF as default */ - sh_mobile_sdhi_sdbuf_width(host, 16); + renesas_sdhi_sdbuf_width(host, 16); return 0; } -static unsigned int sh_mobile_sdhi_clk_update(struct tmio_mmc_host *host, +static unsigned int renesas_sdhi_clk_update(struct tmio_mmc_host *host, unsigned int new_clock) { - struct sh_mobile_sdhi *priv = host_to_priv(host); + struct renesas_sdhi *priv = host_to_priv(host); unsigned int freq, diff, best_freq = 0, diff_min = ~0; int i, ret; - /* tested only on RCar Gen2+ currently; may work for others */ + /* tested only on R-Car Gen2+ currently; may work for others */ if (!(host->pdata->flags & TMIO_MMC_MIN_RCAR2)) return clk_get_rate(priv->clk); @@ -257,26 +162,26 @@ static unsigned int sh_mobile_sdhi_clk_update(struct tmio_mmc_host *host, return ret == 0 ? best_freq : clk_get_rate(priv->clk); } -static void sh_mobile_sdhi_clk_disable(struct tmio_mmc_host *host) +static void renesas_sdhi_clk_disable(struct tmio_mmc_host *host) { - struct sh_mobile_sdhi *priv = host_to_priv(host); + struct renesas_sdhi *priv = host_to_priv(host); clk_disable_unprepare(priv->clk); clk_disable_unprepare(priv->clk_cd); } -static int sh_mobile_sdhi_card_busy(struct mmc_host *mmc) +static int renesas_sdhi_card_busy(struct mmc_host *mmc) { struct tmio_mmc_host *host = mmc_priv(mmc); return !(sd_ctrl_read16_and_16_as_32(host, CTL_STATUS) & TMIO_STAT_DAT0); } -static int sh_mobile_sdhi_start_signal_voltage_switch(struct mmc_host *mmc, +static int renesas_sdhi_start_signal_voltage_switch(struct mmc_host *mmc, struct mmc_ios *ios) { struct tmio_mmc_host *host = mmc_priv(mmc); - struct sh_mobile_sdhi *priv = host_to_priv(host); + struct renesas_sdhi *priv = host_to_priv(host); struct pinctrl_state *pin_state; int ret; @@ -327,21 +232,21 @@ static int sh_mobile_sdhi_start_signal_voltage_switch(struct mmc_host *mmc, #define SH_MOBILE_SDHI_SCC_RVSREQ_RVSERR BIT(2) static inline u32 sd_scc_read32(struct tmio_mmc_host *host, - struct sh_mobile_sdhi *priv, int addr) + struct renesas_sdhi *priv, int addr) { return readl(priv->scc_ctl + (addr << host->bus_shift)); } static inline void sd_scc_write32(struct tmio_mmc_host *host, - struct sh_mobile_sdhi *priv, + struct renesas_sdhi *priv, int addr, u32 val) { writel(val, priv->scc_ctl + (addr << host->bus_shift)); } -static unsigned int sh_mobile_sdhi_init_tuning(struct tmio_mmc_host *host) +static unsigned int renesas_sdhi_init_tuning(struct tmio_mmc_host *host) { - struct sh_mobile_sdhi *priv; + struct renesas_sdhi *priv; priv = host_to_priv(host); @@ -378,10 +283,10 @@ static unsigned int sh_mobile_sdhi_init_tuning(struct tmio_mmc_host *host) SH_MOBILE_SDHI_SCC_DTCNTL_TAPNUM_MASK; } -static void sh_mobile_sdhi_prepare_tuning(struct tmio_mmc_host *host, +static void renesas_sdhi_prepare_tuning(struct tmio_mmc_host *host, unsigned long tap) { - struct sh_mobile_sdhi *priv = host_to_priv(host); + struct renesas_sdhi *priv = host_to_priv(host); /* Set sampling clock position */ sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_TAPSET, tap); @@ -389,9 +294,9 @@ static void sh_mobile_sdhi_prepare_tuning(struct tmio_mmc_host *host, #define SH_MOBILE_SDHI_MAX_TAP 3 -static int sh_mobile_sdhi_select_tuning(struct tmio_mmc_host *host) +static int renesas_sdhi_select_tuning(struct tmio_mmc_host *host) { - struct sh_mobile_sdhi *priv = host_to_priv(host); + struct renesas_sdhi *priv = host_to_priv(host); unsigned long tap_cnt; /* counter of tuning success */ unsigned long tap_set; /* tap position */ unsigned long tap_start;/* start position of tuning success */ @@ -447,9 +352,9 @@ static int sh_mobile_sdhi_select_tuning(struct tmio_mmc_host *host) } -static bool sh_mobile_sdhi_check_scc_error(struct tmio_mmc_host *host) +static bool renesas_sdhi_check_scc_error(struct tmio_mmc_host *host) { - struct sh_mobile_sdhi *priv = host_to_priv(host); + struct renesas_sdhi *priv = host_to_priv(host); /* Check SCC error */ if (sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL) & @@ -464,9 +369,9 @@ static bool sh_mobile_sdhi_check_scc_error(struct tmio_mmc_host *host) return false; } -static void sh_mobile_sdhi_hw_reset(struct tmio_mmc_host *host) +static void renesas_sdhi_hw_reset(struct tmio_mmc_host *host) { - struct sh_mobile_sdhi *priv; + struct renesas_sdhi *priv; priv = host_to_priv(host); @@ -490,7 +395,7 @@ static void sh_mobile_sdhi_hw_reset(struct tmio_mmc_host *host) sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL)); } -static int sh_mobile_sdhi_wait_idle(struct tmio_mmc_host *host) +static int renesas_sdhi_wait_idle(struct tmio_mmc_host *host) { int timeout = 1000; @@ -506,7 +411,7 @@ static int sh_mobile_sdhi_wait_idle(struct tmio_mmc_host *host) return 0; } -static int sh_mobile_sdhi_write16_hook(struct tmio_mmc_host *host, int addr) +static int renesas_sdhi_write16_hook(struct tmio_mmc_host *host, int addr) { switch (addr) { @@ -519,13 +424,13 @@ static int sh_mobile_sdhi_write16_hook(struct tmio_mmc_host *host, int addr) case CTL_TRANSACTION_CTL: case CTL_DMA_ENABLE: case EXT_ACC: - return sh_mobile_sdhi_wait_idle(host); + return renesas_sdhi_wait_idle(host); } return 0; } -static int sh_mobile_sdhi_multi_io_quirk(struct mmc_card *card, +static int renesas_sdhi_multi_io_quirk(struct mmc_card *card, unsigned int direction, int blk_size) { /* @@ -543,18 +448,19 @@ static int sh_mobile_sdhi_multi_io_quirk(struct mmc_card *card, return blk_size; } -static void sh_mobile_sdhi_enable_dma(struct tmio_mmc_host *host, bool enable) +static void renesas_sdhi_enable_dma(struct tmio_mmc_host *host, bool enable) { sd_ctrl_write16(host, CTL_DMA_ENABLE, enable ? 2 : 0); /* enable 32bit access if DMA mode if possibile */ - sh_mobile_sdhi_sdbuf_width(host, enable ? 32 : 16); + renesas_sdhi_sdbuf_width(host, enable ? 32 : 16); } -static int sh_mobile_sdhi_probe(struct platform_device *pdev) +int renesas_sdhi_probe(struct platform_device *pdev, + const struct tmio_mmc_dma_ops *dma_ops) { - const struct sh_mobile_sdhi_of_data *of_data = of_device_get_match_data(&pdev->dev); - struct sh_mobile_sdhi *priv; + const struct renesas_sdhi_of_data *of_data = of_device_get_match_data( &pdev->dev); + struct renesas_sdhi *priv; struct tmio_mmc_data *mmc_data; struct tmio_mmc_data *mmd = pdev->dev.platform_data; struct tmio_mmc_host *host; @@ -566,7 +472,7 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev) if (!res) return -EINVAL; - priv = devm_kzalloc(&pdev->dev, sizeof(struct sh_mobile_sdhi), GFP_KERNEL); + priv = devm_kzalloc(&pdev->dev, sizeof(struct renesas_sdhi), GFP_KERNEL); if (!priv) return -ENOMEM; @@ -621,18 +527,18 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev) } host->dma = dma_priv; - host->write16_hook = sh_mobile_sdhi_write16_hook; - host->clk_enable = sh_mobile_sdhi_clk_enable; - host->clk_update = sh_mobile_sdhi_clk_update; - host->clk_disable = sh_mobile_sdhi_clk_disable; - host->multi_io_quirk = sh_mobile_sdhi_multi_io_quirk; + host->write16_hook = renesas_sdhi_write16_hook; + host->clk_enable = renesas_sdhi_clk_enable; + host->clk_update = renesas_sdhi_clk_update; + host->clk_disable = renesas_sdhi_clk_disable; + host->multi_io_quirk = renesas_sdhi_multi_io_quirk; /* SDR speeds are only available on Gen2+ */ if (mmc_data->flags & TMIO_MMC_MIN_RCAR2) { /* card_busy caused issues on r8a73a4 (pre-Gen2) CD-less SDHI */ - host->card_busy = sh_mobile_sdhi_card_busy; + host->card_busy = renesas_sdhi_card_busy; host->start_signal_voltage_switch = - sh_mobile_sdhi_start_signal_voltage_switch; + renesas_sdhi_start_signal_voltage_switch; } /* Orginally registers were 16 bit apart, could be 32 or 64 nowadays */ @@ -643,7 +549,7 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev) *mmc_data = *mmd; dma_priv->filter = shdma_chan_filter; - dma_priv->enable = sh_mobile_sdhi_enable_dma; + dma_priv->enable = renesas_sdhi_enable_dma; mmc_data->alignment_shift = 1; /* 2-byte alignment */ mmc_data->capabilities |= MMC_CAP_MMC_HIGHSPEED; @@ -667,7 +573,7 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev) /* All SDHI have SDIO status bits which must be 1 */ mmc_data->flags |= TMIO_MMC_SDIO_STATUS_SETBITS; - ret = tmio_mmc_host_probe(host, mmc_data); + ret = tmio_mmc_host_probe(host, mmc_data, dma_ops); if (ret < 0) goto efree; @@ -675,7 +581,7 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev) if (of_data && of_data->scc_offset && (host->mmc->caps & MMC_CAP_UHS_SDR104 || host->mmc->caps2 & MMC_CAP2_HS200_1_8V_SDR)) { - const struct sh_mobile_sdhi_scc *taps = of_data->taps; + const struct renesas_sdhi_scc *taps = of_data->taps; bool hit = false; host->mmc->caps |= MMC_CAP_HW_RESET; @@ -693,11 +599,11 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev) dev_warn(&host->pdev->dev, "Unknown clock rate for SDR104\n"); priv->scc_ctl = host->ctl + of_data->scc_offset; - host->init_tuning = sh_mobile_sdhi_init_tuning; - host->prepare_tuning = sh_mobile_sdhi_prepare_tuning; - host->select_tuning = sh_mobile_sdhi_select_tuning; - host->check_scc_error = sh_mobile_sdhi_check_scc_error; - host->hw_reset = sh_mobile_sdhi_hw_reset; + host->init_tuning = renesas_sdhi_init_tuning; + host->prepare_tuning = renesas_sdhi_prepare_tuning; + host->select_tuning = renesas_sdhi_select_tuning; + host->check_scc_error = renesas_sdhi_check_scc_error; + host->hw_reset = renesas_sdhi_hw_reset; } i = 0; @@ -732,8 +638,9 @@ efree: eprobe: return ret; } +EXPORT_SYMBOL_GPL(renesas_sdhi_probe); -static int sh_mobile_sdhi_remove(struct platform_device *pdev) +int renesas_sdhi_remove(struct platform_device *pdev) { struct mmc_host *mmc = platform_get_drvdata(pdev); struct tmio_mmc_host *host = mmc_priv(mmc); @@ -742,28 +649,4 @@ static int sh_mobile_sdhi_remove(struct platform_device *pdev) return 0; } - -static const struct dev_pm_ops tmio_mmc_dev_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, - pm_runtime_force_resume) - SET_RUNTIME_PM_OPS(tmio_mmc_host_runtime_suspend, - tmio_mmc_host_runtime_resume, - NULL) -}; - -static struct platform_driver sh_mobile_sdhi_driver = { - .driver = { - .name = "sh_mobile_sdhi", - .pm = &tmio_mmc_dev_pm_ops, - .of_match_table = sh_mobile_sdhi_of_match, - }, - .probe = sh_mobile_sdhi_probe, - .remove = sh_mobile_sdhi_remove, -}; - -module_platform_driver(sh_mobile_sdhi_driver); - -MODULE_DESCRIPTION("SuperH Mobile SDHI driver"); -MODULE_AUTHOR("Magnus Damm"); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:sh_mobile_sdhi"); +EXPORT_SYMBOL_GPL(renesas_sdhi_remove); diff --git a/drivers/mmc/host/tmio_mmc_dma.c b/drivers/mmc/host/renesas_sdhi_sys_dmac.c index e2093db2b7ff..7eab55adc5b2 100644 --- a/drivers/mmc/host/tmio_mmc_dma.c +++ b/drivers/mmc/host/renesas_sdhi_sys_dmac.c @@ -1,13 +1,11 @@ /* - * linux/drivers/mmc/tmio_mmc_dma.c + * DMA function for TMIO MMC implementations * * Copyright (C) 2010-2011 Guennadi Liakhovetski * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. - * - * DMA function for TMIO MMC implementations */ #include <linux/device.h> @@ -15,14 +13,97 @@ #include <linux/dmaengine.h> #include <linux/mfd/tmio.h> #include <linux/mmc/host.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> #include <linux/pagemap.h> #include <linux/scatterlist.h> +#include "renesas_sdhi.h" #include "tmio_mmc.h" #define TMIO_MMC_MIN_DMA_LEN 8 -void tmio_mmc_enable_dma(struct tmio_mmc_host *host, bool enable) +static const struct renesas_sdhi_of_data of_default_cfg = { + .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT, +}; + +static const struct renesas_sdhi_of_data of_rz_compatible = { + .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_32BIT_DATA_PORT, + .tmio_ocr_mask = MMC_VDD_32_33, + .capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ, +}; + +static const struct renesas_sdhi_of_data of_rcar_gen1_compatible = { + .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_WRPROTECT_DISABLE | + TMIO_MMC_CLK_ACTUAL, + .capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ, +}; + +/* Definitions for sampling clocks */ +static struct renesas_sdhi_scc rcar_gen2_scc_taps[] = { + { + .clk_rate = 156000000, + .tap = 0x00000703, + }, + { + .clk_rate = 0, + .tap = 0x00000300, + }, +}; + +static const struct renesas_sdhi_of_data of_rcar_gen2_compatible = { + .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_WRPROTECT_DISABLE | + TMIO_MMC_CLK_ACTUAL | TMIO_MMC_MIN_RCAR2, + .capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ | + MMC_CAP_CMD23, + .dma_buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES, + .dma_rx_offset = 0x2000, + .scc_offset = 0x0300, + .taps = rcar_gen2_scc_taps, + .taps_num = ARRAY_SIZE(rcar_gen2_scc_taps), +}; + +/* Definitions for sampling clocks */ +static struct renesas_sdhi_scc rcar_gen3_scc_taps[] = { + { + .clk_rate = 0, + .tap = 0x00000300, + }, +}; + +static const struct renesas_sdhi_of_data of_rcar_gen3_compatible = { + .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_WRPROTECT_DISABLE | + TMIO_MMC_CLK_ACTUAL | TMIO_MMC_MIN_RCAR2, + .capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ | + MMC_CAP_CMD23, + .bus_shift = 2, + .scc_offset = 0x1000, + .taps = rcar_gen3_scc_taps, + .taps_num = ARRAY_SIZE(rcar_gen3_scc_taps), +}; + +static const struct of_device_id renesas_sdhi_sys_dmac_of_match[] = { + { .compatible = "renesas,sdhi-shmobile" }, + { .compatible = "renesas,sdhi-sh73a0", .data = &of_default_cfg, }, + { .compatible = "renesas,sdhi-r8a73a4", .data = &of_default_cfg, }, + { .compatible = "renesas,sdhi-r8a7740", .data = &of_default_cfg, }, + { .compatible = "renesas,sdhi-r7s72100", .data = &of_rz_compatible, }, + { .compatible = "renesas,sdhi-r8a7778", .data = &of_rcar_gen1_compatible, }, + { .compatible = "renesas,sdhi-r8a7779", .data = &of_rcar_gen1_compatible, }, + { .compatible = "renesas,sdhi-r8a7790", .data = &of_rcar_gen2_compatible, }, + { .compatible = "renesas,sdhi-r8a7791", .data = &of_rcar_gen2_compatible, }, + { .compatible = "renesas,sdhi-r8a7792", .data = &of_rcar_gen2_compatible, }, + { .compatible = "renesas,sdhi-r8a7793", .data = &of_rcar_gen2_compatible, }, + { .compatible = "renesas,sdhi-r8a7794", .data = &of_rcar_gen2_compatible, }, + { .compatible = "renesas,sdhi-r8a7795", .data = &of_rcar_gen3_compatible, }, + { .compatible = "renesas,sdhi-r8a7796", .data = &of_rcar_gen3_compatible, }, + {}, +}; +MODULE_DEVICE_TABLE(of, renesas_sdhi_sys_dmac_of_match); + + +static void renesas_sdhi_sys_dmac_enable_dma(struct tmio_mmc_host *host, + bool enable) { if (!host->chan_tx || !host->chan_rx) return; @@ -31,19 +112,19 @@ void tmio_mmc_enable_dma(struct tmio_mmc_host *host, bool enable) host->dma->enable(host, enable); } -void tmio_mmc_abort_dma(struct tmio_mmc_host *host) +static void renesas_sdhi_sys_dmac_abort_dma(struct tmio_mmc_host *host) { - tmio_mmc_enable_dma(host, false); + renesas_sdhi_sys_dmac_enable_dma(host, false); if (host->chan_rx) dmaengine_terminate_all(host->chan_rx); if (host->chan_tx) dmaengine_terminate_all(host->chan_tx); - tmio_mmc_enable_dma(host, true); + renesas_sdhi_sys_dmac_enable_dma(host, true); } -static void tmio_mmc_dma_callback(void *arg) +static void renesas_sdhi_sys_dmac_dma_callback(void *arg) { struct tmio_mmc_host *host = arg; @@ -71,7 +152,7 @@ out: spin_unlock_irq(&host->lock); } -static void tmio_mmc_start_dma_rx(struct tmio_mmc_host *host) +static void renesas_sdhi_sys_dmac_start_dma_rx(struct tmio_mmc_host *host) { struct scatterlist *sg = host->sg_ptr, *sg_tmp; struct dma_async_tx_descriptor *desc = NULL; @@ -117,7 +198,7 @@ static void tmio_mmc_start_dma_rx(struct tmio_mmc_host *host) if (desc) { reinit_completion(&host->dma_dataend); - desc->callback = tmio_mmc_dma_callback; + desc->callback = renesas_sdhi_sys_dmac_dma_callback; desc->callback_param = host; cookie = dmaengine_submit(desc); @@ -129,7 +210,7 @@ static void tmio_mmc_start_dma_rx(struct tmio_mmc_host *host) pio: if (!desc) { /* DMA failed, fall back to PIO */ - tmio_mmc_enable_dma(host, false); + renesas_sdhi_sys_dmac_enable_dma(host, false); if (ret >= 0) ret = -EIO; host->chan_rx = NULL; @@ -145,7 +226,7 @@ pio: } } -static void tmio_mmc_start_dma_tx(struct tmio_mmc_host *host) +static void renesas_sdhi_sys_dmac_start_dma_tx(struct tmio_mmc_host *host) { struct scatterlist *sg = host->sg_ptr, *sg_tmp; struct dma_async_tx_descriptor *desc = NULL; @@ -195,7 +276,7 @@ static void tmio_mmc_start_dma_tx(struct tmio_mmc_host *host) if (desc) { reinit_completion(&host->dma_dataend); - desc->callback = tmio_mmc_dma_callback; + desc->callback = renesas_sdhi_sys_dmac_dma_callback; desc->callback_param = host; cookie = dmaengine_submit(desc); @@ -207,7 +288,7 @@ static void tmio_mmc_start_dma_tx(struct tmio_mmc_host *host) pio: if (!desc) { /* DMA failed, fall back to PIO */ - tmio_mmc_enable_dma(host, false); + renesas_sdhi_sys_dmac_enable_dma(host, false); if (ret >= 0) ret = -EIO; host->chan_tx = NULL; @@ -223,19 +304,19 @@ pio: } } -void tmio_mmc_start_dma(struct tmio_mmc_host *host, +static void renesas_sdhi_sys_dmac_start_dma(struct tmio_mmc_host *host, struct mmc_data *data) { if (data->flags & MMC_DATA_READ) { if (host->chan_rx) - tmio_mmc_start_dma_rx(host); + renesas_sdhi_sys_dmac_start_dma_rx(host); } else { if (host->chan_tx) - tmio_mmc_start_dma_tx(host); + renesas_sdhi_sys_dmac_start_dma_tx(host); } } -static void tmio_mmc_issue_tasklet_fn(unsigned long priv) +static void renesas_sdhi_sys_dmac_issue_tasklet_fn(unsigned long priv) { struct tmio_mmc_host *host = (struct tmio_mmc_host *)priv; struct dma_chan *chan = NULL; @@ -257,7 +338,8 @@ static void tmio_mmc_issue_tasklet_fn(unsigned long priv) dma_async_issue_pending(chan); } -void tmio_mmc_request_dma(struct tmio_mmc_host *host, struct tmio_mmc_data *pdata) +static void renesas_sdhi_sys_dmac_request_dma(struct tmio_mmc_host *host, + struct tmio_mmc_data *pdata) { /* We can only either use DMA for both Tx and Rx or not use it at all */ if (!host->dma || (!host->pdev->dev.of_node && @@ -320,10 +402,12 @@ void tmio_mmc_request_dma(struct tmio_mmc_host *host, struct tmio_mmc_data *pdat goto ebouncebuf; init_completion(&host->dma_dataend); - tasklet_init(&host->dma_issue, tmio_mmc_issue_tasklet_fn, (unsigned long)host); + tasklet_init(&host->dma_issue, + renesas_sdhi_sys_dmac_issue_tasklet_fn, + (unsigned long)host); } - tmio_mmc_enable_dma(host, true); + renesas_sdhi_sys_dmac_enable_dma(host, true); return; @@ -337,7 +421,7 @@ ecfgtx: host->chan_tx = NULL; } -void tmio_mmc_release_dma(struct tmio_mmc_host *host) +static void renesas_sdhi_sys_dmac_release_dma(struct tmio_mmc_host *host) { if (host->chan_tx) { struct dma_chan *chan = host->chan_tx; @@ -354,3 +438,41 @@ void tmio_mmc_release_dma(struct tmio_mmc_host *host) host->bounce_buf = NULL; } } + +static const struct tmio_mmc_dma_ops renesas_sdhi_sys_dmac_dma_ops = { + .start = renesas_sdhi_sys_dmac_start_dma, + .enable = renesas_sdhi_sys_dmac_enable_dma, + .request = renesas_sdhi_sys_dmac_request_dma, + .release = renesas_sdhi_sys_dmac_release_dma, + .abort = renesas_sdhi_sys_dmac_abort_dma, +}; + +static int renesas_sdhi_sys_dmac_probe(struct platform_device *pdev) +{ + return renesas_sdhi_probe(pdev, &renesas_sdhi_sys_dmac_dma_ops); +} + +static const struct dev_pm_ops renesas_sdhi_sys_dmac_dev_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) + SET_RUNTIME_PM_OPS(tmio_mmc_host_runtime_suspend, + tmio_mmc_host_runtime_resume, + NULL) +}; + +static struct platform_driver renesas_sys_dmac_sdhi_driver = { + .driver = { + .name = "sh_mobile_sdhi", + .pm = &renesas_sdhi_sys_dmac_dev_pm_ops, + .of_match_table = renesas_sdhi_sys_dmac_of_match, + }, + .probe = renesas_sdhi_sys_dmac_probe, + .remove = renesas_sdhi_remove, +}; + +module_platform_driver(renesas_sys_dmac_sdhi_driver); + +MODULE_DESCRIPTION("Renesas SDHI driver"); +MODULE_AUTHOR("Magnus Damm"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:sh_mobile_sdhi"); diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c index 23d8b8a73ae9..85140c9af581 100644 --- a/drivers/mmc/host/sdhci-esdhc-imx.c +++ b/drivers/mmc/host/sdhci-esdhc-imx.c @@ -95,7 +95,7 @@ #define ESDHC_CTRL_BUSWIDTH_MASK (0x3 << 1) /* - * There is an INT DMA ERR mis-match between eSDHC and STD SDHC SPEC: + * There is an INT DMA ERR mismatch between eSDHC and STD SDHC SPEC: * Bit25 is used in STD SPEC, and is reserved in fsl eSDHC design, * but bit28 is used as the INT DMA ERR in fsl eSDHC design. * Define this macro DMA error INT for fsl eSDHC @@ -110,16 +110,11 @@ * In exact block transfer, the controller doesn't complete the * operations automatically as required at the end of the * transfer and remains on hold if the abort command is not sent. - * As a result, the TC flag is not asserted and SW received timeout - * exeception. Bit1 of Vendor Spec registor is used to fix it. + * As a result, the TC flag is not asserted and SW received timeout + * exception. Bit1 of Vendor Spec register is used to fix it. */ #define ESDHC_FLAG_MULTIBLK_NO_INT BIT(1) /* - * The flag enables the workaround for ESDHC errata ENGcm07207 which - * affects i.MX25 and i.MX35. - */ -#define ESDHC_FLAG_ENGCM07207 BIT(2) -/* * The flag tells that the ESDHC controller is an USDHC block that is * integrated on the i.MX6 series. */ @@ -131,9 +126,11 @@ /* The IP has SDHCI_CAPABILITIES_1 register */ #define ESDHC_FLAG_HAVE_CAP1 BIT(6) /* - * The IP has errata ERR004536 + * The IP has erratum ERR004536 * uSDHC: ADMA Length Mismatch Error occurs if the AHB read access is slow, * when reading data from the card + * This flag is also set for i.MX25 and i.MX35 in order to get + * SDHCI_QUIRK_BROKEN_ADMA, but for different reasons (ADMA capability bits). */ #define ESDHC_FLAG_ERR004536 BIT(7) /* The IP supports HS200 mode */ @@ -141,7 +138,7 @@ /* The IP supports HS400 mode */ #define ESDHC_FLAG_HS400 BIT(9) -/* A higher clock ferquency than this rate requires strobell dll control */ +/* A clock frequency higher than this rate requires strobe dll control */ #define ESDHC_STROBE_DLL_CLK_FREQ 100000000 struct esdhc_soc_data { @@ -149,11 +146,11 @@ struct esdhc_soc_data { }; static struct esdhc_soc_data esdhc_imx25_data = { - .flags = ESDHC_FLAG_ENGCM07207, + .flags = ESDHC_FLAG_ERR004536, }; static struct esdhc_soc_data esdhc_imx35_data = { - .flags = ESDHC_FLAG_ENGCM07207, + .flags = ESDHC_FLAG_ERR004536, }; static struct esdhc_soc_data esdhc_imx51_data = { @@ -197,7 +194,7 @@ struct pltfm_imx_data { struct clk *clk_ahb; struct clk *clk_per; enum { - NO_CMD_PENDING, /* no multiblock command pending*/ + NO_CMD_PENDING, /* no multiblock command pending */ MULTIBLK_IN_PROCESS, /* exact multiblock cmd in process */ WAIT_FOR_INT, /* sent CMD12, waiting for response INT */ } multiblock_status; @@ -286,7 +283,7 @@ static u32 esdhc_readl_le(struct sdhci_host *host, int reg) * ADMA2 capability of esdhc, but this bit is messed up on * some SOCs (e.g. on MX25, MX35 this bit is set, but they * don't actually support ADMA2). So set the BROKEN_ADMA - * uirk on MX25/35 platforms. + * quirk on MX25/35 platforms. */ if (val & SDHCI_CAN_DO_ADMA1) { @@ -351,7 +348,7 @@ static void esdhc_writel_le(struct sdhci_host *host, u32 val, int reg) if ((val & SDHCI_INT_CARD_INT) && !esdhc_is_usdhc(imx_data)) { /* * Clear and then set D3CD bit to avoid missing the - * card interrupt. This is a eSDHC controller problem + * card interrupt. This is an eSDHC controller problem * so we need to apply the following workaround: clear * and set D3CD bit will make eSDHC re-sample the card * interrupt. In case a card interrupt was lost, @@ -579,7 +576,7 @@ static void esdhc_writeb_le(struct sdhci_host *host, u8 val, int reg) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); - u32 new_val; + u32 new_val = 0; u32 mask; switch (reg) { @@ -604,35 +601,52 @@ static void esdhc_writeb_le(struct sdhci_host *host, u8 val, int reg) * Do not touch buswidth bits here. This is done in * esdhc_pltfm_bus_width. * Do not touch the D3CD bit either which is used for the - * SDIO interrupt errata workaround. + * SDIO interrupt erratum workaround. */ mask = 0xffff & ~(ESDHC_CTRL_BUSWIDTH_MASK | ESDHC_CTRL_D3CD); esdhc_clrset_le(host, mask, new_val, reg); return; + case SDHCI_SOFTWARE_RESET: + if (val & SDHCI_RESET_DATA) + new_val = readl(host->ioaddr + SDHCI_HOST_CONTROL); + break; } esdhc_clrset_le(host, 0xff, val, reg); - /* - * The esdhc has a design violation to SDHC spec which tells - * that software reset should not affect card detection circuit. - * But esdhc clears its SYSCTL register bits [0..2] during the - * software reset. This will stop those clocks that card detection - * circuit relies on. To work around it, we turn the clocks on back - * to keep card detection circuit functional. - */ - if ((reg == SDHCI_SOFTWARE_RESET) && (val & 1)) { - esdhc_clrset_le(host, 0x7, 0x7, ESDHC_SYSTEM_CONTROL); - /* - * The reset on usdhc fails to clear MIX_CTRL register. - * Do it manually here. - */ - if (esdhc_is_usdhc(imx_data)) { - /* the tuning bits should be kept during reset */ - new_val = readl(host->ioaddr + ESDHC_MIX_CTRL); - writel(new_val & ESDHC_MIX_CTRL_TUNING_MASK, - host->ioaddr + ESDHC_MIX_CTRL); - imx_data->is_ddr = 0; + if (reg == SDHCI_SOFTWARE_RESET) { + if (val & SDHCI_RESET_ALL) { + /* + * The esdhc has a design violation to SDHC spec which + * tells that software reset should not affect card + * detection circuit. But esdhc clears its SYSCTL + * register bits [0..2] during the software reset. This + * will stop those clocks that card detection circuit + * relies on. To work around it, we turn the clocks on + * back to keep card detection circuit functional. + */ + esdhc_clrset_le(host, 0x7, 0x7, ESDHC_SYSTEM_CONTROL); + /* + * The reset on usdhc fails to clear MIX_CTRL register. + * Do it manually here. + */ + if (esdhc_is_usdhc(imx_data)) { + /* + * the tuning bits should be kept during reset + */ + new_val = readl(host->ioaddr + ESDHC_MIX_CTRL); + writel(new_val & ESDHC_MIX_CTRL_TUNING_MASK, + host->ioaddr + ESDHC_MIX_CTRL); + imx_data->is_ddr = 0; + } + } else if (val & SDHCI_RESET_DATA) { + /* + * The eSDHC DAT line software reset clears at least the + * data transfer width on i.MX25, so make sure that the + * Host Control register is unaffected. + */ + esdhc_clrset_le(host, 0xff, new_val, + SDHCI_HOST_CONTROL); } } } @@ -657,7 +671,8 @@ static inline void esdhc_pltfm_set_clock(struct sdhci_host *host, struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); unsigned int host_clock = pltfm_host->clock; - int pre_div = 2; + int ddr_pre_div = imx_data->is_ddr ? 2 : 1; + int pre_div = 1; int div = 1; u32 temp, val; @@ -672,28 +687,23 @@ static inline void esdhc_pltfm_set_clock(struct sdhci_host *host, return; } - if (esdhc_is_usdhc(imx_data) && !imx_data->is_ddr) - pre_div = 1; - temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL); temp &= ~(ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN | ESDHC_CLOCK_MASK); sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL); - while (host_clock / pre_div / 16 > clock && pre_div < 256) + while (host_clock / (16 * pre_div * ddr_pre_div) > clock && + pre_div < 256) pre_div *= 2; - while (host_clock / pre_div / div > clock && div < 16) + while (host_clock / (div * pre_div * ddr_pre_div) > clock && div < 16) div++; - host->mmc->actual_clock = host_clock / pre_div / div; + host->mmc->actual_clock = host_clock / (div * pre_div * ddr_pre_div); dev_dbg(mmc_dev(host->mmc), "desired SD clock: %d, actual: %d\n", clock, host->mmc->actual_clock); - if (imx_data->is_ddr) - pre_div >>= 2; - else - pre_div >>= 1; + pre_div >>= 1; div--; temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL); @@ -763,7 +773,7 @@ static void esdhc_prepare_tuning(struct sdhci_host *host, u32 val) writel(reg, host->ioaddr + ESDHC_MIX_CTRL); writel(val << 8, host->ioaddr + ESDHC_TUNE_CTRL_STATUS); dev_dbg(mmc_dev(host->mmc), - "tunning with delay 0x%x ESDHC_TUNE_CTRL_STATUS 0x%x\n", + "tuning with delay 0x%x ESDHC_TUNE_CTRL_STATUS 0x%x\n", val, readl(host->ioaddr + ESDHC_TUNE_CTRL_STATUS)); } @@ -807,7 +817,7 @@ static int esdhc_executing_tuning(struct sdhci_host *host, u32 opcode) ret = mmc_send_tuning(host->mmc, opcode, NULL); esdhc_post_tuning(host); - dev_dbg(mmc_dev(host->mmc), "tunning %s at 0x%x ret %d\n", + dev_dbg(mmc_dev(host->mmc), "tuning %s at 0x%x ret %d\n", ret ? "failed" : "passed", avg, ret); return ret; @@ -847,15 +857,15 @@ static int esdhc_change_pinstate(struct sdhci_host *host, } /* - * For HS400 eMMC, there is a data_strobe line, this signal is generated + * For HS400 eMMC, there is a data_strobe line. This signal is generated * by the device and used for data output and CRC status response output * in HS400 mode. The frequency of this signal follows the frequency of - * CLK generated by host. Host receive the data which is aligned to the + * CLK generated by host. The host receives the data which is aligned to the * edge of data_strobe line. Due to the time delay between CLK line and * data_strobe line, if the delay time is larger than one clock cycle, - * then CLK and data_strobe line will misaligned, read error shows up. + * then CLK and data_strobe line will be misaligned, read error shows up. * So when the CLK is higher than 100MHz, each clock cycle is short enough, - * host should config the delay target. + * host should configure the delay target. */ static void esdhc_set_strobe_dll(struct sdhci_host *host) { @@ -895,7 +905,7 @@ static void esdhc_reset_tuning(struct sdhci_host *host) struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); u32 ctrl; - /* Rest the tuning circurt */ + /* Reset the tuning circuit */ if (esdhc_is_usdhc(imx_data)) { if (imx_data->socdata->flags & ESDHC_FLAG_MAN_TUNING) { ctrl = readl(host->ioaddr + ESDHC_MIX_CTRL); @@ -976,7 +986,7 @@ static unsigned int esdhc_get_max_timeout_count(struct sdhci_host *host) struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); - /* Doc Errata: the uSDHC actual maximum timeout count is 1 << 29 */ + /* Doc Erratum: the uSDHC actual maximum timeout count is 1 << 29 */ return esdhc_is_usdhc(imx_data) ? 1 << 29 : 1 << 27; } @@ -1032,10 +1042,10 @@ static void sdhci_esdhc_imx_hwinit(struct sdhci_host *host) /* * ROM code will change the bit burst_length_enable setting - * to zero if this usdhc is choosed to boot system. Change + * to zero if this usdhc is chosen to boot system. Change * it back here, otherwise it will impact the performance a * lot. This bit is used to enable/disable the burst length - * for the external AHB2AXI bridge, it's usefully especially + * for the external AHB2AXI bridge. It's useful especially * for INCR transfer because without burst length indicator, * the AHB2AXI bridge does not know the burst length in * advance. And without burst length indicator, AHB INCR @@ -1045,7 +1055,7 @@ static void sdhci_esdhc_imx_hwinit(struct sdhci_host *host) | ESDHC_BURST_LEN_EN_INCR, host->ioaddr + SDHCI_HOST_CONTROL); /* - * errata ESDHC_FLAG_ERR004536 fix for MX6Q TO1.2 and MX6DL + * erratum ESDHC_FLAG_ERR004536 fix for MX6Q TO1.2 and MX6DL * TO1.1, it's harmless for MX6SL */ writel(readl(host->ioaddr + 0x6c) | BIT(7), @@ -1104,7 +1114,7 @@ sdhci_esdhc_imx_probe_dt(struct platform_device *pdev, mmc_of_parse_voltage(np, &host->ocr_mask); - /* sdr50 and sdr104 needs work on 1.8v signal voltage */ + /* sdr50 and sdr104 need work on 1.8v signal voltage */ if ((boarddata->support_vsel) && esdhc_is_usdhc(imx_data) && !IS_ERR(imx_data->pins_default)) { imx_data->pins_100mhz = pinctrl_lookup_state(imx_data->pinctrl, @@ -1116,7 +1126,8 @@ sdhci_esdhc_imx_probe_dt(struct platform_device *pdev, dev_warn(mmc_dev(host->mmc), "could not get ultra high speed state, work on normal mode\n"); /* - * fall back to not support uhs by specify no 1.8v quirk + * fall back to not supporting uhs by specifying no + * 1.8v quirk */ host->quirks2 |= SDHCI_QUIRK2_NO_1_8_V; } @@ -1250,14 +1261,20 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev) pltfm_host->clk = imx_data->clk_per; pltfm_host->clock = clk_get_rate(pltfm_host->clk); - clk_prepare_enable(imx_data->clk_per); - clk_prepare_enable(imx_data->clk_ipg); - clk_prepare_enable(imx_data->clk_ahb); + err = clk_prepare_enable(imx_data->clk_per); + if (err) + goto free_sdhci; + err = clk_prepare_enable(imx_data->clk_ipg); + if (err) + goto disable_per_clk; + err = clk_prepare_enable(imx_data->clk_ahb); + if (err) + goto disable_ipg_clk; imx_data->pinctrl = devm_pinctrl_get(&pdev->dev); if (IS_ERR(imx_data->pinctrl)) { err = PTR_ERR(imx_data->pinctrl); - goto disable_clk; + goto disable_ahb_clk; } imx_data->pins_default = pinctrl_lookup_state(imx_data->pinctrl, @@ -1265,11 +1282,6 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev) if (IS_ERR(imx_data->pins_default)) dev_warn(mmc_dev(host->mmc), "could not get default state\n"); - if (imx_data->socdata->flags & ESDHC_FLAG_ENGCM07207) - /* Fix errata ENGcm07207 present on i.MX25 and i.MX35 */ - host->quirks |= SDHCI_QUIRK_NO_MULTIBLOCK - | SDHCI_QUIRK_BROKEN_ADMA; - if (esdhc_is_usdhc(imx_data)) { host->quirks2 |= SDHCI_QUIRK2_PRESET_VALUE_BROKEN; host->mmc->caps |= MMC_CAP_1_8V_DDR; @@ -1297,13 +1309,13 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev) else err = sdhci_esdhc_imx_probe_nondt(pdev, host, imx_data); if (err) - goto disable_clk; + goto disable_ahb_clk; sdhci_esdhc_imx_hwinit(host); err = sdhci_add_host(host); if (err) - goto disable_clk; + goto disable_ahb_clk; pm_runtime_set_active(&pdev->dev); pm_runtime_set_autosuspend_delay(&pdev->dev, 50); @@ -1313,10 +1325,12 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev) return 0; -disable_clk: - clk_disable_unprepare(imx_data->clk_per); - clk_disable_unprepare(imx_data->clk_ipg); +disable_ahb_clk: clk_disable_unprepare(imx_data->clk_ahb); +disable_ipg_clk: + clk_disable_unprepare(imx_data->clk_ipg); +disable_per_clk: + clk_disable_unprepare(imx_data->clk_per); free_sdhci: sdhci_pltfm_free(pdev); return err; @@ -1393,14 +1407,34 @@ static int sdhci_esdhc_runtime_resume(struct device *dev) struct sdhci_host *host = dev_get_drvdata(dev); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); + int err; if (!sdhci_sdio_irq_enabled(host)) { - clk_prepare_enable(imx_data->clk_per); - clk_prepare_enable(imx_data->clk_ipg); + err = clk_prepare_enable(imx_data->clk_per); + if (err) + return err; + err = clk_prepare_enable(imx_data->clk_ipg); + if (err) + goto disable_per_clk; } - clk_prepare_enable(imx_data->clk_ahb); + err = clk_prepare_enable(imx_data->clk_ahb); + if (err) + goto disable_ipg_clk; + err = sdhci_runtime_resume_host(host); + if (err) + goto disable_ahb_clk; + + return 0; - return sdhci_runtime_resume_host(host); +disable_ahb_clk: + clk_disable_unprepare(imx_data->clk_ahb); +disable_ipg_clk: + if (!sdhci_sdio_irq_enabled(host)) + clk_disable_unprepare(imx_data->clk_ipg); +disable_per_clk: + if (!sdhci_sdio_irq_enabled(host)) + clk_disable_unprepare(imx_data->clk_per); + return err; } #endif diff --git a/drivers/mmc/host/sdhci-esdhc.h b/drivers/mmc/host/sdhci-esdhc.h index c4bbd7485987..e7893f21b65e 100644 --- a/drivers/mmc/host/sdhci-esdhc.h +++ b/drivers/mmc/host/sdhci-esdhc.h @@ -19,6 +19,7 @@ */ #define ESDHC_DEFAULT_QUIRKS (SDHCI_QUIRK_FORCE_BLK_SZ_2048 | \ + SDHCI_QUIRK_32BIT_DMA_ADDR | \ SDHCI_QUIRK_NO_BUSY_IRQ | \ SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | \ SDHCI_QUIRK_PIO_NEEDS_DELAY | \ diff --git a/drivers/mmc/host/sdhci-of-arasan.c b/drivers/mmc/host/sdhci-of-arasan.c index ea6b36c88ae7..b13c0a7d50e4 100644 --- a/drivers/mmc/host/sdhci-of-arasan.c +++ b/drivers/mmc/host/sdhci-of-arasan.c @@ -638,7 +638,7 @@ static int sdhci_arasan_probe(struct platform_device *pdev) ret = mmc_of_parse(host->mmc); if (ret) { - dev_err(&pdev->dev, "parsing dt failed (%u)\n", ret); + dev_err(&pdev->dev, "parsing dt failed (%d)\n", ret); goto unreg_clk; } diff --git a/drivers/mmc/host/sdhci-pci-core.c b/drivers/mmc/host/sdhci-pci-core.c index 92fc3f7c538d..b3ddc32fa00b 100644 --- a/drivers/mmc/host/sdhci-pci-core.c +++ b/drivers/mmc/host/sdhci-pci-core.c @@ -1171,554 +1171,76 @@ static const struct sdhci_pci_fixes sdhci_amd = { }; static const struct pci_device_id pci_ids[] = { - { - .vendor = PCI_VENDOR_ID_RICOH, - .device = PCI_DEVICE_ID_RICOH_R5C822, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_ricoh, - }, - - { - .vendor = PCI_VENDOR_ID_RICOH, - .device = 0x843, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_ricoh_mmc, - }, - - { - .vendor = PCI_VENDOR_ID_RICOH, - .device = 0xe822, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_ricoh_mmc, - }, - - { - .vendor = PCI_VENDOR_ID_RICOH, - .device = 0xe823, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_ricoh_mmc, - }, - - { - .vendor = PCI_VENDOR_ID_ENE, - .device = PCI_DEVICE_ID_ENE_CB712_SD, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_ene_712, - }, - - { - .vendor = PCI_VENDOR_ID_ENE, - .device = PCI_DEVICE_ID_ENE_CB712_SD_2, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_ene_712, - }, - - { - .vendor = PCI_VENDOR_ID_ENE, - .device = PCI_DEVICE_ID_ENE_CB714_SD, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_ene_714, - }, - - { - .vendor = PCI_VENDOR_ID_ENE, - .device = PCI_DEVICE_ID_ENE_CB714_SD_2, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_ene_714, - }, - - { - .vendor = PCI_VENDOR_ID_MARVELL, - .device = PCI_DEVICE_ID_MARVELL_88ALP01_SD, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_cafe, - }, - - { - .vendor = PCI_VENDOR_ID_JMICRON, - .device = PCI_DEVICE_ID_JMICRON_JMB38X_SD, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_jmicron, - }, - - { - .vendor = PCI_VENDOR_ID_JMICRON, - .device = PCI_DEVICE_ID_JMICRON_JMB38X_MMC, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_jmicron, - }, - - { - .vendor = PCI_VENDOR_ID_JMICRON, - .device = PCI_DEVICE_ID_JMICRON_JMB388_SD, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_jmicron, - }, - - { - .vendor = PCI_VENDOR_ID_JMICRON, - .device = PCI_DEVICE_ID_JMICRON_JMB388_ESD, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_jmicron, - }, - - { - .vendor = PCI_VENDOR_ID_SYSKONNECT, - .device = 0x8000, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_syskt, - }, - - { - .vendor = PCI_VENDOR_ID_VIA, - .device = 0x95d0, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_via, - }, - - { - .vendor = PCI_VENDOR_ID_REALTEK, - .device = 0x5250, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_rtsx, - }, - - { - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_QRK_SD, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_intel_qrk, - }, - - { - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_MRST_SD0, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_intel_mrst_hc0, - }, - - { - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_MRST_SD1, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_intel_mrst_hc1_hc2, - }, - - { - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_MRST_SD2, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_intel_mrst_hc1_hc2, - }, - - { - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_MFD_SD, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_intel_mfd_sd, - }, - - { - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_MFD_SDIO1, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_intel_mfd_sdio, - }, - - { - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_MFD_SDIO2, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_intel_mfd_sdio, - }, - - { - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_MFD_EMMC0, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_intel_mfd_emmc, - }, - - { - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_MFD_EMMC1, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_intel_mfd_emmc, - }, - - { - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_PCH_SDIO0, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_intel_pch_sdio, - }, - - { - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_PCH_SDIO1, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_intel_pch_sdio, - }, - - { - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_BYT_EMMC, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_intel_byt_emmc, - }, - - { - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_BYT_SDIO, - .subvendor = PCI_VENDOR_ID_NI, - .subdevice = 0x7884, - .driver_data = (kernel_ulong_t)&sdhci_ni_byt_sdio, - }, - - { - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_BYT_SDIO, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_intel_byt_sdio, - }, - - { - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_BYT_SD, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_intel_byt_sd, - }, - - { - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_BYT_EMMC2, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_intel_byt_emmc, - }, - - { - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_BSW_EMMC, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_intel_byt_emmc, - }, - - { - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_BSW_SDIO, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_intel_byt_sdio, - }, - - { - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_BSW_SD, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_intel_byt_sd, - }, - - { - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_CLV_SDIO0, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_intel_mfd_sd, - }, - - { - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_CLV_SDIO1, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_intel_mfd_sdio, - }, - - { - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_CLV_SDIO2, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_intel_mfd_sdio, - }, - - { - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_CLV_EMMC0, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_intel_mfd_emmc, - }, - - { - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_CLV_EMMC1, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_intel_mfd_emmc, - }, - - { - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_MRFLD_MMC, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_intel_mrfld_mmc, - }, - - { - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_SPT_EMMC, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_intel_byt_emmc, - }, - - { - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_SPT_SDIO, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_intel_byt_sdio, - }, - - { - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_SPT_SD, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_intel_byt_sd, - }, - - { - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_DNV_EMMC, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_intel_byt_emmc, - }, - - { - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_BXT_EMMC, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_intel_byt_emmc, - }, - - { - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_BXT_SDIO, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_intel_byt_sdio, - }, - - { - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_BXT_SD, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_intel_byt_sd, - }, - - { - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_BXTM_EMMC, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_intel_byt_emmc, - }, - - { - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_BXTM_SDIO, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_intel_byt_sdio, - }, - - { - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_BXTM_SD, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_intel_byt_sd, - }, - - { - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_APL_EMMC, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_intel_byt_emmc, - }, - - { - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_APL_SDIO, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_intel_byt_sdio, - }, - - { - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_APL_SD, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_intel_byt_sd, - }, - - { - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_GLK_EMMC, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_intel_byt_emmc, - }, - - { - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_GLK_SDIO, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_intel_byt_sdio, - }, - - { - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_GLK_SD, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_intel_byt_sd, - }, - - { - .vendor = PCI_VENDOR_ID_O2, - .device = PCI_DEVICE_ID_O2_8120, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_o2, - }, - - { - .vendor = PCI_VENDOR_ID_O2, - .device = PCI_DEVICE_ID_O2_8220, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_o2, - }, - - { - .vendor = PCI_VENDOR_ID_O2, - .device = PCI_DEVICE_ID_O2_8221, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_o2, - }, - - { - .vendor = PCI_VENDOR_ID_O2, - .device = PCI_DEVICE_ID_O2_8320, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_o2, - }, - - { - .vendor = PCI_VENDOR_ID_O2, - .device = PCI_DEVICE_ID_O2_8321, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_o2, - }, - - { - .vendor = PCI_VENDOR_ID_O2, - .device = PCI_DEVICE_ID_O2_FUJIN2, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_o2, - }, - - { - .vendor = PCI_VENDOR_ID_O2, - .device = PCI_DEVICE_ID_O2_SDS0, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_o2, - }, - - { - .vendor = PCI_VENDOR_ID_O2, - .device = PCI_DEVICE_ID_O2_SDS1, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_o2, - }, - - { - .vendor = PCI_VENDOR_ID_O2, - .device = PCI_DEVICE_ID_O2_SEABIRD0, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_o2, - }, - - { - .vendor = PCI_VENDOR_ID_O2, - .device = PCI_DEVICE_ID_O2_SEABIRD1, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_o2, - }, - { - .vendor = PCI_VENDOR_ID_AMD, - .device = PCI_ANY_ID, - .class = PCI_CLASS_SYSTEM_SDHCI << 8, - .class_mask = 0xFFFF00, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (kernel_ulong_t)&sdhci_amd, - }, - { /* Generic SD host controller */ - PCI_DEVICE_CLASS((PCI_CLASS_SYSTEM_SDHCI << 8), 0xFFFF00) - }, - + SDHCI_PCI_DEVICE(RICOH, R5C822, ricoh), + SDHCI_PCI_DEVICE(RICOH, R5C843, ricoh_mmc), + SDHCI_PCI_DEVICE(RICOH, R5CE822, ricoh_mmc), + SDHCI_PCI_DEVICE(RICOH, R5CE823, ricoh_mmc), + SDHCI_PCI_DEVICE(ENE, CB712_SD, ene_712), + SDHCI_PCI_DEVICE(ENE, CB712_SD_2, ene_712), + SDHCI_PCI_DEVICE(ENE, CB714_SD, ene_714), + SDHCI_PCI_DEVICE(ENE, CB714_SD_2, ene_714), + SDHCI_PCI_DEVICE(MARVELL, 88ALP01_SD, cafe), + SDHCI_PCI_DEVICE(JMICRON, JMB38X_SD, jmicron), + SDHCI_PCI_DEVICE(JMICRON, JMB38X_MMC, jmicron), + SDHCI_PCI_DEVICE(JMICRON, JMB388_SD, jmicron), + SDHCI_PCI_DEVICE(JMICRON, JMB388_ESD, jmicron), + SDHCI_PCI_DEVICE(SYSKONNECT, 8000, syskt), + SDHCI_PCI_DEVICE(VIA, 95D0, via), + SDHCI_PCI_DEVICE(REALTEK, 5250, rtsx), + SDHCI_PCI_DEVICE(INTEL, QRK_SD, intel_qrk), + SDHCI_PCI_DEVICE(INTEL, MRST_SD0, intel_mrst_hc0), + SDHCI_PCI_DEVICE(INTEL, MRST_SD1, intel_mrst_hc1_hc2), + SDHCI_PCI_DEVICE(INTEL, MRST_SD2, intel_mrst_hc1_hc2), + SDHCI_PCI_DEVICE(INTEL, MFD_SD, intel_mfd_sd), + SDHCI_PCI_DEVICE(INTEL, MFD_SDIO1, intel_mfd_sdio), + SDHCI_PCI_DEVICE(INTEL, MFD_SDIO2, intel_mfd_sdio), + SDHCI_PCI_DEVICE(INTEL, MFD_EMMC0, intel_mfd_emmc), + SDHCI_PCI_DEVICE(INTEL, MFD_EMMC1, intel_mfd_emmc), + SDHCI_PCI_DEVICE(INTEL, PCH_SDIO0, intel_pch_sdio), + SDHCI_PCI_DEVICE(INTEL, PCH_SDIO1, intel_pch_sdio), + SDHCI_PCI_DEVICE(INTEL, BYT_EMMC, intel_byt_emmc), + SDHCI_PCI_SUBDEVICE(INTEL, BYT_SDIO, NI, 7884, ni_byt_sdio), + SDHCI_PCI_DEVICE(INTEL, BYT_SDIO, intel_byt_sdio), + SDHCI_PCI_DEVICE(INTEL, BYT_SD, intel_byt_sd), + SDHCI_PCI_DEVICE(INTEL, BYT_EMMC2, intel_byt_emmc), + SDHCI_PCI_DEVICE(INTEL, BSW_EMMC, intel_byt_emmc), + SDHCI_PCI_DEVICE(INTEL, BSW_SDIO, intel_byt_sdio), + SDHCI_PCI_DEVICE(INTEL, BSW_SD, intel_byt_sd), + SDHCI_PCI_DEVICE(INTEL, CLV_SDIO0, intel_mfd_sd), + SDHCI_PCI_DEVICE(INTEL, CLV_SDIO1, intel_mfd_sdio), + SDHCI_PCI_DEVICE(INTEL, CLV_SDIO2, intel_mfd_sdio), + SDHCI_PCI_DEVICE(INTEL, CLV_EMMC0, intel_mfd_emmc), + SDHCI_PCI_DEVICE(INTEL, CLV_EMMC1, intel_mfd_emmc), + SDHCI_PCI_DEVICE(INTEL, MRFLD_MMC, intel_mrfld_mmc), + SDHCI_PCI_DEVICE(INTEL, SPT_EMMC, intel_byt_emmc), + SDHCI_PCI_DEVICE(INTEL, SPT_SDIO, intel_byt_sdio), + SDHCI_PCI_DEVICE(INTEL, SPT_SD, intel_byt_sd), + SDHCI_PCI_DEVICE(INTEL, DNV_EMMC, intel_byt_emmc), + SDHCI_PCI_DEVICE(INTEL, BXT_EMMC, intel_byt_emmc), + SDHCI_PCI_DEVICE(INTEL, BXT_SDIO, intel_byt_sdio), + SDHCI_PCI_DEVICE(INTEL, BXT_SD, intel_byt_sd), + SDHCI_PCI_DEVICE(INTEL, BXTM_EMMC, intel_byt_emmc), + SDHCI_PCI_DEVICE(INTEL, BXTM_SDIO, intel_byt_sdio), + SDHCI_PCI_DEVICE(INTEL, BXTM_SD, intel_byt_sd), + SDHCI_PCI_DEVICE(INTEL, APL_EMMC, intel_byt_emmc), + SDHCI_PCI_DEVICE(INTEL, APL_SDIO, intel_byt_sdio), + SDHCI_PCI_DEVICE(INTEL, APL_SD, intel_byt_sd), + SDHCI_PCI_DEVICE(INTEL, GLK_EMMC, intel_byt_emmc), + SDHCI_PCI_DEVICE(INTEL, GLK_SDIO, intel_byt_sdio), + SDHCI_PCI_DEVICE(INTEL, GLK_SD, intel_byt_sd), + SDHCI_PCI_DEVICE(O2, 8120, o2), + SDHCI_PCI_DEVICE(O2, 8220, o2), + SDHCI_PCI_DEVICE(O2, 8221, o2), + SDHCI_PCI_DEVICE(O2, 8320, o2), + SDHCI_PCI_DEVICE(O2, 8321, o2), + SDHCI_PCI_DEVICE(O2, FUJIN2, o2), + SDHCI_PCI_DEVICE(O2, SDS0, o2), + SDHCI_PCI_DEVICE(O2, SDS1, o2), + SDHCI_PCI_DEVICE(O2, SEABIRD0, o2), + SDHCI_PCI_DEVICE(O2, SEABIRD1, o2), + SDHCI_PCI_DEVICE_CLASS(AMD, SYSTEM_SDHCI, PCI_CLASS_MASK, amd), + /* Generic SD host controller */ + {PCI_DEVICE_CLASS(SYSTEM_SDHCI, PCI_CLASS_MASK)}, { /* end: all zeroes */ }, }; diff --git a/drivers/mmc/host/sdhci-pci.h b/drivers/mmc/host/sdhci-pci.h index 37766d20a600..e63fb9b3b776 100644 --- a/drivers/mmc/host/sdhci-pci.h +++ b/drivers/mmc/host/sdhci-pci.h @@ -2,7 +2,7 @@ #define __SDHCI_PCI_H /* - * PCI device IDs + * PCI device IDs, sub IDs */ #define PCI_DEVICE_ID_INTEL_PCH_SDIO0 0x8809 @@ -38,6 +38,47 @@ #define PCI_DEVICE_ID_INTEL_GLK_EMMC 0x31cc #define PCI_DEVICE_ID_INTEL_GLK_SDIO 0x31d0 +#define PCI_DEVICE_ID_SYSKONNECT_8000 0x8000 +#define PCI_DEVICE_ID_VIA_95D0 0x95d0 +#define PCI_DEVICE_ID_REALTEK_5250 0x5250 + +#define PCI_SUBDEVICE_ID_NI_7884 0x7884 + +/* + * PCI device class and mask + */ + +#define SYSTEM_SDHCI (PCI_CLASS_SYSTEM_SDHCI << 8) +#define PCI_CLASS_MASK 0xFFFF00 + +/* + * Macros for PCI device-description + */ + +#define _PCI_VEND(vend) PCI_VENDOR_ID_##vend +#define _PCI_DEV(vend, dev) PCI_DEVICE_ID_##vend##_##dev +#define _PCI_SUBDEV(subvend, subdev) PCI_SUBDEVICE_ID_##subvend##_##subdev + +#define SDHCI_PCI_DEVICE(vend, dev, cfg) { \ + .vendor = _PCI_VEND(vend), .device = _PCI_DEV(vend, dev), \ + .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, \ + .driver_data = (kernel_ulong_t)&(sdhci_##cfg) \ +} + +#define SDHCI_PCI_SUBDEVICE(vend, dev, subvend, subdev, cfg) { \ + .vendor = _PCI_VEND(vend), .device = _PCI_DEV(vend, dev), \ + .subvendor = _PCI_VEND(subvend), \ + .subdevice = _PCI_SUBDEV(subvend, subdev), \ + .driver_data = (kernel_ulong_t)&(sdhci_##cfg) \ +} + +#define SDHCI_PCI_DEVICE_CLASS(vend, cl, cl_msk, cfg) { \ + .vendor = _PCI_VEND(vend), .device = PCI_ANY_ID, \ + .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, \ + .class = (cl), .class_mask = (cl_msk), \ + .driver_data = (kernel_ulong_t)&(sdhci_##cfg) \ +} + /* * PCI registers */ diff --git a/drivers/mmc/host/sdricoh_cs.c b/drivers/mmc/host/sdricoh_cs.c index 5ff26ab81eb1..70cb00aa79a0 100644 --- a/drivers/mmc/host/sdricoh_cs.c +++ b/drivers/mmc/host/sdricoh_cs.c @@ -256,9 +256,6 @@ static int sdricoh_blockio(struct sdricoh_host *host, int read, } } - if (len) - return -EIO; - return 0; } diff --git a/drivers/mmc/host/tmio_mmc.c b/drivers/mmc/host/tmio_mmc.c index e897e7fc3b14..59880146e7f9 100644 --- a/drivers/mmc/host/tmio_mmc.c +++ b/drivers/mmc/host/tmio_mmc.c @@ -1,5 +1,7 @@ /* - * linux/drivers/mmc/host/tmio_mmc.c + * Driver for the MMC / SD / SDIO cell found in: + * + * TC6393XB TC6391XB TC6387XB T7L66XB ASIC3 * * Copyright (C) 2007 Ian Molton * Copyright (C) 2004 Ian Molton @@ -7,10 +9,6 @@ * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. - * - * Driver for the MMC / SD / SDIO cell found in: - * - * TC6393XB TC6391XB TC6387XB T7L66XB ASIC3 */ #include <linux/device.h> @@ -99,7 +97,7 @@ static int tmio_mmc_probe(struct platform_device *pdev) /* SD control register space size is 0x200, 0x400 for bus_shift=1 */ host->bus_shift = resource_size(res) >> 10; - ret = tmio_mmc_host_probe(host, pdata); + ret = tmio_mmc_host_probe(host, pdata, NULL); if (ret) goto host_free; diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h index d0edb5730d3f..9c94b6eb9b49 100644 --- a/drivers/mmc/host/tmio_mmc.h +++ b/drivers/mmc/host/tmio_mmc.h @@ -1,5 +1,7 @@ /* - * linux/drivers/mmc/host/tmio_mmc.h + * Driver for the MMC / SD / SDIO cell found in: + * + * TC6393XB TC6391XB TC6387XB T7L66XB ASIC3 * * Copyright (C) 2016 Sang Engineering, Wolfram Sang * Copyright (C) 2015-16 Renesas Electronics Corporation @@ -10,9 +12,6 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * - * Driver for the MMC / SD / SDIO cell found in: - * - * TC6393XB TC6391XB TC6387XB T7L66XB ASIC3 */ #ifndef TMIO_MMC_H @@ -115,6 +114,15 @@ struct tmio_mmc_dma { void (*enable)(struct tmio_mmc_host *host, bool enable); }; +struct tmio_mmc_dma_ops { + void (*start)(struct tmio_mmc_host *host, struct mmc_data *data); + void (*enable)(struct tmio_mmc_host *host, bool enable); + void (*request)(struct tmio_mmc_host *host, + struct tmio_mmc_data *pdata); + void (*release)(struct tmio_mmc_host *host); + void (*abort)(struct tmio_mmc_host *host); +}; + struct tmio_mmc_host { void __iomem *ctl; struct mmc_command *cmd; @@ -189,12 +197,15 @@ struct tmio_mmc_host { /* Tuning values: 1 for success, 0 for failure */ DECLARE_BITMAP(taps, BITS_PER_BYTE * sizeof(long)); unsigned int tap_num; + + const struct tmio_mmc_dma_ops *dma_ops; }; struct tmio_mmc_host *tmio_mmc_host_alloc(struct platform_device *pdev); void tmio_mmc_host_free(struct tmio_mmc_host *host); int tmio_mmc_host_probe(struct tmio_mmc_host *host, - struct tmio_mmc_data *pdata); + struct tmio_mmc_data *pdata, + const struct tmio_mmc_dma_ops *dma_ops); void tmio_mmc_host_remove(struct tmio_mmc_host *host); void tmio_mmc_do_data_irq(struct tmio_mmc_host *host); @@ -216,38 +227,6 @@ static inline void tmio_mmc_kunmap_atomic(struct scatterlist *sg, local_irq_restore(*flags); } -#if defined(CONFIG_MMC_SDHI) || defined(CONFIG_MMC_SDHI_MODULE) -void tmio_mmc_start_dma(struct tmio_mmc_host *host, struct mmc_data *data); -void tmio_mmc_enable_dma(struct tmio_mmc_host *host, bool enable); -void tmio_mmc_request_dma(struct tmio_mmc_host *host, struct tmio_mmc_data *pdata); -void tmio_mmc_release_dma(struct tmio_mmc_host *host); -void tmio_mmc_abort_dma(struct tmio_mmc_host *host); -#else -static inline void tmio_mmc_start_dma(struct tmio_mmc_host *host, - struct mmc_data *data) -{ -} - -static inline void tmio_mmc_enable_dma(struct tmio_mmc_host *host, bool enable) -{ -} - -static inline void tmio_mmc_request_dma(struct tmio_mmc_host *host, - struct tmio_mmc_data *pdata) -{ - host->chan_tx = NULL; - host->chan_rx = NULL; -} - -static inline void tmio_mmc_release_dma(struct tmio_mmc_host *host) -{ -} - -static inline void tmio_mmc_abort_dma(struct tmio_mmc_host *host) -{ -} -#endif - #ifdef CONFIG_PM int tmio_mmc_host_runtime_suspend(struct device *dev); int tmio_mmc_host_runtime_resume(struct device *dev); diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_core.c index a2d92f10501b..ed4068125349 100644 --- a/drivers/mmc/host/tmio_mmc_pio.c +++ b/drivers/mmc/host/tmio_mmc_core.c @@ -1,5 +1,7 @@ /* - * linux/drivers/mmc/host/tmio_mmc_pio.c + * Driver for the MMC / SD / SDIO IP found in: + * + * TC6393XB, TC6391XB, TC6387XB, T7L66XB, ASIC3, SH-Mobile SoCs * * Copyright (C) 2016 Sang Engineering, Wolfram Sang * Copyright (C) 2015-16 Renesas Electronics Corporation @@ -11,10 +13,6 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * - * Driver for the MMC / SD / SDIO IP found in: - * - * TC6393XB, TC6391XB, TC6387XB, T7L66XB, ASIC3, SH-Mobile SoCs - * * This driver draws mainly on scattered spec sheets, Reverse engineering * of the toshiba e800 SD driver and some parts of the 2.4 ASIC3 driver (4 bit * support). (Further 4 bit support from a later datasheet). @@ -52,17 +50,55 @@ #include "tmio_mmc.h" +static inline void tmio_mmc_start_dma(struct tmio_mmc_host *host, + struct mmc_data *data) +{ + if (host->dma_ops) + host->dma_ops->start(host, data); +} + +static inline void tmio_mmc_enable_dma(struct tmio_mmc_host *host, bool enable) +{ + if (host->dma_ops) + host->dma_ops->enable(host, enable); +} + +static inline void tmio_mmc_request_dma(struct tmio_mmc_host *host, + struct tmio_mmc_data *pdata) +{ + if (host->dma_ops) { + host->dma_ops->request(host, pdata); + } else { + host->chan_tx = NULL; + host->chan_rx = NULL; + } +} + +static inline void tmio_mmc_release_dma(struct tmio_mmc_host *host) +{ + if (host->dma_ops) + host->dma_ops->release(host); +} + +static inline void tmio_mmc_abort_dma(struct tmio_mmc_host *host) +{ + if (host->dma_ops) + host->dma_ops->abort(host); +} + void tmio_mmc_enable_mmc_irqs(struct tmio_mmc_host *host, u32 i) { host->sdcard_irq_mask &= ~(i & TMIO_MASK_IRQ); sd_ctrl_write32_as_16_and_16(host, CTL_IRQ_MASK, host->sdcard_irq_mask); } +EXPORT_SYMBOL(tmio_mmc_enable_mmc_irqs); void tmio_mmc_disable_mmc_irqs(struct tmio_mmc_host *host, u32 i) { host->sdcard_irq_mask |= (i & TMIO_MASK_IRQ); sd_ctrl_write32_as_16_and_16(host, CTL_IRQ_MASK, host->sdcard_irq_mask); } +EXPORT_SYMBOL(tmio_mmc_disable_mmc_irqs); static void tmio_mmc_ack_mmc_irqs(struct tmio_mmc_host *host, u32 i) { @@ -229,6 +265,12 @@ static void tmio_mmc_reset(struct tmio_mmc_host *host) if (host->pdata->flags & TMIO_MMC_HAVE_HIGH_REG) sd_ctrl_write16(host, CTL_RESET_SDIO, 0x0001); msleep(10); + + if (host->pdata->flags & TMIO_MMC_SDIO_IRQ) { + sd_ctrl_write16(host, CTL_SDIO_IRQ_MASK, host->sdio_irq_mask); + sd_ctrl_write16(host, CTL_TRANSACTION_CTL, 0x0001); + } + } static void tmio_mmc_reset_work(struct work_struct *work) @@ -279,45 +321,6 @@ static void tmio_mmc_reset_work(struct work_struct *work) mmc_request_done(host->mmc, mrq); } -/* called with host->lock held, interrupts disabled */ -static void tmio_mmc_finish_request(struct tmio_mmc_host *host) -{ - struct mmc_request *mrq; - unsigned long flags; - - spin_lock_irqsave(&host->lock, flags); - - mrq = host->mrq; - if (IS_ERR_OR_NULL(mrq)) { - spin_unlock_irqrestore(&host->lock, flags); - return; - } - - host->cmd = NULL; - host->data = NULL; - host->force_pio = false; - - cancel_delayed_work(&host->delayed_reset_work); - - host->mrq = NULL; - spin_unlock_irqrestore(&host->lock, flags); - - if (mrq->cmd->error || (mrq->data && mrq->data->error)) - tmio_mmc_abort_dma(host); - - if (host->check_scc_error) - host->check_scc_error(host); - - mmc_request_done(host->mmc, mrq); -} - -static void tmio_mmc_done_work(struct work_struct *work) -{ - struct tmio_mmc_host *host = container_of(work, struct tmio_mmc_host, - done); - tmio_mmc_finish_request(host); -} - /* These are the bitmasks the tmio chip requires to implement the MMC response * types. Note that R1 and R6 are the same in this scheme. */ #define APP_CMD 0x0040 @@ -371,11 +374,11 @@ static int tmio_mmc_start_command(struct tmio_mmc_host *host, struct mmc_command c |= TRANSFER_MULTI; /* - * Disable auto CMD12 at IO_RW_EXTENDED when - * multiple block transfer + * Disable auto CMD12 at IO_RW_EXTENDED and SET_BLOCK_COUNT + * when doing multiple block transfer */ if ((host->pdata->flags & TMIO_MMC_HAVE_CMD12_CTRL) && - (cmd->opcode == SD_IO_RW_EXTENDED)) + (cmd->opcode == SD_IO_RW_EXTENDED || host->mrq->sbc)) c |= NO_CMD12_ISSUE; } if (data->flags & MMC_DATA_READ) @@ -552,7 +555,7 @@ void tmio_mmc_do_data_irq(struct tmio_mmc_host *host) host->mrq); } - if (stop) { + if (stop && !host->mrq->sbc) { if (stop->opcode != MMC_STOP_TRANSMISSION || stop->arg) dev_err(&host->pdev->dev, "unsupported stop: CMD%u,0x%x. We did CMD12,0\n", stop->opcode, stop->arg); @@ -565,6 +568,7 @@ void tmio_mmc_do_data_irq(struct tmio_mmc_host *host) schedule_work(&host->done); } +EXPORT_SYMBOL(tmio_mmc_do_data_irq); static void tmio_mmc_data_irq(struct tmio_mmc_host *host, unsigned int stat) { @@ -857,12 +861,42 @@ out: return ret; } +static void tmio_process_mrq(struct tmio_mmc_host *host, struct mmc_request *mrq) +{ + struct mmc_command *cmd; + int ret; + + if (mrq->sbc && host->cmd != mrq->sbc) { + cmd = mrq->sbc; + } else { + cmd = mrq->cmd; + if (mrq->data) { + ret = tmio_mmc_start_data(host, mrq->data); + if (ret) + goto fail; + } + } + + ret = tmio_mmc_start_command(host, cmd); + if (ret) + goto fail; + + schedule_delayed_work(&host->delayed_reset_work, + msecs_to_jiffies(CMDREQ_TIMEOUT)); + return; + +fail: + host->force_pio = false; + host->mrq = NULL; + mrq->cmd->error = ret; + mmc_request_done(host->mmc, mrq); +} + /* Process requests from the MMC layer */ static void tmio_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq) { struct tmio_mmc_host *host = mmc_priv(mmc); unsigned long flags; - int ret; spin_lock_irqsave(&host->lock, flags); @@ -882,24 +916,54 @@ static void tmio_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq) spin_unlock_irqrestore(&host->lock, flags); - if (mrq->data) { - ret = tmio_mmc_start_data(host, mrq->data); - if (ret) - goto fail; + tmio_process_mrq(host, mrq); +} + +static void tmio_mmc_finish_request(struct tmio_mmc_host *host) +{ + struct mmc_request *mrq; + unsigned long flags; + + spin_lock_irqsave(&host->lock, flags); + + mrq = host->mrq; + if (IS_ERR_OR_NULL(mrq)) { + spin_unlock_irqrestore(&host->lock, flags); + return; + } + + /* If not SET_BLOCK_COUNT, clear old data */ + if (host->cmd != mrq->sbc) { + host->cmd = NULL; + host->data = NULL; + host->force_pio = false; + host->mrq = NULL; } - ret = tmio_mmc_start_command(host, mrq->cmd); - if (!ret) { - schedule_delayed_work(&host->delayed_reset_work, - msecs_to_jiffies(CMDREQ_TIMEOUT)); + cancel_delayed_work(&host->delayed_reset_work); + + spin_unlock_irqrestore(&host->lock, flags); + + if (mrq->cmd->error || (mrq->data && mrq->data->error)) + tmio_mmc_abort_dma(host); + + if (host->check_scc_error) + host->check_scc_error(host); + + /* If SET_BLOCK_COUNT, continue with main command */ + if (host->mrq) { + tmio_process_mrq(host, mrq); return; } -fail: - host->force_pio = false; - host->mrq = NULL; - mrq->cmd->error = ret; - mmc_request_done(mmc, mrq); + mmc_request_done(host->mmc, mrq); +} + +static void tmio_mmc_done_work(struct work_struct *work) +{ + struct tmio_mmc_host *host = container_of(work, struct tmio_mmc_host, + done); + tmio_mmc_finish_request(host); } static int tmio_mmc_clk_enable(struct tmio_mmc_host *host) @@ -1140,7 +1204,8 @@ void tmio_mmc_host_free(struct tmio_mmc_host *host) EXPORT_SYMBOL(tmio_mmc_host_free); int tmio_mmc_host_probe(struct tmio_mmc_host *_host, - struct tmio_mmc_data *pdata) + struct tmio_mmc_data *pdata, + const struct tmio_mmc_dma_ops *dma_ops) { struct platform_device *pdev = _host->pdev; struct mmc_host *mmc = _host->mmc; @@ -1221,6 +1286,10 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host, if (_host->native_hotplug) pm_runtime_get_noresume(&pdev->dev); + _host->sdio_irq_enabled = false; + if (pdata->flags & TMIO_MMC_SDIO_IRQ) + _host->sdio_irq_mask = TMIO_SDIO_MASK_ALL; + tmio_mmc_clk_stop(_host); tmio_mmc_reset(_host); @@ -1237,13 +1306,6 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host, _host->sdcard_irq_mask &= ~irq_mask; - _host->sdio_irq_enabled = false; - if (pdata->flags & TMIO_MMC_SDIO_IRQ) { - _host->sdio_irq_mask = TMIO_SDIO_MASK_ALL; - sd_ctrl_write16(_host, CTL_SDIO_IRQ_MASK, _host->sdio_irq_mask); - sd_ctrl_write16(_host, CTL_TRANSACTION_CTL, 0x0001); - } - spin_lock_init(&_host->lock); mutex_init(&_host->ios_lock); @@ -1252,6 +1314,7 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host, INIT_WORK(&_host->done, tmio_mmc_done_work); /* See if we also get DMA */ + _host->dma_ops = dma_ops; tmio_mmc_request_dma(_host, pdata); pm_runtime_set_active(&pdev->dev); diff --git a/drivers/mmc/host/vub300.c b/drivers/mmc/host/vub300.c index c061e7c704be..fbeea1a491a6 100644 --- a/drivers/mmc/host/vub300.c +++ b/drivers/mmc/host/vub300.c @@ -2107,7 +2107,8 @@ static int vub300_probe(struct usb_interface *interface, usb_string(udev, udev->descriptor.iSerialNumber, serial_number, sizeof(serial_number)); dev_info(&udev->dev, "probing VID:PID(%04X:%04X) %s %s %s\n", - udev->descriptor.idVendor, udev->descriptor.idProduct, + le16_to_cpu(udev->descriptor.idVendor), + le16_to_cpu(udev->descriptor.idProduct), manufacturer, product, serial_number); command_out_urb = usb_alloc_urb(0, GFP_KERNEL); if (!command_out_urb) { diff --git a/include/linux/mfd/tmio.h b/include/linux/mfd/tmio.h index a1520d88ebf3..c83c16b931a8 100644 --- a/include/linux/mfd/tmio.h +++ b/include/linux/mfd/tmio.h @@ -66,7 +66,7 @@ */ #define TMIO_MMC_SDIO_IRQ (1 << 2) -/* Some features are only available or tested on RCar Gen2 or later */ +/* Some features are only available or tested on R-Car Gen2 or later */ #define TMIO_MMC_MIN_RCAR2 (1 << 3) /* diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h index aad015e0152b..46c73e97e61f 100644 --- a/include/linux/mmc/card.h +++ b/include/linux/mmc/card.h @@ -305,9 +305,7 @@ struct mmc_card { struct mmc_part part[MMC_NUM_PHY_PARTITION]; /* physical partitions */ unsigned int nr_parts; - struct mmc_queue_req *mqrq; /* Shared queue structure */ unsigned int bouncesz; /* Bounce buffer size */ - int qdepth; /* Shared queue depth */ }; static inline bool mmc_large_sector(struct mmc_card *card) diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index 21385ac0c9b1..9209f95a5106 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -130,6 +130,7 @@ struct mmc_host_ops { int (*get_cd)(struct mmc_host *host); void (*enable_sdio_irq)(struct mmc_host *host, int enable); + void (*ack_sdio_irq)(struct mmc_host *host); /* optional callback for HC quirks */ void (*init_card)(struct mmc_host *host, struct mmc_card *card); @@ -270,6 +271,7 @@ struct mmc_host { #define MMC_CAP_UHS_SDR50 (1 << 18) /* Host supports UHS SDR50 mode */ #define MMC_CAP_UHS_SDR104 (1 << 19) /* Host supports UHS SDR104 mode */ #define MMC_CAP_UHS_DDR50 (1 << 20) /* Host supports UHS DDR50 mode */ +#define MMC_CAP_NO_BOUNCE_BUFF (1 << 21) /* Disable bounce buffers on host */ #define MMC_CAP_DRIVER_TYPE_A (1 << 23) /* Host supports Driver Type A */ #define MMC_CAP_DRIVER_TYPE_C (1 << 24) /* Host supports Driver Type C */ #define MMC_CAP_DRIVER_TYPE_D (1 << 25) /* Host supports Driver Type D */ @@ -358,6 +360,7 @@ struct mmc_host { unsigned int sdio_irqs; struct task_struct *sdio_irq_thread; + struct delayed_work sdio_irq_work; bool sdio_irq_pending; atomic_t sdio_irq_thread_abort; @@ -428,6 +431,7 @@ static inline void mmc_signal_sdio_irq(struct mmc_host *host) } void sdio_run_irqs(struct mmc_host *host); +void sdio_signal_irq(struct mmc_host *host); #ifdef CONFIG_REGULATOR int mmc_regulator_get_ocrmask(struct regulator *supply); |