From e9ed8835e99047422e09a192c0f61564d501d49b Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Wed, 12 Oct 2016 10:50:35 +0800 Subject: mmc: dw_mmc: add runtime PM callback This patch add dw_mci_runtime_suspend/resume interfaces and expose it to dw_mci variant driver to support runtime PM. Signed-off-by: Shawn Lin Signed-off-by: Jaehoon Chung Signed-off-by: Ulf Hansson --- drivers/mmc/host/dw_mmc.c | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) (limited to 'drivers/mmc/host/dw_mmc.c') diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index df478ae72e23..875ce2d0ac87 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -3267,7 +3267,7 @@ EXPORT_SYMBOL(dw_mci_remove); -#ifdef CONFIG_PM_SLEEP +#ifdef CONFIG_PM /* * TODO: we should probably disable the clock to the card in the suspend path. */ @@ -3325,7 +3325,35 @@ int dw_mci_resume(struct dw_mci *host) return 0; } EXPORT_SYMBOL(dw_mci_resume); -#endif /* CONFIG_PM_SLEEP */ + +int dw_mci_runtime_suspend(struct device *dev) +{ + int err = 0; + struct dw_mci *host = dev_get_drvdata(dev); + + err = dw_mci_suspend(host); + if (err) + return err; + + clk_disable_unprepare(host->ciu_clk); + + return err; +} +EXPORT_SYMBOL(dw_mci_runtime_suspend); + +int dw_mci_runtime_resume(struct device *dev) +{ + int ret = 0; + struct dw_mci *host = dev_get_drvdata(dev); + + ret = clk_prepare_enable(host->ciu_clk); + if (ret) + return ret; + + return dw_mci_resume(host); +} +EXPORT_SYMBOL(dw_mci_runtime_resume); +#endif /* CONFIG_PM */ static int __init dw_mci_init(void) { -- cgit v1.2.3 From 1f5c51d76e8f3040fd5c2e711d5760d696281307 Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Wed, 12 Oct 2016 10:50:38 +0800 Subject: mmc: dw_mmc: disable biu clk if possible We could disable biu clk if gpio card detect available, or it is a non-removable device. Signed-off-by: Shawn Lin Signed-off-by: Jaehoon Chung Signed-off-by: Ulf Hansson --- drivers/mmc/host/dw_mmc-rockchip.c | 1 + drivers/mmc/host/dw_mmc.c | 13 +++++++++++++ 2 files changed, 14 insertions(+) (limited to 'drivers/mmc/host/dw_mmc.c') diff --git a/drivers/mmc/host/dw_mmc-rockchip.c b/drivers/mmc/host/dw_mmc-rockchip.c index 0a05ad3c5fbf..9a46e4694227 100644 --- a/drivers/mmc/host/dw_mmc-rockchip.c +++ b/drivers/mmc/host/dw_mmc-rockchip.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 875ce2d0ac87..7cf3394139e4 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -3337,6 +3337,11 @@ int dw_mci_runtime_suspend(struct device *dev) clk_disable_unprepare(host->ciu_clk); + if (host->cur_slot && + (mmc_can_gpio_cd(host->cur_slot->mmc) || + !mmc_card_is_removable(host->cur_slot->mmc))) + clk_disable_unprepare(host->biu_clk); + return err; } EXPORT_SYMBOL(dw_mci_runtime_suspend); @@ -3346,6 +3351,14 @@ int dw_mci_runtime_resume(struct device *dev) int ret = 0; struct dw_mci *host = dev_get_drvdata(dev); + if (host->cur_slot && + (mmc_can_gpio_cd(host->cur_slot->mmc) || + !mmc_card_is_removable(host->cur_slot->mmc))) { + ret = clk_prepare_enable(host->biu_clk); + if (ret) + return ret; + } + ret = clk_prepare_enable(host->ciu_clk); if (ret) return ret; -- cgit v1.2.3 From ed24e1ff5ae3d74cda41a2feb7ebe4053d694e37 Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Wed, 12 Oct 2016 10:56:55 +0800 Subject: mmc: dw_mmc: remove system PM callback Now there are no variant drivers using dw_mci_suspend and dw_mci_resume, so let's remove it. Signed-off-by: Shawn Lin Signed-off-by: Jaehoon Chung Signed-off-by: Ulf Hansson --- drivers/mmc/host/dw_mmc.c | 81 ++++++++++++++++------------------------------- drivers/mmc/host/dw_mmc.h | 2 -- 2 files changed, 27 insertions(+), 56 deletions(-) (limited to 'drivers/mmc/host/dw_mmc.c') diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 7cf3394139e4..d426fa41bcce 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -3268,27 +3268,41 @@ EXPORT_SYMBOL(dw_mci_remove); #ifdef CONFIG_PM -/* - * TODO: we should probably disable the clock to the card in the suspend path. - */ -int dw_mci_suspend(struct dw_mci *host) +int dw_mci_runtime_suspend(struct device *dev) { + struct dw_mci *host = dev_get_drvdata(dev); + if (host->use_dma && host->dma_ops->exit) host->dma_ops->exit(host); + clk_disable_unprepare(host->ciu_clk); + + if (host->cur_slot && + (mmc_can_gpio_cd(host->cur_slot->mmc) || + !mmc_card_is_removable(host->cur_slot->mmc))) + clk_disable_unprepare(host->biu_clk); + return 0; } -EXPORT_SYMBOL(dw_mci_suspend); +EXPORT_SYMBOL(dw_mci_runtime_suspend); -int dw_mci_resume(struct dw_mci *host) +int dw_mci_runtime_resume(struct device *dev) { - int i, ret; + int i, ret = 0; + struct dw_mci *host = dev_get_drvdata(dev); - if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_ALL_RESET_FLAGS)) { - ret = -ENODEV; - return ret; + if (host->cur_slot && + (mmc_can_gpio_cd(host->cur_slot->mmc) || + !mmc_card_is_removable(host->cur_slot->mmc))) { + ret = clk_prepare_enable(host->biu_clk); + if (ret) + return ret; } + ret = clk_prepare_enable(host->ciu_clk); + if (ret) + return ret; + if (host->use_dma && host->dma_ops->init) host->dma_ops->init(host); @@ -3296,8 +3310,8 @@ int dw_mci_resume(struct dw_mci *host) * Restore the initial value at FIFOTH register * And Invalidate the prev_blksz with zero */ - mci_writel(host, FIFOTH, host->fifoth_val); - host->prev_blksz = 0; + mci_writel(host, FIFOTH, host->fifoth_val); + host->prev_blksz = 0; /* Put in max timeout */ mci_writel(host, TMOUT, 0xFFFFFFFF); @@ -3322,48 +3336,7 @@ int dw_mci_resume(struct dw_mci *host) /* Now that slots are all setup, we can enable card detect */ dw_mci_enable_cd(host); - return 0; -} -EXPORT_SYMBOL(dw_mci_resume); - -int dw_mci_runtime_suspend(struct device *dev) -{ - int err = 0; - struct dw_mci *host = dev_get_drvdata(dev); - - err = dw_mci_suspend(host); - if (err) - return err; - - clk_disable_unprepare(host->ciu_clk); - - if (host->cur_slot && - (mmc_can_gpio_cd(host->cur_slot->mmc) || - !mmc_card_is_removable(host->cur_slot->mmc))) - clk_disable_unprepare(host->biu_clk); - - return err; -} -EXPORT_SYMBOL(dw_mci_runtime_suspend); - -int dw_mci_runtime_resume(struct device *dev) -{ - int ret = 0; - struct dw_mci *host = dev_get_drvdata(dev); - - if (host->cur_slot && - (mmc_can_gpio_cd(host->cur_slot->mmc) || - !mmc_card_is_removable(host->cur_slot->mmc))) { - ret = clk_prepare_enable(host->biu_clk); - if (ret) - return ret; - } - - ret = clk_prepare_enable(host->ciu_clk); - if (ret) - return ret; - - return dw_mci_resume(host); + return ret; } EXPORT_SYMBOL(dw_mci_runtime_resume); #endif /* CONFIG_PM */ diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h index d14a391eb709..4a6ae750feeb 100644 --- a/drivers/mmc/host/dw_mmc.h +++ b/drivers/mmc/host/dw_mmc.h @@ -235,8 +235,6 @@ extern int dw_mci_probe(struct dw_mci *host); extern void dw_mci_remove(struct dw_mci *host); #ifdef CONFIG_PM -extern int dw_mci_suspend(struct dw_mci *host); -extern int dw_mci_resume(struct dw_mci *host); extern int dw_mci_runtime_suspend(struct device *device); extern int dw_mci_runtime_resume(struct device *device); #endif -- cgit v1.2.3 From 26be9d705f44521d5cf39bfb009a499e870be649 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 16 Nov 2016 18:55:01 +0000 Subject: mmc: dw_mmc: fix spelling mistake in dev_dbg message Trivial fix to spelling mistake "desciptor" to "descriptor" in dev_dbg message. Signed-off-by: Colin Ian King Signed-off-by: Jaehoon Chung Signed-off-by: Ulf Hansson --- drivers/mmc/host/dw_mmc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/mmc/host/dw_mmc.c') diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index d426fa41bcce..080003b00074 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -612,7 +612,7 @@ static inline int dw_mci_prepare_desc64(struct dw_mci *host, return 0; err_own_bit: /* restore the descriptor chain as it's polluted */ - dev_dbg(host->dev, "desciptor is still owned by IDMAC.\n"); + dev_dbg(host->dev, "descriptor is still owned by IDMAC.\n"); memset(host->sg_cpu, 0, DESC_RING_BUF_SZ); dw_mci_idmac_init(host); return -EINVAL; @@ -688,7 +688,7 @@ static inline int dw_mci_prepare_desc32(struct dw_mci *host, return 0; err_own_bit: /* restore the descriptor chain as it's polluted */ - dev_dbg(host->dev, "desciptor is still owned by IDMAC.\n"); + dev_dbg(host->dev, "descriptor is still owned by IDMAC.\n"); memset(host->sg_cpu, 0, DESC_RING_BUF_SZ); dw_mci_idmac_init(host); return -EINVAL; -- cgit v1.2.3 From 21657ebd63774a61841f6f317fedd344df4f5e0c Mon Sep 17 00:00:00 2001 From: Jaehoon Chung Date: Thu, 17 Nov 2016 16:40:33 +0900 Subject: mmc: dw_mmc: display the real register value on debugfs Developer wants to see the real register value, not register offset. This patch fixed to display the real value of register. Signed-off-by: Jaehoon Chung Tested-by: Heiko Stuebner Reviewed-by: Shawn Lin Signed-off-by: Ulf Hansson --- drivers/mmc/host/dw_mmc.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'drivers/mmc/host/dw_mmc.c') diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 080003b00074..3cf2490b16bd 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -165,12 +165,14 @@ static const struct file_operations dw_mci_req_fops = { static int dw_mci_regs_show(struct seq_file *s, void *v) { - seq_printf(s, "STATUS:\t0x%08x\n", SDMMC_STATUS); - seq_printf(s, "RINTSTS:\t0x%08x\n", SDMMC_RINTSTS); - seq_printf(s, "CMD:\t0x%08x\n", SDMMC_CMD); - seq_printf(s, "CTRL:\t0x%08x\n", SDMMC_CTRL); - seq_printf(s, "INTMASK:\t0x%08x\n", SDMMC_INTMASK); - seq_printf(s, "CLKENA:\t0x%08x\n", SDMMC_CLKENA); + struct dw_mci *host = s->private; + + seq_printf(s, "STATUS:\t0x%08x\n", mci_readl(host, STATUS)); + seq_printf(s, "RINTSTS:\t0x%08x\n", mci_readl(host, RINTSTS)); + seq_printf(s, "CMD:\t0x%08x\n", mci_readl(host, CMD)); + seq_printf(s, "CTRL:\t0x%08x\n", mci_readl(host, CTRL)); + seq_printf(s, "INTMASK:\t0x%08x\n", mci_readl(host, INTMASK)); + seq_printf(s, "CLKENA:\t0x%08x\n", mci_readl(host, CLKENA)); return 0; } -- cgit v1.2.3 From 1f4d50790b74ff9ed9e3bfd14f880be5eb6c64af Mon Sep 17 00:00:00 2001 From: Jaehoon Chung Date: Thu, 17 Nov 2016 16:40:34 +0900 Subject: mmc: dw_mmc: fix the debug message for checking card's present If display the debug message, this message should be spamming. If flags is maintained the previous value, didn't display the debug message. Signed-off-by: Jaehoon Chung Tested-by: Heiko Stuebner Reviewed-by: Shawn Lin Signed-off-by: Ulf Hansson --- drivers/mmc/host/dw_mmc.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'drivers/mmc/host/dw_mmc.c') diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 3cf2490b16bd..441ca447c4ba 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -1538,13 +1538,10 @@ static int dw_mci_get_cd(struct mmc_host *mmc) == 0 ? 1 : 0; spin_lock_bh(&host->lock); - if (present) { - set_bit(DW_MMC_CARD_PRESENT, &slot->flags); + if (present && !test_and_set_bit(DW_MMC_CARD_PRESENT, &slot->flags)) dev_dbg(&mmc->class_dev, "card is present\n"); - } else { - clear_bit(DW_MMC_CARD_PRESENT, &slot->flags); + else if (!test_and_clear_bit(DW_MMC_CARD_PRESENT, &slot->flags)) dev_dbg(&mmc->class_dev, "card is not present\n"); - } spin_unlock_bh(&host->lock); return present; -- cgit v1.2.3 From 72e83577bc5bc02a92c7fd47d108de11c04dcbf0 Mon Sep 17 00:00:00 2001 From: Jaehoon Chung Date: Thu, 17 Nov 2016 16:40:35 +0900 Subject: mmc: dw_mmc: change the DW_MCI_FREQ_MIN from 400K to 100K If there is no property "clock-freq-min-max", mmc->f_min should be set to 400K by default. But Some SoC can be used 100K. When 100K is used, MMC core will try to check from 400K to 100K. Reported-by: Shawn Lin Signed-off-by: Jaehoon Chung Tested-by: Heiko Stuebner Reviewed-by: Shawn Lin Signed-off-by: Ulf Hansson --- drivers/mmc/host/dw_mmc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mmc/host/dw_mmc.c') diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 441ca447c4ba..7c7cbb763deb 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -54,7 +54,7 @@ #define DW_MCI_DMA_THRESHOLD 16 #define DW_MCI_FREQ_MAX 200000000 /* unit: HZ */ -#define DW_MCI_FREQ_MIN 400000 /* unit: HZ */ +#define DW_MCI_FREQ_MIN 100000 /* unit: HZ */ #define IDMAC_INT_CLR (SDMMC_IDMAC_INT_AI | SDMMC_IDMAC_INT_NI | \ SDMMC_IDMAC_INT_CES | SDMMC_IDMAC_INT_DU | \ -- cgit v1.2.3 From 8c005b409080b5c98b74b96642d2aacf7f099cf0 Mon Sep 17 00:00:00 2001 From: Jaehoon Chung Date: Thu, 17 Nov 2016 16:40:36 +0900 Subject: mmc: dw_mmc: use the hold register when send stop command If DW_MMC_CARD_NO_USE_HOLD isn't set, it's usesd by default. Enve if SDMMC_CMD_USB_HOLD_REG is set in prepare_command(), but it doesn't set in pre_stop_abort(). To maintain the consistency, add the checking condition for this. Signed-off-by: Jaehoon Chung Tested-by: Heiko Stuebner Reviewed-by: Shawn Lin Signed-off-by: Ulf Hansson --- drivers/mmc/host/dw_mmc.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/mmc/host/dw_mmc.c') diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 7c7cbb763deb..a7620ff56e8e 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -337,6 +337,9 @@ static u32 dw_mci_prep_stop_abort(struct dw_mci *host, struct mmc_command *cmd) cmdr = stop->opcode | SDMMC_CMD_STOP | SDMMC_CMD_RESP_CRC | SDMMC_CMD_RESP_EXP; + if (!test_bit(DW_MMC_CARD_NO_USE_HOLD, &host->cur_slot->flags)) + cmdr |= SDMMC_CMD_USE_HOLD_REG; + return cmdr; } -- cgit v1.2.3 From e13c3c081845b51e8ba71a90e91c52679cfdbf89 Mon Sep 17 00:00:00 2001 From: Jaehoon Chung Date: Thu, 17 Nov 2016 16:40:37 +0900 Subject: mmc: dw_mmc: call the dw_mci_prep_stop_abort() by default stop_cmdr should be set to values relevant to stop command. It migth be assigned to values whatever there is mrq->stop or not. Then it doesn't need to use dw_mci_prepare_command(). It's enough to use the prep_stop_abort for preparing stop command. Signed-off-by: Jaehoon Chung Tested-by: Heiko Stuebner Reviewed-by: Shawn Lin Signed-off-by: Ulf Hansson --- drivers/mmc/host/dw_mmc.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) (limited to 'drivers/mmc/host/dw_mmc.c') diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index a7620ff56e8e..0b220e5a8169 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -385,7 +385,7 @@ static void dw_mci_start_command(struct dw_mci *host, static inline void send_stop_abort(struct dw_mci *host, struct mmc_data *data) { - struct mmc_command *stop = data->stop ? data->stop : &host->stop_abort; + struct mmc_command *stop = &host->stop_abort; dw_mci_start_command(host, stop, host->stop_cmdr); } @@ -1278,10 +1278,7 @@ static void __dw_mci_start_request(struct dw_mci *host, spin_unlock_irqrestore(&host->irq_lock, irqflags); } - if (mrq->stop) - host->stop_cmdr = dw_mci_prepare_command(slot->mmc, mrq->stop); - else - host->stop_cmdr = dw_mci_prep_stop_abort(host, cmd); + host->stop_cmdr = dw_mci_prep_stop_abort(host, cmd); } static void dw_mci_start_request(struct dw_mci *host, @@ -1891,8 +1888,7 @@ static void dw_mci_tasklet_func(unsigned long priv) if (test_and_clear_bit(EVENT_DATA_ERROR, &host->pending_events)) { dw_mci_stop_dma(host); - if (data->stop || - !(host->data_status & (SDMMC_INT_DRTO | + if (!(host->data_status & (SDMMC_INT_DRTO | SDMMC_INT_EBE))) send_stop_abort(host, data); state = STATE_DATA_ERROR; @@ -1928,8 +1924,7 @@ static void dw_mci_tasklet_func(unsigned long priv) if (test_and_clear_bit(EVENT_DATA_ERROR, &host->pending_events)) { dw_mci_stop_dma(host); - if (data->stop || - !(host->data_status & (SDMMC_INT_DRTO | + if (!(host->data_status & (SDMMC_INT_DRTO | SDMMC_INT_EBE))) send_stop_abort(host, data); state = STATE_DATA_ERROR; @@ -2005,7 +2000,7 @@ static void dw_mci_tasklet_func(unsigned long priv) host->cmd = NULL; host->data = NULL; - if (mrq->stop) + if (!mrq->sbc && mrq->stop) dw_mci_command_complete(host, mrq->stop); else host->cmd_status = 0; -- cgit v1.2.3 From a4cc7eb4416fda59f18e744925ba3a347f7ecac5 Mon Sep 17 00:00:00 2001 From: Jaehoon Chung Date: Thu, 17 Nov 2016 16:40:38 +0900 Subject: mmc: dw_mmc: use the cookie's enum values for post/pre_req() This patch removed the meaningless value. Instead, use the cookie's enum values for executing correctly. Signed-off-by: Jaehoon Chung Tested-by: Heiko Stuebner Signed-off-by: Ulf Hansson --- drivers/mmc/host/dw_mmc.c | 39 +++++++++++++++++++-------------------- include/linux/mmc/dw_mmc.h | 6 ++++++ 2 files changed, 25 insertions(+), 20 deletions(-) (limited to 'drivers/mmc/host/dw_mmc.c') diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 0b220e5a8169..65546b6df840 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -414,12 +414,13 @@ static void dw_mci_dma_cleanup(struct dw_mci *host) { struct mmc_data *data = host->data; - if (data) - if (!data->host_cookie) - dma_unmap_sg(host->dev, - data->sg, - data->sg_len, - dw_mci_get_dma_dir(data)); + if (data && data->host_cookie == COOKIE_MAPPED) { + dma_unmap_sg(host->dev, + data->sg, + data->sg_len, + dw_mci_get_dma_dir(data)); + data->host_cookie = COOKIE_UNMAPPED; + } } static void dw_mci_idmac_reset(struct dw_mci *host) @@ -850,13 +851,13 @@ static const struct dw_mci_dma_ops dw_mci_edmac_ops = { static int dw_mci_pre_dma_transfer(struct dw_mci *host, struct mmc_data *data, - bool next) + int cookie) { struct scatterlist *sg; unsigned int i, sg_len; - if (!next && data->host_cookie) - return data->host_cookie; + if (data->host_cookie == COOKIE_PRE_MAPPED) + return data->sg_len; /* * We don't do DMA on "complex" transfers, i.e. with @@ -881,8 +882,7 @@ static int dw_mci_pre_dma_transfer(struct dw_mci *host, if (sg_len == 0) return -EINVAL; - if (next) - data->host_cookie = sg_len; + data->host_cookie = cookie; return sg_len; } @@ -897,13 +897,12 @@ static void dw_mci_pre_req(struct mmc_host *mmc, if (!slot->host->use_dma || !data) return; - if (data->host_cookie) { - data->host_cookie = 0; - return; - } + /* This data might be unmapped at this time */ + data->host_cookie = COOKIE_UNMAPPED; - if (dw_mci_pre_dma_transfer(slot->host, mrq->data, 1) < 0) - data->host_cookie = 0; + if (dw_mci_pre_dma_transfer(slot->host, mrq->data, + COOKIE_PRE_MAPPED) < 0) + data->host_cookie = COOKIE_UNMAPPED; } static void dw_mci_post_req(struct mmc_host *mmc, @@ -916,12 +915,12 @@ static void dw_mci_post_req(struct mmc_host *mmc, if (!slot->host->use_dma || !data) return; - if (data->host_cookie) + if (data->host_cookie != COOKIE_UNMAPPED) dma_unmap_sg(slot->host->dev, data->sg, data->sg_len, dw_mci_get_dma_dir(data)); - data->host_cookie = 0; + data->host_cookie = COOKIE_UNMAPPED; } static void dw_mci_adjust_fifoth(struct dw_mci *host, struct mmc_data *data) @@ -1027,7 +1026,7 @@ static int dw_mci_submit_data_dma(struct dw_mci *host, struct mmc_data *data) if (!host->use_dma) return -ENODEV; - sg_len = dw_mci_pre_dma_transfer(host, data, 0); + sg_len = dw_mci_pre_dma_transfer(host, data, COOKIE_MAPPED); if (sg_len < 0) { host->dma_ops->stop(host); return sg_len; diff --git a/include/linux/mmc/dw_mmc.h b/include/linux/mmc/dw_mmc.h index f5af2bd35e7f..15db6f83f53f 100644 --- a/include/linux/mmc/dw_mmc.h +++ b/include/linux/mmc/dw_mmc.h @@ -39,6 +39,12 @@ enum { EVENT_DATA_ERROR, }; +enum dw_mci_cookie { + COOKIE_UNMAPPED, + COOKIE_PRE_MAPPED, /* mapped by pre_req() of dwmmc */ + COOKIE_MAPPED, /* mapped by prepare_data() of dwmmc */ +}; + struct mmc_data; enum { -- cgit v1.2.3 From 0349c0854eb653596d7a15ef5556e8b55c3d0386 Mon Sep 17 00:00:00 2001 From: Jaehoon Chung Date: Thu, 17 Nov 2016 16:40:39 +0900 Subject: mmc: dw_mmc: remove the unnecessary mmc_data structure Remove the unnecessary mmc_data structure. Instead, cmd->data can be used. Signed-off-by: Jaehoon Chung Tested-by: Heiko Stuebner Reviewed-by: Shawn Lin Signed-off-by: Ulf Hansson --- drivers/mmc/host/dw_mmc.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/mmc/host/dw_mmc.c') diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 65546b6df840..3c553dc22579 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -236,7 +236,6 @@ static void mci_send_cmd(struct dw_mci_slot *slot, u32 cmd, u32 arg); static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd) { - struct mmc_data *data; struct dw_mci_slot *slot = mmc_priv(mmc); struct dw_mci *host = slot->host; u32 cmdr; @@ -291,10 +290,9 @@ static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd) if (cmd->flags & MMC_RSP_CRC) cmdr |= SDMMC_CMD_RESP_CRC; - data = cmd->data; - if (data) { + if (cmd->data) { cmdr |= SDMMC_CMD_DAT_EXP; - if (data->flags & MMC_DATA_WRITE) + if (cmd->data->flags & MMC_DATA_WRITE) cmdr |= SDMMC_CMD_DAT_WR; } -- cgit v1.2.3 From b023030f10573de738bbe8df63d43acab64c9f7b Mon Sep 17 00:00:00 2001 From: Jaehoon Chung Date: Thu, 17 Nov 2016 16:40:40 +0900 Subject: mmc: dw_mmc: The "clock-freq-min-max" property was deprecated The "clock-freq-min-max" property was deprecated. There is "max-frequency" property in drivers/mmc/core/host.c "max-frequency" can be replaced with "clock-freq-min-max". Minimum clock value might be set to 100K by default. Then MMC core should try to find the correct value from 400K to 100K. So it just needs to set Maximum clock value. Signed-off-by: Jaehoon Chung Reviewed-by: Shawn Lin Acked-by: Rob Herring Signed-off-by: Ulf Hansson --- Documentation/devicetree/bindings/mmc/synopsys-dw-mshc.txt | 3 ++- drivers/mmc/host/dw_mmc.c | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/mmc/host/dw_mmc.c') diff --git a/Documentation/devicetree/bindings/mmc/synopsys-dw-mshc.txt b/Documentation/devicetree/bindings/mmc/synopsys-dw-mshc.txt index bfa461aaac99..1279a221640a 100644 --- a/Documentation/devicetree/bindings/mmc/synopsys-dw-mshc.txt +++ b/Documentation/devicetree/bindings/mmc/synopsys-dw-mshc.txt @@ -59,8 +59,9 @@ Optional properties: is specified and the ciu clock is specified then we'll try to set the ciu clock to this at probe time. -* clock-freq-min-max: Minimum and Maximum clock frequency for card output +* clock-freq-min-max (DEPRECATED): Minimum and Maximum clock frequency for card output clock(cclk_out). If it's not specified, max is 200MHZ and min is 400KHz by default. + (Use the "max-frequency" instead of "clock-freq-min-max".) * num-slots: specifies the number of slots supported by the controller. The number of physical slots actually used could be equal or less than the diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 3c553dc22579..881ca3e37da4 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -2609,6 +2609,8 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id) mmc->f_min = DW_MCI_FREQ_MIN; mmc->f_max = DW_MCI_FREQ_MAX; } else { + dev_info(host->dev, + "'clock-freq-min-max' property was deprecated.\n"); mmc->f_min = freq[0]; mmc->f_max = freq[1]; } -- cgit v1.2.3 From d3c6aac3bdfe97b8b44db6a8aba59786cb9531dc Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 23 Nov 2016 11:02:24 +0100 Subject: mmc: delete is_first_req parameter from pre-request callback The void (*pre_req) callback in the struct mmc_host_ops vtable is passing an argument "is_first_req" indicating whether this is the first request or not. None of the in-kernel users use this parameter: instead, since they all just do variants of dma_map* they use the DMA cookie to indicate whether a pre* callback has already been done for a request when they decide how to handle it. Delete the parameter from the callback and all users, as it is just pointless cruft. Signed-off-by: Linus Walleij Acked-by: Jaehoon Chung Signed-off-by: Ulf Hansson --- drivers/mmc/core/core.c | 11 ++++------- drivers/mmc/host/dw_mmc.c | 3 +-- drivers/mmc/host/jz4740_mmc.c | 3 +-- drivers/mmc/host/mmci.c | 3 +-- drivers/mmc/host/mtk-sd.c | 3 +-- drivers/mmc/host/omap_hsmmc.c | 3 +-- drivers/mmc/host/rtsx_pci_sdmmc.c | 3 +-- drivers/mmc/host/sdhci.c | 3 +-- include/linux/mmc/host.h | 3 +-- 9 files changed, 12 insertions(+), 23 deletions(-) (limited to 'drivers/mmc/host/dw_mmc.c') diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 060f76742550..f39397f7c8dc 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -611,18 +611,15 @@ EXPORT_SYMBOL(mmc_is_req_done); * mmc_pre_req - Prepare for a new request * @host: MMC host to prepare command * @mrq: MMC request to prepare for - * @is_first_req: true if there is no previous started request - * that may run in parellel to this call, otherwise false * * mmc_pre_req() is called in prior to mmc_start_req() to let * host prepare for the new request. Preparation of a request may be * performed while another request is running on the host. */ -static void mmc_pre_req(struct mmc_host *host, struct mmc_request *mrq, - bool is_first_req) +static void mmc_pre_req(struct mmc_host *host, struct mmc_request *mrq) { if (host->ops->pre_req) - host->ops->pre_req(host, mrq, is_first_req); + host->ops->pre_req(host, mrq); } /** @@ -667,7 +664,7 @@ struct mmc_async_req *mmc_start_req(struct mmc_host *host, /* Prepare a new request */ if (areq) - mmc_pre_req(host, areq->mrq, !host->areq); + mmc_pre_req(host, areq->mrq); if (host->areq) { status = mmc_wait_for_data_req_done(host, host->areq->mrq, areq); @@ -696,7 +693,7 @@ struct mmc_async_req *mmc_start_req(struct mmc_host *host, /* prepare the request again */ if (areq) - mmc_pre_req(host, areq->mrq, !host->areq); + mmc_pre_req(host, areq->mrq); } } diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 881ca3e37da4..d400afc74719 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -886,8 +886,7 @@ static int dw_mci_pre_dma_transfer(struct dw_mci *host, } static void dw_mci_pre_req(struct mmc_host *mmc, - struct mmc_request *mrq, - bool is_first_req) + struct mmc_request *mrq) { struct dw_mci_slot *slot = mmc_priv(mmc); struct mmc_data *data = mrq->data; diff --git a/drivers/mmc/host/jz4740_mmc.c b/drivers/mmc/host/jz4740_mmc.c index 684087db170b..819ad32964fc 100644 --- a/drivers/mmc/host/jz4740_mmc.c +++ b/drivers/mmc/host/jz4740_mmc.c @@ -320,8 +320,7 @@ dma_unmap: } static void jz4740_mmc_pre_request(struct mmc_host *mmc, - struct mmc_request *mrq, - bool is_first_req) + struct mmc_request *mrq) { struct jz4740_mmc_host *host = mmc_priv(mmc); struct mmc_data *data = mrq->data; diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 6af3ee7b452a..01a804792f30 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -699,8 +699,7 @@ static void mmci_get_next_data(struct mmci_host *host, struct mmc_data *data) next->dma_chan = NULL; } -static void mmci_pre_request(struct mmc_host *mmc, struct mmc_request *mrq, - bool is_first_req) +static void mmci_pre_request(struct mmc_host *mmc, struct mmc_request *mrq) { struct mmci_host *host = mmc_priv(mmc); struct mmc_data *data = mrq->data; diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c index 86af0b199a54..10ef2ae1d2f6 100644 --- a/drivers/mmc/host/mtk-sd.c +++ b/drivers/mmc/host/mtk-sd.c @@ -927,8 +927,7 @@ static void msdc_ops_request(struct mmc_host *mmc, struct mmc_request *mrq) msdc_start_command(host, mrq, mrq->cmd); } -static void msdc_pre_req(struct mmc_host *mmc, struct mmc_request *mrq, - bool is_first_req) +static void msdc_pre_req(struct mmc_host *mmc, struct mmc_request *mrq) { struct msdc_host *host = mmc_priv(mmc); struct mmc_data *data = mrq->data; diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 5f2f24a7360d..ad11c4cc12ed 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -1565,8 +1565,7 @@ static void omap_hsmmc_post_req(struct mmc_host *mmc, struct mmc_request *mrq, } } -static void omap_hsmmc_pre_req(struct mmc_host *mmc, struct mmc_request *mrq, - bool is_first_req) +static void omap_hsmmc_pre_req(struct mmc_host *mmc, struct mmc_request *mrq) { struct omap_hsmmc_host *host = mmc_priv(mmc); diff --git a/drivers/mmc/host/rtsx_pci_sdmmc.c b/drivers/mmc/host/rtsx_pci_sdmmc.c index 3ccaa1415f33..ecb99a8d2fa2 100644 --- a/drivers/mmc/host/rtsx_pci_sdmmc.c +++ b/drivers/mmc/host/rtsx_pci_sdmmc.c @@ -190,8 +190,7 @@ static int sd_pre_dma_transfer(struct realtek_pci_sdmmc *host, return using_cookie; } -static void sdmmc_pre_req(struct mmc_host *mmc, struct mmc_request *mrq, - bool is_first_req) +static void sdmmc_pre_req(struct mmc_host *mmc, struct mmc_request *mrq) { struct realtek_pci_sdmmc *host = mmc_priv(mmc); struct mmc_data *data = mrq->data; diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 62aedf191b0c..7f2526c9572f 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -2202,8 +2202,7 @@ static void sdhci_post_req(struct mmc_host *mmc, struct mmc_request *mrq, data->host_cookie = COOKIE_UNMAPPED; } -static void sdhci_pre_req(struct mmc_host *mmc, struct mmc_request *mrq, - bool is_first_req) +static void sdhci_pre_req(struct mmc_host *mmc, struct mmc_request *mrq) { struct sdhci_host *host = mmc_priv(mmc); diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index 68639295148d..2a6418d0c343 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -93,8 +93,7 @@ struct mmc_host_ops { */ void (*post_req)(struct mmc_host *host, struct mmc_request *req, int err); - void (*pre_req)(struct mmc_host *host, struct mmc_request *req, - bool is_first_req); + void (*pre_req)(struct mmc_host *host, struct mmc_request *req); void (*request)(struct mmc_host *host, struct mmc_request *req); /* -- cgit v1.2.3 From df9bcc2bc0a1f8d2963bd916698268fb2470713b Mon Sep 17 00:00:00 2001 From: Joonyoung Shim Date: Fri, 25 Nov 2016 12:47:15 +0900 Subject: mmc: dw_mmc: add missing codes for runtime resume The commit 64997de4fd17 ("mmc: dw_mmc: remove system PM callback") is missing to call dw_mci_ctrl_reset(). This adds to call dw_mci_ctrl_reset() and to handle error of clocks. Signed-off-by: Joonyoung Shim Signed-off-by: Jaehoon Chung Signed-off-by: Ulf Hansson --- drivers/mmc/host/dw_mmc.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) (limited to 'drivers/mmc/host/dw_mmc.c') diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index d400afc74719..0aa4bcd85bb7 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -3296,7 +3296,13 @@ int dw_mci_runtime_resume(struct device *dev) ret = clk_prepare_enable(host->ciu_clk); if (ret) - return ret; + goto err; + + if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_ALL_RESET_FLAGS)) { + clk_disable_unprepare(host->ciu_clk); + ret = -ENODEV; + goto err; + } if (host->use_dma && host->dma_ops->init) host->dma_ops->init(host); @@ -3331,6 +3337,14 @@ int dw_mci_runtime_resume(struct device *dev) /* Now that slots are all setup, we can enable card detect */ dw_mci_enable_cd(host); + return 0; + +err: + if (host->cur_slot && + (mmc_can_gpio_cd(host->cur_slot->mmc) || + !mmc_card_is_removable(host->cur_slot->mmc))) + clk_disable_unprepare(host->biu_clk); + return ret; } EXPORT_SYMBOL(dw_mci_runtime_resume); -- cgit v1.2.3 From 1c238a95a727e8cd3fe1c97a653c4101b8dd39d2 Mon Sep 17 00:00:00 2001 From: Jaehoon Chung Date: Thu, 24 Nov 2016 20:04:40 +0900 Subject: mmc: dw_mmc: check the "present" variable before checking flags Before checking flags, it has to check "present" variable. Otherwise, flags should be cleared everytime. Signed-off-by: Jaehoon Chung Signed-off-by: Ulf Hansson --- drivers/mmc/host/dw_mmc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/mmc/host/dw_mmc.c') diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 0aa4bcd85bb7..c0e96ade4cc9 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -1536,7 +1536,8 @@ static int dw_mci_get_cd(struct mmc_host *mmc) spin_lock_bh(&host->lock); if (present && !test_and_set_bit(DW_MMC_CARD_PRESENT, &slot->flags)) dev_dbg(&mmc->class_dev, "card is present\n"); - else if (!test_and_clear_bit(DW_MMC_CARD_PRESENT, &slot->flags)) + else if (!present && + !test_and_clear_bit(DW_MMC_CARD_PRESENT, &slot->flags)) dev_dbg(&mmc->class_dev, "card is not present\n"); spin_unlock_bh(&host->lock); -- cgit v1.2.3 From d10111cf8586e16dbdbe8ed60de7065b54a70df1 Mon Sep 17 00:00:00 2001 From: Jaehoon Chung Date: Thu, 24 Nov 2016 20:04:41 +0900 Subject: mmc: dw_mmc: add the debug message for polling and non-removable If card is polling or non-removable, display the more exact message. It's helpful to debug which detecting scheme is using. Signed-off-by: Jaehoon Chung Signed-off-by: Ulf Hansson --- drivers/mmc/host/dw_mmc.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) (limited to 'drivers/mmc/host/dw_mmc.c') diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index c0e96ade4cc9..45b1a3de0b68 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -1525,9 +1525,23 @@ static int dw_mci_get_cd(struct mmc_host *mmc) int gpio_cd = mmc_gpio_get_cd(mmc); /* Use platform get_cd function, else try onboard card detect */ - if ((mmc->caps & MMC_CAP_NEEDS_POLL) || !mmc_card_is_removable(mmc)) + if (((mmc->caps & MMC_CAP_NEEDS_POLL) + || !mmc_card_is_removable(mmc))) { present = 1; - else if (gpio_cd >= 0) + + if (!test_bit(DW_MMC_CARD_PRESENT, &slot->flags)) { + if (mmc->caps & MMC_CAP_NEEDS_POLL) { + dev_info(&mmc->class_dev, + "card is polling.\n"); + } else { + dev_info(&mmc->class_dev, + "card is non-removable.\n"); + } + set_bit(DW_MMC_CARD_PRESENT, &slot->flags); + } + + return present; + } else if (gpio_cd >= 0) present = gpio_cd; else present = (mci_readl(slot->host, CDETECT) & (1 << slot->id)) -- cgit v1.2.3 From e6cd7a8ea1c3efe412e6b9e900b635ea29764f70 Mon Sep 17 00:00:00 2001 From: Jaehoon Chung Date: Thu, 24 Nov 2016 20:04:42 +0900 Subject: mmc: dw_mmc: display the clock message only one time when card is polling When card is polling (broken-cd), there is a spamming messge related to clock. After applied this patch, display the message only one time at boot time. It's enough to check which clock values is used. Also prevent to display the spamming message. Signed-off-by: Jaehoon Chung Signed-off-by: Ulf Hansson --- drivers/mmc/host/dw_mmc.c | 13 ++++++++++++- drivers/mmc/host/dw_mmc.h | 1 + 2 files changed, 13 insertions(+), 1 deletion(-) (limited to 'drivers/mmc/host/dw_mmc.c') diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 45b1a3de0b68..b44306b886cb 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -1176,13 +1176,24 @@ static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool force_clkinit) div = (host->bus_hz != clock) ? DIV_ROUND_UP(div, 2) : 0; - if (clock != slot->__clk_old || force_clkinit) + if ((clock != slot->__clk_old && + !test_bit(DW_MMC_CARD_NEEDS_POLL, &slot->flags)) || + force_clkinit) { dev_info(&slot->mmc->class_dev, "Bus speed (slot %d) = %dHz (slot req %dHz, actual %dHZ div = %d)\n", slot->id, host->bus_hz, clock, div ? ((host->bus_hz / div) >> 1) : host->bus_hz, div); + /* + * If card is polling, display the message only + * one time at boot time. + */ + if (slot->mmc->caps & MMC_CAP_NEEDS_POLL && + slot->mmc->f_min == clock) + set_bit(DW_MMC_CARD_NEEDS_POLL, &slot->flags); + } + /* disable clock */ mci_writel(host, CLKENA, 0); mci_writel(host, CLKSRC, 0); diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h index 4a6ae750feeb..c59465829387 100644 --- a/drivers/mmc/host/dw_mmc.h +++ b/drivers/mmc/host/dw_mmc.h @@ -272,6 +272,7 @@ struct dw_mci_slot { #define DW_MMC_CARD_NEED_INIT 1 #define DW_MMC_CARD_NO_LOW_PWR 2 #define DW_MMC_CARD_NO_USE_HOLD 3 +#define DW_MMC_CARD_NEEDS_POLL 4 int id; int sdio_id; }; -- cgit v1.2.3