From c51ff6c6180e76a1ba96aef799a9c41aa80fcc95 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Fri, 9 Dec 2016 17:51:41 +0100 Subject: [PATCH 001/145] mmc: tmio: use SDIO master interrupt bit only when allowed The master bit to enable SDIO interrupts can only be accessed if SCLKDIVEN bit allows that. However, the core uses the SDIO enable callback at times when SCLKDIVEN forbids the change. This leads to "timeout waiting for SD bus idle" messages. We now activate the master bit in probe once if SDIO is supported. IRQ en-/disabling will be done now by the individual IRQ enablement bits only. Signed-off-by: Wolfram Sang Reviewed-by: Yasushi SHOJI Signed-off-by: Ulf Hansson --- drivers/mmc/host/tmio_mmc_pio.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c index 2064fa1a5bf1..3ca97f3c3079 100644 --- a/drivers/mmc/host/tmio_mmc_pio.c +++ b/drivers/mmc/host/tmio_mmc_pio.c @@ -140,12 +140,10 @@ static void tmio_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable) host->sdio_irq_mask = TMIO_SDIO_MASK_ALL & ~TMIO_SDIO_STAT_IOIRQ; - sd_ctrl_write16(host, CTL_TRANSACTION_CTL, 0x0001); sd_ctrl_write16(host, CTL_SDIO_IRQ_MASK, host->sdio_irq_mask); } else if (!enable && host->sdio_irq_enabled) { 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, 0x0000); host->sdio_irq_enabled = false; pm_runtime_mark_last_busy(mmc_dev(mmc)); @@ -1232,7 +1230,7 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host, 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, 0x0000); + sd_ctrl_write16(_host, CTL_TRANSACTION_CTL, 0x0001); } spin_lock_init(&_host->lock); @@ -1280,6 +1278,9 @@ void tmio_mmc_host_remove(struct tmio_mmc_host *host) struct platform_device *pdev = host->pdev; struct mmc_host *mmc = host->mmc; + if (host->pdata->flags & TMIO_MMC_SDIO_IRQ) + sd_ctrl_write16(host, CTL_TRANSACTION_CTL, 0x0000); + if (!host->native_hotplug) pm_runtime_get_sync(&pdev->dev); From dc9f1a8d790ee766c47eca163261225680691e64 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Mon, 12 Dec 2016 20:51:20 +0100 Subject: [PATCH 002/145] mmc: sh_mobile_sdhi: simplify accessing DT data By using the helper of_device_get_match_data(), we can skip some checking and make the code simpler. Signed-off-by: Wolfram Sang Reviewed-by: Geert Uytterhoeven Signed-off-by: Ulf Hansson --- drivers/mmc/host/sh_mobile_sdhi.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/sh_mobile_sdhi.c index d46c2d00c182..a6887cf4ce1b 100644 --- a/drivers/mmc/host/sh_mobile_sdhi.c +++ b/drivers/mmc/host/sh_mobile_sdhi.c @@ -556,8 +556,7 @@ static void sh_mobile_sdhi_enable_dma(struct tmio_mmc_host *host, bool enable) static int sh_mobile_sdhi_probe(struct platform_device *pdev) { - const struct of_device_id *of_id = - of_match_device(sh_mobile_sdhi_of_match, &pdev->dev); + const struct sh_mobile_sdhi_of_data *of_data = of_device_get_match_data(&pdev->dev); struct sh_mobile_sdhi *priv; struct tmio_mmc_data *mmc_data; struct tmio_mmc_data *mmd = pdev->dev.platform_data; @@ -598,9 +597,8 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev) goto eprobe; } - if (of_id && of_id->data) { - const struct sh_mobile_sdhi_of_data *of_data = of_id->data; + if (of_data) { mmc_data->flags |= of_data->tmio_flags; mmc_data->ocr_mask = of_data->tmio_ocr_mask; mmc_data->capabilities |= of_data->capabilities; @@ -671,14 +669,10 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev) if (host->mmc->caps & MMC_CAP_UHS_SDR104) { host->mmc->caps |= MMC_CAP_HW_RESET; - if (of_id && of_id->data) { - const struct sh_mobile_sdhi_of_data *of_data; - const struct sh_mobile_sdhi_scc *taps; + if (of_data) { + const struct sh_mobile_sdhi_scc *taps = of_data->taps; bool hit = false; - of_data = of_id->data; - taps = of_data->taps; - for (i = 0; i < of_data->taps_num; i++) { if (taps[i].clk_rate == 0 || taps[i].clk_rate == host->mmc->f_max) { From 6ade9a2c2da855ff38e74c4298976400feca968e Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Mon, 12 Dec 2016 20:51:21 +0100 Subject: [PATCH 003/145] mmc: sh_mobile_sdhi: improve prerequisite for hw_reset We need a SCC unit for hw_reset. Those units can only be described in of_data. So, of_data and a valid SCC offset are prerequisites for enabling the hw_reset capability. Merge the two 'if' conditions into one and add a check for an scc offset. Signed-off-by: Wolfram Sang Reviewed-by: Geert Uytterhoeven Signed-off-by: Ulf Hansson --- drivers/mmc/host/sh_mobile_sdhi.c | 32 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/sh_mobile_sdhi.c index a6887cf4ce1b..0a22b45b1605 100644 --- a/drivers/mmc/host/sh_mobile_sdhi.c +++ b/drivers/mmc/host/sh_mobile_sdhi.c @@ -666,27 +666,25 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev) if (ret < 0) goto efree; - if (host->mmc->caps & MMC_CAP_UHS_SDR104) { + if (of_data && of_data->scc_offset && host->mmc->caps & MMC_CAP_UHS_SDR104) { + const struct sh_mobile_sdhi_scc *taps = of_data->taps; + bool hit = false; + host->mmc->caps |= MMC_CAP_HW_RESET; - if (of_data) { - const struct sh_mobile_sdhi_scc *taps = of_data->taps; - bool hit = false; - - for (i = 0; i < of_data->taps_num; i++) { - if (taps[i].clk_rate == 0 || - taps[i].clk_rate == host->mmc->f_max) { - host->scc_tappos = taps->tap; - hit = true; - break; - } + for (i = 0; i < of_data->taps_num; i++) { + if (taps[i].clk_rate == 0 || + taps[i].clk_rate == host->mmc->f_max) { + host->scc_tappos = taps->tap; + hit = true; + break; } - - if (!hit) - dev_warn(&host->pdev->dev, "Unknown clock rate for SDR104\n"); - - priv->scc_ctl = host->ctl + of_data->scc_offset; } + + if (!hit) + dev_warn(&host->pdev->dev, "Unknown clock rate for SDR104\n"); + + priv->scc_ctl = host->ctl + of_data->scc_offset; } i = 0; From e831ead3b3ddc4227cef10dc63d919fd7242d7b8 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Mon, 12 Dec 2016 20:51:22 +0100 Subject: [PATCH 004/145] mmc: sh_mobile_sdhi: improve prerequisites for tuning Prerequisites for tuning are the same as for hw_reset. We need an SCC and a supported mode. Populate the tuning related functions only when those conditions are met. This also removes a tiny race window. Previously, the functions were populated when the SCC offset was not initialized which could have led to an OOPS. Signed-off-by: Wolfram Sang Signed-off-by: Ulf Hansson --- drivers/mmc/host/sh_mobile_sdhi.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/sh_mobile_sdhi.c index 0a22b45b1605..b30c7f7f988c 100644 --- a/drivers/mmc/host/sh_mobile_sdhi.c +++ b/drivers/mmc/host/sh_mobile_sdhi.c @@ -621,11 +621,6 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev) host->card_busy = sh_mobile_sdhi_card_busy; host->start_signal_voltage_switch = sh_mobile_sdhi_start_signal_voltage_switch; - 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; } /* Orginally registers were 16 bit apart, could be 32 or 64 nowadays */ @@ -666,6 +661,7 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev) if (ret < 0) goto efree; + /* Enable tuning iff we have an SCC and a supported mode */ if (of_data && of_data->scc_offset && host->mmc->caps & MMC_CAP_UHS_SDR104) { const struct sh_mobile_sdhi_scc *taps = of_data->taps; bool hit = false; @@ -685,6 +681,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; } i = 0; From 97c64b2cd57608f7064810780056d17944f49128 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Mon, 12 Dec 2016 20:51:23 +0100 Subject: [PATCH 005/145] mmc: sh_mobile_sdhi: remove superfluous check in hw_reset The capability for HW_RESET is only activated if SDR104 is present, so no need to check for SDR104 in the function itself again. Signed-off-by: Wolfram Sang Signed-off-by: Ulf Hansson --- drivers/mmc/host/sh_mobile_sdhi.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/sh_mobile_sdhi.c index b30c7f7f988c..3f986e802980 100644 --- a/drivers/mmc/host/sh_mobile_sdhi.c +++ b/drivers/mmc/host/sh_mobile_sdhi.c @@ -468,9 +468,6 @@ static void sh_mobile_sdhi_hw_reset(struct tmio_mmc_host *host) { struct sh_mobile_sdhi *priv; - if (!(host->mmc->caps & MMC_CAP_UHS_SDR104)) - return; - priv = host_to_priv(host); /* Reset SCC */ From 7f9096f1c89ea698c22fde91285de2ef3eabd614 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Mon, 12 Dec 2016 20:51:24 +0100 Subject: [PATCH 006/145] mmc: sh_mobile_sdhi: remove superfluous check in init_tuning The function will only be available if SDR104 was detected in probe, so no need to check in the function itself again. Signed-off-by: Wolfram Sang Signed-off-by: Ulf Hansson --- drivers/mmc/host/sh_mobile_sdhi.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/sh_mobile_sdhi.c index 3f986e802980..6e8972b310c1 100644 --- a/drivers/mmc/host/sh_mobile_sdhi.c +++ b/drivers/mmc/host/sh_mobile_sdhi.c @@ -335,9 +335,6 @@ static unsigned int sh_mobile_sdhi_init_tuning(struct tmio_mmc_host *host) { struct sh_mobile_sdhi *priv; - if (!(host->mmc->caps & MMC_CAP_UHS_SDR104)) - return 0; - priv = host_to_priv(host); /* set sampling clock selection range */ From 03c5b0d90300fc725fc1fb644872b522483a2d7e Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Mon, 12 Dec 2016 20:51:25 +0100 Subject: [PATCH 007/145] mmc: sh_mobile_sdhi: remove superfluous check in SCC error check The function will only be available if SDR104 was detected in probe, so no need to check in the function itself again. Signed-off-by: Wolfram Sang Signed-off-by: Ulf Hansson --- drivers/mmc/host/sh_mobile_sdhi.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/sh_mobile_sdhi.c index 6e8972b310c1..72c2dbc74c9f 100644 --- a/drivers/mmc/host/sh_mobile_sdhi.c +++ b/drivers/mmc/host/sh_mobile_sdhi.c @@ -441,12 +441,7 @@ 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) { - struct sh_mobile_sdhi *priv; - - if (!(host->mmc->caps & MMC_CAP_UHS_SDR104)) - return 0; - - priv = host_to_priv(host); + struct sh_mobile_sdhi *priv = host_to_priv(host); /* Check SCC error */ if (sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL) & From b1c95170f97ef19ff63a6da1eb2c70899186aecc Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Mon, 12 Dec 2016 20:51:26 +0100 Subject: [PATCH 008/145] mmc: sh_mobile_sdhi: enable HS200 Setup tuning when the board is HS200 enabled. Signed-off-by: Wolfram Sang Signed-off-by: Ulf Hansson --- drivers/mmc/host/sh_mobile_sdhi.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/sh_mobile_sdhi.c index 72c2dbc74c9f..59db14b4827c 100644 --- a/drivers/mmc/host/sh_mobile_sdhi.c +++ b/drivers/mmc/host/sh_mobile_sdhi.c @@ -651,7 +651,9 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev) goto efree; /* Enable tuning iff we have an SCC and a supported mode */ - if (of_data && of_data->scc_offset && host->mmc->caps & MMC_CAP_UHS_SDR104) { + 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; bool hit = false; From 46bc5c408e4e325efbfff26609c76099979180a7 Mon Sep 17 00:00:00 2001 From: Jungseung Lee Date: Thu, 22 Dec 2016 12:37:34 +0900 Subject: [PATCH 009/145] mmc: core: Export device lifetime information through sysfs In the eMMC 5.0 version of the spec, several EXT_CSD fields about device lifetime are added. - Two types of estimated indications reflected by averaged wear out of memory - An indication reflected by average reserved blocks Export the information through sysfs. Signed-off-by: Jungseung Lee Reviewed-by: Jaehoon Chung Reviewed-by: Shawn Lin Signed-off-by: Ulf Hansson --- drivers/mmc/core/mmc.c | 12 ++++++++++++ include/linux/mmc/card.h | 3 +++ include/linux/mmc/mmc.h | 3 +++ 3 files changed, 18 insertions(+) diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index b61b52f9da3d..c0e250706353 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -617,6 +617,12 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd) card->ext_csd.ffu_capable = (ext_csd[EXT_CSD_SUPPORTED_MODE] & 0x1) && !(ext_csd[EXT_CSD_FW_CONFIG] & 0x1); + + card->ext_csd.pre_eol_info = ext_csd[EXT_CSD_PRE_EOL_INFO]; + card->ext_csd.device_life_time_est_typ_a = + ext_csd[EXT_CSD_DEVICE_LIFE_TIME_EST_TYP_A]; + card->ext_csd.device_life_time_est_typ_b = + ext_csd[EXT_CSD_DEVICE_LIFE_TIME_EST_TYP_B]; } /* eMMC v5.1 or later */ @@ -764,6 +770,10 @@ MMC_DEV_ATTR(manfid, "0x%06x\n", card->cid.manfid); MMC_DEV_ATTR(name, "%s\n", card->cid.prod_name); MMC_DEV_ATTR(oemid, "0x%04x\n", card->cid.oemid); MMC_DEV_ATTR(prv, "0x%x\n", card->cid.prv); +MMC_DEV_ATTR(pre_eol_info, "%02x\n", card->ext_csd.pre_eol_info); +MMC_DEV_ATTR(life_time, "0x%02x 0x%02x\n", + card->ext_csd.device_life_time_est_typ_a, + card->ext_csd.device_life_time_est_typ_b); MMC_DEV_ATTR(serial, "0x%08x\n", card->cid.serial); MMC_DEV_ATTR(enhanced_area_offset, "%llu\n", card->ext_csd.enhanced_area_offset); @@ -817,6 +827,8 @@ static struct attribute *mmc_std_attrs[] = { &dev_attr_name.attr, &dev_attr_oemid.attr, &dev_attr_prv.attr, + &dev_attr_pre_eol_info.attr, + &dev_attr_life_time.attr, &dev_attr_serial.attr, &dev_attr_enhanced_area_offset.attr, &dev_attr_enhanced_area_size.attr, diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h index 95d69d498296..00449e51838a 100644 --- a/include/linux/mmc/card.h +++ b/include/linux/mmc/card.h @@ -121,6 +121,9 @@ struct mmc_ext_csd { u8 raw_pwr_cl_ddr_200_360; /* 253 */ u8 raw_bkops_status; /* 246 */ u8 raw_sectors[4]; /* 212 - 4 bytes */ + u8 pre_eol_info; /* 267 */ + u8 device_life_time_est_typ_a; /* 268 */ + u8 device_life_time_est_typ_b; /* 269 */ unsigned int feature_support; #define MMC_DISCARD_FEATURE BIT(0) /* CMD38 feature */ diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h index 672730acc705..a0740829ff00 100644 --- a/include/linux/mmc/mmc.h +++ b/include/linux/mmc/mmc.h @@ -339,6 +339,9 @@ struct _mmc_csd { #define EXT_CSD_CACHE_SIZE 249 /* RO, 4 bytes */ #define EXT_CSD_PWR_CL_DDR_200_360 253 /* RO */ #define EXT_CSD_FIRMWARE_VERSION 254 /* RO, 8 bytes */ +#define EXT_CSD_PRE_EOL_INFO 267 /* RO */ +#define EXT_CSD_DEVICE_LIFE_TIME_EST_TYP_A 268 /* RO */ +#define EXT_CSD_DEVICE_LIFE_TIME_EST_TYP_B 269 /* RO */ #define EXT_CSD_CMDQ_DEPTH 307 /* RO */ #define EXT_CSD_CMDQ_SUPPORT 308 /* RO */ #define EXT_CSD_SUPPORTED_MODE 493 /* RO */ From 8cb6ed17eb30f190f215031844433981644b064d Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 19 Dec 2016 15:03:44 +0100 Subject: [PATCH 010/145] mmc: block: Avoid uninitialized warning in mmc_blk_issue_discard_rq() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With gcc-4.1.2: mmc/core/block.c: In function ‘mmc_blk_issue_discard_rq’: mmc/core/block.c:1150: warning: ‘arg’ may be used uninitialized in this function mmc/core/block.c:1150: warning: ‘nr’ may be used uninitialized in this function mmc/core/block.c:1150: warning: ‘from’ may be used uninitialized in this function While this is a false positive, it can be avoided easily by jumping over the checks for "err" that are always false. Signed-off-by: Geert Uytterhoeven Signed-off-by: Ulf Hansson --- drivers/mmc/core/block.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index cb1698f268f1..5f942a34d65c 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -1152,7 +1152,7 @@ static int mmc_blk_issue_discard_rq(struct mmc_queue *mq, struct request *req) if (!mmc_can_erase(card)) { err = -EOPNOTSUPP; - goto out; + goto fail; } from = blk_rq_pos(req); @@ -1181,6 +1181,7 @@ out: goto retry; if (!err) mmc_blk_reset_success(md, type); +fail: blk_end_request(req, err, blk_rq_bytes(req)); return err ? 0 : 1; From 164b50b353908c79b551b3658e37f29182e2c0b3 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 19 Dec 2016 15:03:45 +0100 Subject: [PATCH 011/145] mmc: block: Replace "goto retry" by a proper do / while loop Signed-off-by: Geert Uytterhoeven Signed-off-by: Ulf Hansson --- drivers/mmc/core/block.c | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index 5f942a34d65c..6648a17b96c0 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -1164,21 +1164,19 @@ static int mmc_blk_issue_discard_rq(struct mmc_queue *mq, struct request *req) arg = MMC_TRIM_ARG; else arg = MMC_ERASE_ARG; -retry: - if (card->quirks & MMC_QUIRK_INAND_CMD38) { - err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, - INAND_CMD38_ARG_EXT_CSD, - arg == MMC_TRIM_ARG ? - INAND_CMD38_ARG_TRIM : - INAND_CMD38_ARG_ERASE, - 0); - if (err) - goto out; - } - err = mmc_erase(card, from, nr, arg); -out: - if (err == -EIO && !mmc_blk_reset(md, card->host, type)) - goto retry; + do { + err = 0; + if (card->quirks & MMC_QUIRK_INAND_CMD38) { + err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, + INAND_CMD38_ARG_EXT_CSD, + arg == MMC_TRIM_ARG ? + INAND_CMD38_ARG_TRIM : + INAND_CMD38_ARG_ERASE, + 0); + } + if (!err) + err = mmc_erase(card, from, nr, arg); + } while (err == -EIO && !mmc_blk_reset(md, card->host, type)); if (!err) mmc_blk_reset_success(md, type); fail: From c7836d1593b87cb813c58cf64e08b052ebbe2a78 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Mon, 19 Dec 2016 20:51:18 +0900 Subject: [PATCH 012/145] mmc: use empty initializer list to zero-clear structures In the MMC subsystem, we see such initializers that only clears the first member explicitly. For example, struct mmc_request mrq = {NULL}; sets the first member (.sbc) to NULL explicitly. However, this is an unstable form because we may insert a non-pointer member at the top of the struct mmc_request in the future. (if we do so, the compiler will spit warnings.) So, using a designated initializer is preferred coding style. The expression above is equivalent to: struct mmc_request mrq = { .sbc = NULL }; Of course, this does not express our intention. We want to fill all struct members with zeros. Please note struct members are implicitly zero-cleared unless otherwise specified in the initializer. After all, the most reasonable (and stable) form is: struct mmc_request mrq = {}; Do likewise for mmc_command, mmc_data as well. Signed-off-by: Masahiro Yamada Reviewed-by: Linus Walleij Signed-off-by: Ulf Hansson --- drivers/mmc/core/block.c | 16 +++++------ drivers/mmc/core/core.c | 10 +++---- drivers/mmc/core/mmc.c | 2 +- drivers/mmc/core/mmc_ops.c | 44 +++++++++++++++---------------- drivers/mmc/core/mmc_test.c | 26 +++++++++--------- drivers/mmc/core/sd_ops.c | 30 ++++++++++----------- drivers/mmc/core/sdio_ops.c | 10 +++---- drivers/mmc/host/rtsx_pci_sdmmc.c | 2 +- drivers/mmc/host/rtsx_usb_sdmmc.c | 2 +- drivers/mmc/host/sdhci.c | 4 +-- 10 files changed, 73 insertions(+), 73 deletions(-) diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index 6648a17b96c0..6adc3ce28447 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -442,9 +442,9 @@ out: static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md, struct mmc_blk_ioc_data *idata) { - struct mmc_command cmd = {0}; - struct mmc_data data = {0}; - struct mmc_request mrq = {NULL}; + struct mmc_command cmd = {}; + struct mmc_data data = {}; + struct mmc_request mrq = {}; struct scatterlist sg; int err; int is_rpmb = false; @@ -768,9 +768,9 @@ static u32 mmc_sd_num_wr_blocks(struct mmc_card *card) u32 result; __be32 *blocks; - struct mmc_request mrq = {NULL}; - struct mmc_command cmd = {0}; - struct mmc_data data = {0}; + struct mmc_request mrq = {}; + struct mmc_command cmd = {}; + struct mmc_data data = {}; struct scatterlist sg; @@ -819,7 +819,7 @@ static u32 mmc_sd_num_wr_blocks(struct mmc_card *card) static int get_card_status(struct mmc_card *card, u32 *status, int retries) { - struct mmc_command cmd = {0}; + struct mmc_command cmd = {}; int err; cmd.opcode = MMC_SEND_STATUS; @@ -884,7 +884,7 @@ static int send_stop(struct mmc_card *card, unsigned int timeout_ms, struct request *req, bool *gen_err, u32 *stop_status) { struct mmc_host *host = card->host; - struct mmc_command cmd = {0}; + struct mmc_command cmd = {}; int err; bool use_r1b_resp = rq_data_dir(req) == WRITE; diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 1076b9d89df3..3b34a751eea1 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -807,7 +807,7 @@ EXPORT_SYMBOL(mmc_interrupt_hpi); */ int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, int retries) { - struct mmc_request mrq = {NULL}; + struct mmc_request mrq = {}; WARN_ON(!host->claimed); @@ -1648,7 +1648,7 @@ int __mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage) int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage, u32 ocr) { - struct mmc_command cmd = {0}; + struct mmc_command cmd = {}; int err = 0; u32 clock; @@ -2129,7 +2129,7 @@ static unsigned int mmc_erase_timeout(struct mmc_card *card, static int mmc_do_erase(struct mmc_card *card, unsigned int from, unsigned int to, unsigned int arg) { - struct mmc_command cmd = {0}; + struct mmc_command cmd = {}; unsigned int qty = 0, busy_timeout = 0; bool use_r1b_resp = false; unsigned long timeout; @@ -2551,7 +2551,7 @@ EXPORT_SYMBOL(mmc_calc_max_discard); int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen) { - struct mmc_command cmd = {0}; + struct mmc_command cmd = {}; if (mmc_card_blockaddr(card) || mmc_card_ddr52(card) || mmc_card_hs400(card) || mmc_card_hs400es(card)) @@ -2567,7 +2567,7 @@ EXPORT_SYMBOL(mmc_set_blocklen); int mmc_set_blockcount(struct mmc_card *card, unsigned int blockcount, bool is_rel_write) { - struct mmc_command cmd = {0}; + struct mmc_command cmd = {}; cmd.opcode = MMC_SET_BLOCK_COUNT; cmd.arg = blockcount & 0x0000FFFF; diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index c0e250706353..ec2e85c7ae12 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -1817,7 +1817,7 @@ static int mmc_can_sleep(struct mmc_card *card) static int mmc_sleep(struct mmc_host *host) { - struct mmc_command cmd = {0}; + struct mmc_command cmd = {}; struct mmc_card *card = host->card; unsigned int timeout_ms = DIV_ROUND_UP(card->ext_csd.sa_timeout, 10000); int err; diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c index e6ea8503f40c..fe80f26d6971 100644 --- a/drivers/mmc/core/mmc_ops.c +++ b/drivers/mmc/core/mmc_ops.c @@ -57,7 +57,7 @@ static const u8 tuning_blk_pattern_8bit[] = { int mmc_send_status(struct mmc_card *card, u32 *status) { int err; - struct mmc_command cmd = {0}; + struct mmc_command cmd = {}; cmd.opcode = MMC_SEND_STATUS; if (!mmc_host_is_spi(card->host)) @@ -79,7 +79,7 @@ int mmc_send_status(struct mmc_card *card, u32 *status) static int _mmc_select_card(struct mmc_host *host, struct mmc_card *card) { - struct mmc_command cmd = {0}; + struct mmc_command cmd = {}; cmd.opcode = MMC_SELECT_CARD; @@ -115,7 +115,7 @@ int mmc_deselect_cards(struct mmc_host *host) */ int mmc_set_dsr(struct mmc_host *host) { - struct mmc_command cmd = {0}; + struct mmc_command cmd = {}; cmd.opcode = MMC_SET_DSR; @@ -128,7 +128,7 @@ int mmc_set_dsr(struct mmc_host *host) int mmc_go_idle(struct mmc_host *host) { int err; - struct mmc_command cmd = {0}; + struct mmc_command cmd = {}; /* * Non-SPI hosts need to prevent chipselect going active during @@ -164,7 +164,7 @@ int mmc_go_idle(struct mmc_host *host) int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) { - struct mmc_command cmd = {0}; + struct mmc_command cmd = {}; int i, err = 0; cmd.opcode = MMC_SEND_OP_COND; @@ -203,7 +203,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 err; - struct mmc_command cmd = {0}; + struct mmc_command cmd = {}; cmd.opcode = MMC_ALL_SEND_CID; cmd.arg = 0; @@ -220,7 +220,7 @@ int mmc_all_send_cid(struct mmc_host *host, u32 *cid) int mmc_set_relative_addr(struct mmc_card *card) { - struct mmc_command cmd = {0}; + struct mmc_command cmd = {}; cmd.opcode = MMC_SET_RELATIVE_ADDR; cmd.arg = card->rca << 16; @@ -233,7 +233,7 @@ static int mmc_send_cxd_native(struct mmc_host *host, u32 arg, u32 *cxd, int opcode) { int err; - struct mmc_command cmd = {0}; + struct mmc_command cmd = {}; cmd.opcode = opcode; cmd.arg = arg; @@ -256,9 +256,9 @@ static int mmc_send_cxd_data(struct mmc_card *card, struct mmc_host *host, u32 opcode, void *buf, unsigned len) { - struct mmc_request mrq = {NULL}; - struct mmc_command cmd = {0}; - struct mmc_data data = {0}; + struct mmc_request mrq = {}; + struct mmc_command cmd = {}; + struct mmc_data data = {}; struct scatterlist sg; mrq.cmd = &cmd; @@ -387,7 +387,7 @@ EXPORT_SYMBOL_GPL(mmc_get_ext_csd); int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp) { - struct mmc_command cmd = {0}; + struct mmc_command cmd = {}; int err; cmd.opcode = MMC_SPI_READ_OCR; @@ -402,7 +402,7 @@ int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp) int mmc_spi_set_crc(struct mmc_host *host, int use_crc) { - struct mmc_command cmd = {0}; + struct mmc_command cmd = {}; int err; cmd.opcode = MMC_SPI_CRC_ON_OFF; @@ -530,7 +530,7 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value, { struct mmc_host *host = card->host; int err; - struct mmc_command cmd = {0}; + struct mmc_command cmd = {}; bool use_r1b_resp = use_busy_signal; unsigned char old_timing = host->ios.timing; @@ -610,9 +610,9 @@ EXPORT_SYMBOL_GPL(mmc_switch); int mmc_send_tuning(struct mmc_host *host, u32 opcode, int *cmd_error) { - struct mmc_request mrq = {NULL}; - struct mmc_command cmd = {0}; - struct mmc_data data = {0}; + struct mmc_request mrq = {}; + struct mmc_command cmd = {}; + struct mmc_data data = {}; struct scatterlist sg; struct mmc_ios *ios = &host->ios; const u8 *tuning_block_pattern; @@ -679,7 +679,7 @@ EXPORT_SYMBOL_GPL(mmc_send_tuning); int mmc_abort_tuning(struct mmc_host *host, u32 opcode) { - struct mmc_command cmd = {0}; + struct mmc_command cmd = {}; /* * eMMC specification specifies that CMD12 can be used to stop a tuning @@ -706,9 +706,9 @@ static int mmc_send_bus_test(struct mmc_card *card, struct mmc_host *host, u8 opcode, u8 len) { - struct mmc_request mrq = {NULL}; - struct mmc_command cmd = {0}; - struct mmc_data data = {0}; + struct mmc_request mrq = {}; + struct mmc_command cmd = {}; + struct mmc_data data = {}; struct scatterlist sg; u8 *data_buf; u8 *test_buf; @@ -802,7 +802,7 @@ int mmc_bus_test(struct mmc_card *card, u8 bus_width) int mmc_send_hpi_cmd(struct mmc_card *card, u32 *status) { - struct mmc_command cmd = {0}; + struct mmc_command cmd = {}; unsigned int opcode; int err; diff --git a/drivers/mmc/core/mmc_test.c b/drivers/mmc/core/mmc_test.c index 3ab6e52d106c..bd8eb9bfc153 100644 --- a/drivers/mmc/core/mmc_test.c +++ b/drivers/mmc/core/mmc_test.c @@ -260,7 +260,7 @@ static int mmc_test_busy(struct mmc_command *cmd) static int mmc_test_wait_busy(struct mmc_test_card *test) { int ret, busy; - struct mmc_command cmd = {0}; + struct mmc_command cmd = {}; busy = 0; do { @@ -292,10 +292,10 @@ static int mmc_test_wait_busy(struct mmc_test_card *test) static int mmc_test_buffer_transfer(struct mmc_test_card *test, u8 *buffer, unsigned addr, unsigned blksz, int write) { - struct mmc_request mrq = {0}; - struct mmc_command cmd = {0}; - struct mmc_command stop = {0}; - struct mmc_data data = {0}; + struct mmc_request mrq = {}; + struct mmc_command cmd = {}; + struct mmc_command stop = {}; + struct mmc_data data = {}; struct scatterlist sg; @@ -885,10 +885,10 @@ static int mmc_test_simple_transfer(struct mmc_test_card *test, struct scatterlist *sg, unsigned sg_len, unsigned dev_addr, unsigned blocks, unsigned blksz, int write) { - struct mmc_request mrq = {0}; - struct mmc_command cmd = {0}; - struct mmc_command stop = {0}; - struct mmc_data data = {0}; + struct mmc_request mrq = {}; + struct mmc_command cmd = {}; + struct mmc_command stop = {}; + struct mmc_data data = {}; mrq.cmd = &cmd; mrq.data = &data; @@ -910,10 +910,10 @@ static int mmc_test_simple_transfer(struct mmc_test_card *test, static int mmc_test_broken_transfer(struct mmc_test_card *test, unsigned blocks, unsigned blksz, int write) { - struct mmc_request mrq = {0}; - struct mmc_command cmd = {0}; - struct mmc_command stop = {0}; - struct mmc_data data = {0}; + struct mmc_request mrq = {}; + struct mmc_command cmd = {}; + struct mmc_command stop = {}; + struct mmc_data data = {}; struct scatterlist sg; diff --git a/drivers/mmc/core/sd_ops.c b/drivers/mmc/core/sd_ops.c index de125a41aa7a..9d5824a37586 100644 --- a/drivers/mmc/core/sd_ops.c +++ b/drivers/mmc/core/sd_ops.c @@ -25,7 +25,7 @@ int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card) { int err; - struct mmc_command cmd = {0}; + struct mmc_command cmd = {}; if (WARN_ON(card && card->host != host)) return -EINVAL; @@ -68,7 +68,7 @@ EXPORT_SYMBOL_GPL(mmc_app_cmd); int mmc_wait_for_app_cmd(struct mmc_host *host, struct mmc_card *card, struct mmc_command *cmd, int retries) { - struct mmc_request mrq = {NULL}; + struct mmc_request mrq = {}; int i, err; @@ -120,7 +120,7 @@ EXPORT_SYMBOL(mmc_wait_for_app_cmd); int mmc_app_set_bus_width(struct mmc_card *card, int width) { - struct mmc_command cmd = {0}; + struct mmc_command cmd = {}; cmd.opcode = SD_APP_SET_BUS_WIDTH; cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; @@ -141,7 +141,7 @@ int mmc_app_set_bus_width(struct mmc_card *card, int width) int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) { - struct mmc_command cmd = {0}; + struct mmc_command cmd = {}; int i, err = 0; cmd.opcode = SD_APP_OP_COND; @@ -185,7 +185,7 @@ int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) int mmc_send_if_cond(struct mmc_host *host, u32 ocr) { - struct mmc_command cmd = {0}; + struct mmc_command cmd = {}; int err; static const u8 test_pattern = 0xAA; u8 result_pattern; @@ -217,7 +217,7 @@ int mmc_send_if_cond(struct mmc_host *host, u32 ocr) int mmc_send_relative_addr(struct mmc_host *host, unsigned int *rca) { int err; - struct mmc_command cmd = {0}; + struct mmc_command cmd = {}; cmd.opcode = SD_SEND_RELATIVE_ADDR; cmd.arg = 0; @@ -235,9 +235,9 @@ int mmc_send_relative_addr(struct mmc_host *host, unsigned int *rca) int mmc_app_send_scr(struct mmc_card *card, u32 *scr) { int err; - struct mmc_request mrq = {NULL}; - struct mmc_command cmd = {0}; - struct mmc_data data = {0}; + struct mmc_request mrq = {}; + struct mmc_command cmd = {}; + struct mmc_data data = {}; struct scatterlist sg; void *data_buf; @@ -290,9 +290,9 @@ int mmc_app_send_scr(struct mmc_card *card, u32 *scr) int mmc_sd_switch(struct mmc_card *card, int mode, int group, u8 value, u8 *resp) { - struct mmc_request mrq = {NULL}; - struct mmc_command cmd = {0}; - struct mmc_data data = {0}; + struct mmc_request mrq = {}; + struct mmc_command cmd = {}; + struct mmc_data data = {}; struct scatterlist sg; /* NOTE: caller guarantees resp is heap-allocated */ @@ -332,9 +332,9 @@ int mmc_sd_switch(struct mmc_card *card, int mode, int group, int mmc_app_sd_status(struct mmc_card *card, void *ssr) { int err; - struct mmc_request mrq = {NULL}; - struct mmc_command cmd = {0}; - struct mmc_data data = {0}; + struct mmc_request mrq = {}; + struct mmc_command cmd = {}; + struct mmc_data data = {}; struct scatterlist sg; /* NOTE: caller guarantees ssr is heap-allocated */ diff --git a/drivers/mmc/core/sdio_ops.c b/drivers/mmc/core/sdio_ops.c index 90fe5545c677..3c0d3ab4324c 100644 --- a/drivers/mmc/core/sdio_ops.c +++ b/drivers/mmc/core/sdio_ops.c @@ -21,7 +21,7 @@ int mmc_send_io_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) { - struct mmc_command cmd = {0}; + struct mmc_command cmd = {}; int i, err = 0; cmd.opcode = SD_IO_SEND_OP_COND; @@ -66,7 +66,7 @@ int mmc_send_io_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) static int mmc_io_rw_direct_host(struct mmc_host *host, int write, unsigned fn, unsigned addr, u8 in, u8 *out) { - struct mmc_command cmd = {0}; + struct mmc_command cmd = {}; int err; if (fn > 7) @@ -118,9 +118,9 @@ int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn, int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn, unsigned addr, int incr_addr, u8 *buf, unsigned blocks, unsigned blksz) { - struct mmc_request mrq = {NULL}; - struct mmc_command cmd = {0}; - struct mmc_data data = {0}; + struct mmc_request mrq = {}; + struct mmc_command cmd = {}; + struct mmc_data data = {}; struct scatterlist sg, *sg_ptr; struct sg_table sgtable; unsigned int nents, left_size, i; diff --git a/drivers/mmc/host/rtsx_pci_sdmmc.c b/drivers/mmc/host/rtsx_pci_sdmmc.c index ecb99a8d2fa2..41b57713b620 100644 --- a/drivers/mmc/host/rtsx_pci_sdmmc.c +++ b/drivers/mmc/host/rtsx_pci_sdmmc.c @@ -707,7 +707,7 @@ static int sd_tuning_rx_cmd(struct realtek_pci_sdmmc *host, u8 opcode, u8 sample_point) { int err; - struct mmc_command cmd = {0}; + struct mmc_command cmd = {}; err = sd_change_phase(host, sample_point, true); if (err < 0) diff --git a/drivers/mmc/host/rtsx_usb_sdmmc.c b/drivers/mmc/host/rtsx_usb_sdmmc.c index dc1abd14acbc..12d2fbe9c520 100644 --- a/drivers/mmc/host/rtsx_usb_sdmmc.c +++ b/drivers/mmc/host/rtsx_usb_sdmmc.c @@ -682,7 +682,7 @@ static int sd_tuning_rx_cmd(struct rtsx_usb_sdmmc *host, u8 opcode, u8 sample_point) { int err; - struct mmc_command cmd = {0}; + struct mmc_command cmd = {}; err = sd_change_phase(host, sample_point, 0); if (err) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 0def99590d16..a2efa25c7f3b 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -2021,8 +2021,8 @@ static void sdhci_send_tuning(struct sdhci_host *host, u32 opcode, unsigned long flags) { struct mmc_host *mmc = host->mmc; - struct mmc_command cmd = {0}; - struct mmc_request mrq = {NULL}; + struct mmc_command cmd = {}; + struct mmc_request mrq = {}; cmd.opcode = opcode; cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; From c82c27754349168ff52cbf2f878210f8ef384f8b Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Fri, 30 Dec 2016 15:24:32 +0000 Subject: [PATCH 013/145] mmc: sdhci-iproc: Apply caps from bcm2835-mmc driver Since the mmc module on bcm2835 neither provide a capabilities register nor free documentation we must rely on the downstream implementation [1]. So enable the following capabilities for bcm2835: MMC_CAP_MMC_HIGHSPEED MMC_CAP_SD_HIGHSPEED MMC_CAP_DRIVER_TYPE_A MMC_CAP_DRIVER_TYPE_C [1] - https://github.com/raspberrypi/linux/blob/rpi-4.4.y/drivers/mmc/host/bcm2835-mmc.c Signed-off-by: Stefan Wahren Reviewed-by: Eric Anholt Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-iproc.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/mmc/host/sdhci-iproc.c b/drivers/mmc/host/sdhci-iproc.c index d7046d67415a..30b3fdf52c58 100644 --- a/drivers/mmc/host/sdhci-iproc.c +++ b/drivers/mmc/host/sdhci-iproc.c @@ -211,14 +211,17 @@ static const struct sdhci_iproc_data iproc_data = { static const struct sdhci_pltfm_data sdhci_bcm2835_pltfm_data = { .quirks = SDHCI_QUIRK_BROKEN_CARD_DETECTION | SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | - SDHCI_QUIRK_MISSING_CAPS, + SDHCI_QUIRK_MISSING_CAPS | + SDHCI_QUIRK_NO_HISPD_BIT, .ops = &sdhci_iproc_32only_ops, }; static const struct sdhci_iproc_data bcm2835_data = { .pdata = &sdhci_bcm2835_pltfm_data, - .caps = SDHCI_CAN_VDD_330, - .caps1 = 0x00000000, + .caps = SDHCI_CAN_VDD_330 | + SDHCI_CAN_DO_HISPD, + .caps1 = SDHCI_DRIVER_TYPE_A | + SDHCI_DRIVER_TYPE_C, .mmc_caps = 0x00000000, }; From 40165de23df9ed4a630dcd991d63b8cb453e4ba8 Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Fri, 30 Dec 2016 15:24:33 +0000 Subject: [PATCH 014/145] mmc: sdhci-iproc: Increase max_blk_size for bcm2835 According to the BCM2835 datasheet the maximum block size for the eMMC module is restricted to the internal data FIFO which is 1024 byte. But this is still an improvement to the default of 512 byte. Signed-off-by: Stefan Wahren Reviewed-by: Eric Anholt Acked-by: Scott Branden Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-iproc.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/host/sdhci-iproc.c b/drivers/mmc/host/sdhci-iproc.c index 30b3fdf52c58..3275d4995812 100644 --- a/drivers/mmc/host/sdhci-iproc.c +++ b/drivers/mmc/host/sdhci-iproc.c @@ -218,7 +218,9 @@ static const struct sdhci_pltfm_data sdhci_bcm2835_pltfm_data = { static const struct sdhci_iproc_data bcm2835_data = { .pdata = &sdhci_bcm2835_pltfm_data, - .caps = SDHCI_CAN_VDD_330 | + .caps = ((0x1 << SDHCI_MAX_BLOCK_SHIFT) + & SDHCI_MAX_BLOCK_MASK) | + SDHCI_CAN_VDD_330 | SDHCI_CAN_DO_HISPD, .caps1 = SDHCI_DRIVER_TYPE_A | SDHCI_DRIVER_TYPE_C, From 608241f36ad6d11f18cff8f415048bb5dfe6403b Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Fri, 30 Dec 2016 13:47:14 +0100 Subject: [PATCH 015/145] sh: sh7724: Don't use a public mmc header for MMC_PROGRESS* The enum that specifies the MMC_PROGRESS* types, is a sh mmcif specific thing and has no relevance in a public mmc header. Currently it's used only by the sh romImage MMCIF boot, so let's instead define the enum in there and rename the types to MMCIF_* to show this. Cc: linux-sh@vger.kernel.org Cc: Simon Horman Cc: Yoshinori Sato Cc: Rich Felker Signed-off-by: Ulf Hansson Reviewed-by: Simon Horman Reviewed-by: Linus Walleij --- arch/sh/boot/romimage/mmcif-sh7724.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/arch/sh/boot/romimage/mmcif-sh7724.c b/arch/sh/boot/romimage/mmcif-sh7724.c index 16b122510c84..6595b6b45bf1 100644 --- a/arch/sh/boot/romimage/mmcif-sh7724.c +++ b/arch/sh/boot/romimage/mmcif-sh7724.c @@ -9,7 +9,6 @@ */ #include -#include #include #define MMCIF_BASE (void __iomem *)0xa4ca0000 @@ -22,6 +21,13 @@ #define HIZCRC 0xa405015c #define DRVCRA 0xa405018a +enum { + MMCIF_PROGRESS_ENTER, + MMCIF_PROGRESS_INIT, + MMCIF_PROGRESS_LOAD, + MMCIF_PROGRESS_DONE +}; + /* SH7724 specific MMCIF loader * * loads the romImage from an MMC card starting from block 512 @@ -30,7 +36,7 @@ */ asmlinkage void mmcif_loader(unsigned char *buf, unsigned long no_bytes) { - mmcif_update_progress(MMC_PROGRESS_ENTER); + mmcif_update_progress(MMCIF_PROGRESS_ENTER); /* enable clock to the MMCIF hardware block */ __raw_writel(__raw_readl(MSTPCR2) & ~0x20000000, MSTPCR2); @@ -53,12 +59,12 @@ asmlinkage void mmcif_loader(unsigned char *buf, unsigned long no_bytes) /* high drive capability for MMC pins */ __raw_writew(__raw_readw(DRVCRA) | 0x3000, DRVCRA); - mmcif_update_progress(MMC_PROGRESS_INIT); + mmcif_update_progress(MMCIF_PROGRESS_INIT); /* setup MMCIF hardware */ sh_mmcif_boot_init(MMCIF_BASE); - mmcif_update_progress(MMC_PROGRESS_LOAD); + mmcif_update_progress(MMCIF_PROGRESS_LOAD); /* load kernel via MMCIF interface */ sh_mmcif_boot_do_read(MMCIF_BASE, 512, @@ -68,5 +74,5 @@ asmlinkage void mmcif_loader(unsigned char *buf, unsigned long no_bytes) /* disable clock to the MMCIF hardware block */ __raw_writel(__raw_readl(MSTPCR2) | 0x20000000, MSTPCR2); - mmcif_update_progress(MMC_PROGRESS_DONE); + mmcif_update_progress(MMCIF_PROGRESS_DONE); } From 13f00f9f2460cfa106de6c30512b648d85831468 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Fri, 30 Dec 2016 13:47:15 +0100 Subject: [PATCH 016/145] mmc: Removed the unused public mmc boot.h header Signed-off-by: Ulf Hansson Reviewed-by: Linus Walleij --- include/linux/mmc/boot.h | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 include/linux/mmc/boot.h diff --git a/include/linux/mmc/boot.h b/include/linux/mmc/boot.h deleted file mode 100644 index 23acc3baa07d..000000000000 --- a/include/linux/mmc/boot.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef LINUX_MMC_BOOT_H -#define LINUX_MMC_BOOT_H - -enum { MMC_PROGRESS_ENTER, MMC_PROGRESS_INIT, - MMC_PROGRESS_LOAD, MMC_PROGRESS_DONE }; - -#endif /* LINUX_MMC_BOOT_H */ From 95cc4df716a210a19f0611215c49484d460250fd Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Fri, 30 Dec 2016 13:47:16 +0100 Subject: [PATCH 017/145] mmc: sh_mmcif: Remove unused use_cd_gpio/cd_gpio from platform data Cc: Kuninori Morimoto Signed-off-by: Ulf Hansson Reviewed-by: Linus Walleij --- drivers/mmc/host/sh_mmcif.c | 6 ------ include/linux/mmc/sh_mmcif.h | 2 -- 2 files changed, 8 deletions(-) diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c index 900778421be6..5f970550d44e 100644 --- a/drivers/mmc/host/sh_mmcif.c +++ b/drivers/mmc/host/sh_mmcif.c @@ -1509,12 +1509,6 @@ static int sh_mmcif_probe(struct platform_device *pdev) } } - if (pd && pd->use_cd_gpio) { - ret = mmc_gpio_request_cd(mmc, pd->cd_gpio, 0); - if (ret < 0) - goto err_clk; - } - mutex_init(&host->thread_lock); ret = mmc_add_host(mmc); diff --git a/include/linux/mmc/sh_mmcif.h b/include/linux/mmc/sh_mmcif.h index ccd8fb2cad52..5ce5a2c1a1f5 100644 --- a/include/linux/mmc/sh_mmcif.h +++ b/include/linux/mmc/sh_mmcif.h @@ -35,10 +35,8 @@ struct sh_mmcif_plat_data { int (*get_cd)(struct platform_device *pdef); unsigned int slave_id_tx; /* embedded slave_id_[tr]x */ unsigned int slave_id_rx; - bool use_cd_gpio : 1; bool ccs_unsupported : 1; bool clk_ctrl2_present : 1; - unsigned int cd_gpio; u8 sup_pclk; /* 1 :SH7757, 0: SH7724/SH7372 */ unsigned long caps; u32 ocr; From 5957eeba530747e9d77daf2f300a186758be51d9 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Fri, 30 Dec 2016 13:47:17 +0100 Subject: [PATCH 018/145] mmc: sh_mmcif: Remove unused ->get_cd() platform callback Removing the callback also enables us to remove the sh_mmcif_get_cd() altogether, as we convert to use mmc_gpio_get_cd() to the same kind of work. Cc: Kuninori Morimoto Signed-off-by: Ulf Hansson --- drivers/mmc/host/sh_mmcif.c | 18 +----------------- include/linux/mmc/sh_mmcif.h | 1 - 2 files changed, 1 insertion(+), 18 deletions(-) diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c index 5f970550d44e..7ba92a425ee0 100644 --- a/drivers/mmc/host/sh_mmcif.c +++ b/drivers/mmc/host/sh_mmcif.c @@ -1079,26 +1079,10 @@ static void sh_mmcif_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) host->state = STATE_IDLE; } -static int sh_mmcif_get_cd(struct mmc_host *mmc) -{ - struct sh_mmcif_host *host = mmc_priv(mmc); - struct device *dev = sh_mmcif_host_to_dev(host); - struct sh_mmcif_plat_data *p = dev->platform_data; - int ret = mmc_gpio_get_cd(mmc); - - if (ret >= 0) - return ret; - - if (!p || !p->get_cd) - return -ENOSYS; - else - return p->get_cd(host->pd); -} - static struct mmc_host_ops sh_mmcif_ops = { .request = sh_mmcif_request, .set_ios = sh_mmcif_set_ios, - .get_cd = sh_mmcif_get_cd, + .get_cd = mmc_gpio_get_cd, }; static bool sh_mmcif_end_cmd(struct sh_mmcif_host *host) diff --git a/include/linux/mmc/sh_mmcif.h b/include/linux/mmc/sh_mmcif.h index 5ce5a2c1a1f5..7cafc95a2b4e 100644 --- a/include/linux/mmc/sh_mmcif.h +++ b/include/linux/mmc/sh_mmcif.h @@ -32,7 +32,6 @@ */ struct sh_mmcif_plat_data { - int (*get_cd)(struct platform_device *pdef); unsigned int slave_id_tx; /* embedded slave_id_[tr]x */ unsigned int slave_id_rx; bool ccs_unsupported : 1; From 8020f71117042ed82287e4f51c48b57ce4c783df Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Fri, 30 Dec 2016 13:47:18 +0100 Subject: [PATCH 019/145] mmc: sh_mmcif: Remove unused ccs_unsupported from the platform data There are currently no users of the ccs_unsupported member from the platform data, so let's remove it. Note, as some of the sh_mmcif variants may not support ccs, let's keep the current code in the driver, which deals with this. For future support, we should invent a DT binding instead, but let's leave that until it's needed. Cc: Kuninori Morimoto Signed-off-by: Ulf Hansson Reviewed-by: Linus Walleij --- drivers/mmc/host/sh_mmcif.c | 2 +- include/linux/mmc/sh_mmcif.h | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c index 7ba92a425ee0..9fa8ce3fbb1b 100644 --- a/drivers/mmc/host/sh_mmcif.c +++ b/drivers/mmc/host/sh_mmcif.c @@ -1427,7 +1427,7 @@ static int sh_mmcif_probe(struct platform_device *pdev) host->mmc = mmc; host->addr = reg; host->timeout = msecs_to_jiffies(10000); - host->ccs_enable = !pd || !pd->ccs_unsupported; + host->ccs_enable = true; host->clk_ctrl2_enable = pd && pd->clk_ctrl2_present; host->pd = pdev; diff --git a/include/linux/mmc/sh_mmcif.h b/include/linux/mmc/sh_mmcif.h index 7cafc95a2b4e..384b86b90473 100644 --- a/include/linux/mmc/sh_mmcif.h +++ b/include/linux/mmc/sh_mmcif.h @@ -34,7 +34,6 @@ struct sh_mmcif_plat_data { unsigned int slave_id_tx; /* embedded slave_id_[tr]x */ unsigned int slave_id_rx; - bool ccs_unsupported : 1; bool clk_ctrl2_present : 1; u8 sup_pclk; /* 1 :SH7757, 0: SH7724/SH7372 */ unsigned long caps; From dba4bb484e9e495478f2bcf474393d33f7e0ec27 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Fri, 30 Dec 2016 13:47:19 +0100 Subject: [PATCH 020/145] mmc: sh_mmcif: Remove unused clk_ctrl2_present from the platform data There are currently no users of the clk_ctrl2_present member from the platform data, so let's remove it. Note, as some of the sh_mmcif variants may support clk_ctrl2, let's keep the current code in the driver, which deals with this. For future support, we should invent a DT binding instead, but let's leave that until it's needed. Cc: Kuninori Morimoto Signed-off-by: Ulf Hansson Reviewed-by: Linus Walleij --- drivers/mmc/host/sh_mmcif.c | 2 +- include/linux/mmc/sh_mmcif.h | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c index 9fa8ce3fbb1b..4062d6bef3c8 100644 --- a/drivers/mmc/host/sh_mmcif.c +++ b/drivers/mmc/host/sh_mmcif.c @@ -1428,7 +1428,7 @@ static int sh_mmcif_probe(struct platform_device *pdev) host->addr = reg; host->timeout = msecs_to_jiffies(10000); host->ccs_enable = true; - host->clk_ctrl2_enable = pd && pd->clk_ctrl2_present; + host->clk_ctrl2_enable = false; host->pd = pdev; diff --git a/include/linux/mmc/sh_mmcif.h b/include/linux/mmc/sh_mmcif.h index 384b86b90473..a7baa29484c3 100644 --- a/include/linux/mmc/sh_mmcif.h +++ b/include/linux/mmc/sh_mmcif.h @@ -34,7 +34,6 @@ struct sh_mmcif_plat_data { unsigned int slave_id_tx; /* embedded slave_id_[tr]x */ unsigned int slave_id_rx; - bool clk_ctrl2_present : 1; u8 sup_pclk; /* 1 :SH7757, 0: SH7724/SH7372 */ unsigned long caps; u32 ocr; From 0f21c58c63add705065a75495e7a1860a62470ed Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Fri, 30 Dec 2016 13:47:20 +0100 Subject: [PATCH 021/145] mmc: dw_mmc: Remove the public dw_mmc header file There are currently no external users of the public dw_mmc header file, except the dw_mmc driver itself. Therefore let's move the definitions from the public dw_mmc header file into the existing private dw_mmc header file and then remove the public one. Signed-off-by: Ulf Hansson Reviewed-by: Linus Walleij --- MAINTAINERS | 1 - drivers/mmc/host/dw_mmc-exynos.c | 1 - drivers/mmc/host/dw_mmc-k3.c | 1 - drivers/mmc/host/dw_mmc-pci.c | 1 - drivers/mmc/host/dw_mmc-pltfm.c | 1 - drivers/mmc/host/dw_mmc-rockchip.c | 1 - drivers/mmc/host/dw_mmc.c | 1 - drivers/mmc/host/dw_mmc.h | 257 +++++++++++++++++++++++++++ include/linux/mmc/dw_mmc.h | 274 ----------------------------- 9 files changed, 257 insertions(+), 281 deletions(-) delete mode 100644 include/linux/mmc/dw_mmc.h diff --git a/MAINTAINERS b/MAINTAINERS index 107c10e8f2d2..3cee6d55f91f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -10887,7 +10887,6 @@ SYNOPSYS DESIGNWARE MMC/SD/SDIO DRIVER M: Jaehoon Chung L: linux-mmc@vger.kernel.org S: Maintained -F: include/linux/mmc/dw_mmc.h F: drivers/mmc/host/dw_mmc* SYSTEM TRACE MODULE CLASS diff --git a/drivers/mmc/host/dw_mmc-exynos.c b/drivers/mmc/host/dw_mmc-exynos.c index e1335289316c..25691cca1881 100644 --- a/drivers/mmc/host/dw_mmc-exynos.c +++ b/drivers/mmc/host/dw_mmc-exynos.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/mmc/host/dw_mmc-k3.c b/drivers/mmc/host/dw_mmc-k3.c index 9821e6bd5d5e..e38fb0020bb1 100644 --- a/drivers/mmc/host/dw_mmc-k3.c +++ b/drivers/mmc/host/dw_mmc-k3.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/mmc/host/dw_mmc-pci.c b/drivers/mmc/host/dw_mmc-pci.c index ab82796b01e2..ab8713297edb 100644 --- a/drivers/mmc/host/dw_mmc-pci.c +++ b/drivers/mmc/host/dw_mmc-pci.c @@ -18,7 +18,6 @@ #include #include #include -#include #include "dw_mmc.h" #define PCI_BAR_NO 2 diff --git a/drivers/mmc/host/dw_mmc-pltfm.c b/drivers/mmc/host/dw_mmc-pltfm.c index 1236d49ba36e..58c13e21bd5a 100644 --- a/drivers/mmc/host/dw_mmc-pltfm.c +++ b/drivers/mmc/host/dw_mmc-pltfm.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include diff --git a/drivers/mmc/host/dw_mmc-rockchip.c b/drivers/mmc/host/dw_mmc-rockchip.c index 9a46e4694227..372fb6e948c1 100644 --- a/drivers/mmc/host/dw_mmc-rockchip.c +++ b/drivers/mmc/host/dw_mmc-rockchip.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 73db08558e4d..2d8932a20161 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -32,7 +32,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h index c59465829387..960146106596 100644 --- a/drivers/mmc/host/dw_mmc.h +++ b/drivers/mmc/host/dw_mmc.h @@ -14,6 +14,263 @@ #ifndef _DW_MMC_H_ #define _DW_MMC_H_ +#include +#include +#include +#include + +#define MAX_MCI_SLOTS 2 + +enum dw_mci_state { + STATE_IDLE = 0, + STATE_SENDING_CMD, + STATE_SENDING_DATA, + STATE_DATA_BUSY, + STATE_SENDING_STOP, + STATE_DATA_ERROR, + STATE_SENDING_CMD11, + STATE_WAITING_CMD11_DONE, +}; + +enum { + EVENT_CMD_COMPLETE = 0, + EVENT_XFER_COMPLETE, + EVENT_DATA_COMPLETE, + 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 { + TRANS_MODE_PIO = 0, + TRANS_MODE_IDMAC, + TRANS_MODE_EDMAC +}; + +struct dw_mci_dma_slave { + struct dma_chan *ch; + enum dma_transfer_direction direction; +}; + +/** + * struct dw_mci - MMC controller state shared between all slots + * @lock: Spinlock protecting the queue and associated data. + * @irq_lock: Spinlock protecting the INTMASK setting. + * @regs: Pointer to MMIO registers. + * @fifo_reg: Pointer to MMIO registers for data FIFO + * @sg: Scatterlist entry currently being processed by PIO code, if any. + * @sg_miter: PIO mapping scatterlist iterator. + * @cur_slot: The slot which is currently using the controller. + * @mrq: The request currently being processed on @cur_slot, + * or NULL if the controller is idle. + * @cmd: The command currently being sent to the card, or NULL. + * @data: The data currently being transferred, or NULL if no data + * transfer is in progress. + * @stop_abort: The command currently prepared for stoping transfer. + * @prev_blksz: The former transfer blksz record. + * @timing: Record of current ios timing. + * @use_dma: Whether DMA channel is initialized or not. + * @using_dma: Whether DMA is in use for the current transfer. + * @dma_64bit_address: Whether DMA supports 64-bit address mode or not. + * @sg_dma: Bus address of DMA buffer. + * @sg_cpu: Virtual address of DMA buffer. + * @dma_ops: Pointer to platform-specific DMA callbacks. + * @cmd_status: Snapshot of SR taken upon completion of the current + * @ring_size: Buffer size for idma descriptors. + * command. Only valid when EVENT_CMD_COMPLETE is pending. + * @dms: structure of slave-dma private data. + * @phy_regs: physical address of controller's register map + * @data_status: Snapshot of SR taken upon completion of the current + * data transfer. Only valid when EVENT_DATA_COMPLETE or + * EVENT_DATA_ERROR is pending. + * @stop_cmdr: Value to be loaded into CMDR when the stop command is + * to be sent. + * @dir_status: Direction of current transfer. + * @tasklet: Tasklet running the request state machine. + * @pending_events: Bitmask of events flagged by the interrupt handler + * to be processed by the tasklet. + * @completed_events: Bitmask of events which the state machine has + * processed. + * @state: Tasklet state. + * @queue: List of slots waiting for access to the controller. + * @bus_hz: The rate of @mck in Hz. This forms the basis for MMC bus + * rate and timeout calculations. + * @current_speed: Configured rate of the controller. + * @num_slots: Number of slots available. + * @fifoth_val: The value of FIFOTH register. + * @verid: Denote Version ID. + * @dev: Device associated with the MMC controller. + * @pdata: Platform data associated with the MMC controller. + * @drv_data: Driver specific data for identified variant of the controller + * @priv: Implementation defined private data. + * @biu_clk: Pointer to bus interface unit clock instance. + * @ciu_clk: Pointer to card interface unit clock instance. + * @slot: Slots sharing this MMC controller. + * @fifo_depth: depth of FIFO. + * @data_shift: log2 of FIFO item size. + * @part_buf_start: Start index in part_buf. + * @part_buf_count: Bytes of partial data in part_buf. + * @part_buf: Simple buffer for partial fifo reads/writes. + * @push_data: Pointer to FIFO push function. + * @pull_data: Pointer to FIFO pull function. + * @vqmmc_enabled: Status of vqmmc, should be true or false. + * @irq_flags: The flags to be passed to request_irq. + * @irq: The irq value to be passed to request_irq. + * @sdio_id0: Number of slot0 in the SDIO interrupt registers. + * @cmd11_timer: Timer for SD3.0 voltage switch over scheme. + * @dto_timer: Timer for broken data transfer over scheme. + * + * Locking + * ======= + * + * @lock is a softirq-safe spinlock protecting @queue as well as + * @cur_slot, @mrq and @state. These must always be updated + * at the same time while holding @lock. + * + * @irq_lock is an irq-safe spinlock protecting the INTMASK register + * to allow the interrupt handler to modify it directly. Held for only long + * enough to read-modify-write INTMASK and no other locks are grabbed when + * holding this one. + * + * The @mrq field of struct dw_mci_slot is also protected by @lock, + * and must always be written at the same time as the slot is added to + * @queue. + * + * @pending_events and @completed_events are accessed using atomic bit + * operations, so they don't need any locking. + * + * None of the fields touched by the interrupt handler need any + * locking. However, ordering is important: Before EVENT_DATA_ERROR or + * EVENT_DATA_COMPLETE is set in @pending_events, all data-related + * interrupts must be disabled and @data_status updated with a + * snapshot of SR. Similarly, before EVENT_CMD_COMPLETE is set, the + * CMDRDY interrupt must be disabled and @cmd_status updated with a + * snapshot of SR, and before EVENT_XFER_COMPLETE can be set, the + * bytes_xfered field of @data must be written. This is ensured by + * using barriers. + */ +struct dw_mci { + spinlock_t lock; + spinlock_t irq_lock; + void __iomem *regs; + void __iomem *fifo_reg; + + struct scatterlist *sg; + struct sg_mapping_iter sg_miter; + + struct dw_mci_slot *cur_slot; + struct mmc_request *mrq; + struct mmc_command *cmd; + struct mmc_data *data; + struct mmc_command stop_abort; + unsigned int prev_blksz; + unsigned char timing; + + /* DMA interface members*/ + int use_dma; + int using_dma; + int dma_64bit_address; + + dma_addr_t sg_dma; + void *sg_cpu; + const struct dw_mci_dma_ops *dma_ops; + /* For idmac */ + unsigned int ring_size; + + /* For edmac */ + struct dw_mci_dma_slave *dms; + /* Registers's physical base address */ + resource_size_t phy_regs; + + u32 cmd_status; + u32 data_status; + u32 stop_cmdr; + u32 dir_status; + struct tasklet_struct tasklet; + unsigned long pending_events; + unsigned long completed_events; + enum dw_mci_state state; + struct list_head queue; + + u32 bus_hz; + u32 current_speed; + u32 num_slots; + u32 fifoth_val; + u16 verid; + struct device *dev; + struct dw_mci_board *pdata; + const struct dw_mci_drv_data *drv_data; + void *priv; + struct clk *biu_clk; + struct clk *ciu_clk; + struct dw_mci_slot *slot[MAX_MCI_SLOTS]; + + /* FIFO push and pull */ + int fifo_depth; + int data_shift; + u8 part_buf_start; + u8 part_buf_count; + union { + u16 part_buf16; + u32 part_buf32; + u64 part_buf; + }; + void (*push_data)(struct dw_mci *host, void *buf, int cnt); + void (*pull_data)(struct dw_mci *host, void *buf, int cnt); + + bool vqmmc_enabled; + unsigned long irq_flags; /* IRQ flags */ + int irq; + + int sdio_id0; + + struct timer_list cmd11_timer; + struct timer_list dto_timer; +}; + +/* DMA ops for Internal/External DMAC interface */ +struct dw_mci_dma_ops { + /* DMA Ops */ + int (*init)(struct dw_mci *host); + int (*start)(struct dw_mci *host, unsigned int sg_len); + void (*complete)(void *host); + void (*stop)(struct dw_mci *host); + void (*cleanup)(struct dw_mci *host); + void (*exit)(struct dw_mci *host); +}; + +struct dma_pdata; + +/* Board platform data */ +struct dw_mci_board { + u32 num_slots; + + unsigned int bus_hz; /* Clock speed at the cclk_in pad */ + + u32 caps; /* Capabilities */ + u32 caps2; /* More capabilities */ + u32 pm_caps; /* PM capabilities */ + /* + * Override fifo depth. If 0, autodetect it from the FIFOTH register, + * but note that this may not be reliable after a bootloader has used + * it. + */ + unsigned int fifo_depth; + + /* delay in mS before detecting cards after interrupt */ + u32 detect_delay_ms; + + struct reset_control *rstc; + struct dw_mci_dma_ops *dma_ops; + struct dma_pdata *data; +}; + #define DW_MMC_240A 0x240a #define DW_MMC_280A 0x280a diff --git a/include/linux/mmc/dw_mmc.h b/include/linux/mmc/dw_mmc.h deleted file mode 100644 index 15db6f83f53f..000000000000 --- a/include/linux/mmc/dw_mmc.h +++ /dev/null @@ -1,274 +0,0 @@ -/* - * Synopsys DesignWare Multimedia Card Interface driver - * (Based on NXP driver for lpc 31xx) - * - * Copyright (C) 2009 NXP Semiconductors - * Copyright (C) 2009, 2010 Imagination Technologies Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -#ifndef LINUX_MMC_DW_MMC_H -#define LINUX_MMC_DW_MMC_H - -#include -#include -#include -#include - -#define MAX_MCI_SLOTS 2 - -enum dw_mci_state { - STATE_IDLE = 0, - STATE_SENDING_CMD, - STATE_SENDING_DATA, - STATE_DATA_BUSY, - STATE_SENDING_STOP, - STATE_DATA_ERROR, - STATE_SENDING_CMD11, - STATE_WAITING_CMD11_DONE, -}; - -enum { - EVENT_CMD_COMPLETE = 0, - EVENT_XFER_COMPLETE, - EVENT_DATA_COMPLETE, - 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 { - TRANS_MODE_PIO = 0, - TRANS_MODE_IDMAC, - TRANS_MODE_EDMAC -}; - -struct dw_mci_dma_slave { - struct dma_chan *ch; - enum dma_transfer_direction direction; -}; - -/** - * struct dw_mci - MMC controller state shared between all slots - * @lock: Spinlock protecting the queue and associated data. - * @irq_lock: Spinlock protecting the INTMASK setting. - * @regs: Pointer to MMIO registers. - * @fifo_reg: Pointer to MMIO registers for data FIFO - * @sg: Scatterlist entry currently being processed by PIO code, if any. - * @sg_miter: PIO mapping scatterlist iterator. - * @cur_slot: The slot which is currently using the controller. - * @mrq: The request currently being processed on @cur_slot, - * or NULL if the controller is idle. - * @cmd: The command currently being sent to the card, or NULL. - * @data: The data currently being transferred, or NULL if no data - * transfer is in progress. - * @stop_abort: The command currently prepared for stoping transfer. - * @prev_blksz: The former transfer blksz record. - * @timing: Record of current ios timing. - * @use_dma: Whether DMA channel is initialized or not. - * @using_dma: Whether DMA is in use for the current transfer. - * @dma_64bit_address: Whether DMA supports 64-bit address mode or not. - * @sg_dma: Bus address of DMA buffer. - * @sg_cpu: Virtual address of DMA buffer. - * @dma_ops: Pointer to platform-specific DMA callbacks. - * @cmd_status: Snapshot of SR taken upon completion of the current - * @ring_size: Buffer size for idma descriptors. - * command. Only valid when EVENT_CMD_COMPLETE is pending. - * @dms: structure of slave-dma private data. - * @phy_regs: physical address of controller's register map - * @data_status: Snapshot of SR taken upon completion of the current - * data transfer. Only valid when EVENT_DATA_COMPLETE or - * EVENT_DATA_ERROR is pending. - * @stop_cmdr: Value to be loaded into CMDR when the stop command is - * to be sent. - * @dir_status: Direction of current transfer. - * @tasklet: Tasklet running the request state machine. - * @pending_events: Bitmask of events flagged by the interrupt handler - * to be processed by the tasklet. - * @completed_events: Bitmask of events which the state machine has - * processed. - * @state: Tasklet state. - * @queue: List of slots waiting for access to the controller. - * @bus_hz: The rate of @mck in Hz. This forms the basis for MMC bus - * rate and timeout calculations. - * @current_speed: Configured rate of the controller. - * @num_slots: Number of slots available. - * @fifoth_val: The value of FIFOTH register. - * @verid: Denote Version ID. - * @dev: Device associated with the MMC controller. - * @pdata: Platform data associated with the MMC controller. - * @drv_data: Driver specific data for identified variant of the controller - * @priv: Implementation defined private data. - * @biu_clk: Pointer to bus interface unit clock instance. - * @ciu_clk: Pointer to card interface unit clock instance. - * @slot: Slots sharing this MMC controller. - * @fifo_depth: depth of FIFO. - * @data_shift: log2 of FIFO item size. - * @part_buf_start: Start index in part_buf. - * @part_buf_count: Bytes of partial data in part_buf. - * @part_buf: Simple buffer for partial fifo reads/writes. - * @push_data: Pointer to FIFO push function. - * @pull_data: Pointer to FIFO pull function. - * @vqmmc_enabled: Status of vqmmc, should be true or false. - * @irq_flags: The flags to be passed to request_irq. - * @irq: The irq value to be passed to request_irq. - * @sdio_id0: Number of slot0 in the SDIO interrupt registers. - * @cmd11_timer: Timer for SD3.0 voltage switch over scheme. - * @dto_timer: Timer for broken data transfer over scheme. - * - * Locking - * ======= - * - * @lock is a softirq-safe spinlock protecting @queue as well as - * @cur_slot, @mrq and @state. These must always be updated - * at the same time while holding @lock. - * - * @irq_lock is an irq-safe spinlock protecting the INTMASK register - * to allow the interrupt handler to modify it directly. Held for only long - * enough to read-modify-write INTMASK and no other locks are grabbed when - * holding this one. - * - * The @mrq field of struct dw_mci_slot is also protected by @lock, - * and must always be written at the same time as the slot is added to - * @queue. - * - * @pending_events and @completed_events are accessed using atomic bit - * operations, so they don't need any locking. - * - * None of the fields touched by the interrupt handler need any - * locking. However, ordering is important: Before EVENT_DATA_ERROR or - * EVENT_DATA_COMPLETE is set in @pending_events, all data-related - * interrupts must be disabled and @data_status updated with a - * snapshot of SR. Similarly, before EVENT_CMD_COMPLETE is set, the - * CMDRDY interrupt must be disabled and @cmd_status updated with a - * snapshot of SR, and before EVENT_XFER_COMPLETE can be set, the - * bytes_xfered field of @data must be written. This is ensured by - * using barriers. - */ -struct dw_mci { - spinlock_t lock; - spinlock_t irq_lock; - void __iomem *regs; - void __iomem *fifo_reg; - - struct scatterlist *sg; - struct sg_mapping_iter sg_miter; - - struct dw_mci_slot *cur_slot; - struct mmc_request *mrq; - struct mmc_command *cmd; - struct mmc_data *data; - struct mmc_command stop_abort; - unsigned int prev_blksz; - unsigned char timing; - - /* DMA interface members*/ - int use_dma; - int using_dma; - int dma_64bit_address; - - dma_addr_t sg_dma; - void *sg_cpu; - const struct dw_mci_dma_ops *dma_ops; - /* For idmac */ - unsigned int ring_size; - - /* For edmac */ - struct dw_mci_dma_slave *dms; - /* Registers's physical base address */ - resource_size_t phy_regs; - - u32 cmd_status; - u32 data_status; - u32 stop_cmdr; - u32 dir_status; - struct tasklet_struct tasklet; - unsigned long pending_events; - unsigned long completed_events; - enum dw_mci_state state; - struct list_head queue; - - u32 bus_hz; - u32 current_speed; - u32 num_slots; - u32 fifoth_val; - u16 verid; - struct device *dev; - struct dw_mci_board *pdata; - const struct dw_mci_drv_data *drv_data; - void *priv; - struct clk *biu_clk; - struct clk *ciu_clk; - struct dw_mci_slot *slot[MAX_MCI_SLOTS]; - - /* FIFO push and pull */ - int fifo_depth; - int data_shift; - u8 part_buf_start; - u8 part_buf_count; - union { - u16 part_buf16; - u32 part_buf32; - u64 part_buf; - }; - void (*push_data)(struct dw_mci *host, void *buf, int cnt); - void (*pull_data)(struct dw_mci *host, void *buf, int cnt); - - bool vqmmc_enabled; - unsigned long irq_flags; /* IRQ flags */ - int irq; - - int sdio_id0; - - struct timer_list cmd11_timer; - struct timer_list dto_timer; -}; - -/* DMA ops for Internal/External DMAC interface */ -struct dw_mci_dma_ops { - /* DMA Ops */ - int (*init)(struct dw_mci *host); - int (*start)(struct dw_mci *host, unsigned int sg_len); - void (*complete)(void *host); - void (*stop)(struct dw_mci *host); - void (*cleanup)(struct dw_mci *host); - void (*exit)(struct dw_mci *host); -}; - -struct dma_pdata; - -/* Board platform data */ -struct dw_mci_board { - u32 num_slots; - - unsigned int bus_hz; /* Clock speed at the cclk_in pad */ - - u32 caps; /* Capabilities */ - u32 caps2; /* More capabilities */ - u32 pm_caps; /* PM capabilities */ - /* - * Override fifo depth. If 0, autodetect it from the FIFOTH register, - * but note that this may not be reliable after a bootloader has used - * it. - */ - unsigned int fifo_depth; - - /* delay in mS before detecting cards after interrupt */ - u32 detect_delay_ms; - - struct reset_control *rstc; - struct dw_mci_dma_ops *dma_ops; - struct dma_pdata *data; -}; - -#endif /* LINUX_MMC_DW_MMC_H */ From 963836ad8f8415823866c7658f04fd7fa9febdcb Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Fri, 30 Dec 2016 13:47:21 +0100 Subject: [PATCH 022/145] mmc: sdhci-cadence: Include mmc.h Don't rely on host.h to include the mmc.h header, but instead include it explicitly because the driver depends on it. Cc: Masahiro Yamada Signed-off-by: Ulf Hansson Reviewed-by: Linus Walleij Acked-by: Adrian Hunter --- drivers/mmc/host/sdhci-cadence.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mmc/host/sdhci-cadence.c b/drivers/mmc/host/sdhci-cadence.c index 4b0ecb981842..31e786d1b71a 100644 --- a/drivers/mmc/host/sdhci-cadence.c +++ b/drivers/mmc/host/sdhci-cadence.c @@ -17,6 +17,7 @@ #include #include #include +#include #include "sdhci-pltfm.h" From 210583f47293c3a4a96a7e0d3e10b3210d542656 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Fri, 30 Dec 2016 13:47:22 +0100 Subject: [PATCH 023/145] mmc: sdhci: Include leds.h Don't rely on host.h to include the leds.h header, but instead include it explicitly because the driver depends on it. Signed-off-by: Ulf Hansson Reviewed-by: Linus Walleij Acked-by: Adrian Hunter --- drivers/mmc/host/sdhci.h | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index 0b66f210ae82..a10a7b6a3cb4 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -17,6 +17,7 @@ #include #include #include +#include #include From b8789ec482bbbf52f62631e25b6c8648fa834efc Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Fri, 30 Dec 2016 13:47:23 +0100 Subject: [PATCH 024/145] mmc: host: Include interrupt.h in mmc host drivers that depends on it An mmc host driver shouldn't rely on interrupt.h being included by another public mmc header. Instead make that dependency explicit by including interrupt.h in those host drivers that depends on it. Signed-off-by: Ulf Hansson Reviewed-by: Linus Walleij --- drivers/mmc/host/davinci_mmc.c | 1 + drivers/mmc/host/dw_mmc.h | 1 + drivers/mmc/host/meson-gx-mmc.c | 1 + drivers/mmc/host/mtk-sd.c | 1 + drivers/mmc/host/sdhci.h | 1 + drivers/mmc/host/tmio_mmc.h | 1 + drivers/mmc/host/via-sdmmc.c | 1 + drivers/mmc/host/wmt-sdmmc.c | 1 + 8 files changed, 8 insertions(+) diff --git a/drivers/mmc/host/davinci_mmc.c b/drivers/mmc/host/davinci_mmc.c index 36b5af8eadb8..1e2600da105f 100644 --- a/drivers/mmc/host/davinci_mmc.c +++ b/drivers/mmc/host/davinci_mmc.c @@ -36,6 +36,7 @@ #include #include #include +#include #include diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h index 960146106596..231a46f142d2 100644 --- a/drivers/mmc/host/dw_mmc.h +++ b/drivers/mmc/host/dw_mmc.h @@ -18,6 +18,7 @@ #include #include #include +#include #define MAX_MCI_SLOTS 2 diff --git a/drivers/mmc/host/meson-gx-mmc.c b/drivers/mmc/host/meson-gx-mmc.c index 09739352834c..bf19d03ce2ee 100644 --- a/drivers/mmc/host/meson-gx-mmc.c +++ b/drivers/mmc/host/meson-gx-mmc.c @@ -35,6 +35,7 @@ #include #include #include +#include #define DRIVER_NAME "meson-gx-mmc" diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c index 10ef2ae1d2f6..d33828efc253 100644 --- a/drivers/mmc/host/mtk-sd.c +++ b/drivers/mmc/host/mtk-sd.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index a10a7b6a3cb4..edf3adfbc213 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -18,6 +18,7 @@ #include #include #include +#include #include diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h index 9e20bcf3aa8d..9b2284483cdd 100644 --- a/drivers/mmc/host/tmio_mmc.h +++ b/drivers/mmc/host/tmio_mmc.h @@ -24,6 +24,7 @@ #include #include #include +#include #define CTL_SD_CMD 0x00 #define CTL_ARG_REG 0x04 diff --git a/drivers/mmc/host/via-sdmmc.c b/drivers/mmc/host/via-sdmmc.c index 63fac78b3d46..6380044c0628 100644 --- a/drivers/mmc/host/via-sdmmc.c +++ b/drivers/mmc/host/via-sdmmc.c @@ -13,6 +13,7 @@ #include #include #include +#include #include diff --git a/drivers/mmc/host/wmt-sdmmc.c b/drivers/mmc/host/wmt-sdmmc.c index 5af00559e9d6..21ebba88679c 100644 --- a/drivers/mmc/host/wmt-sdmmc.c +++ b/drivers/mmc/host/wmt-sdmmc.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include From 4a80f77618f72f40b970d96f4e8492ea2dd6f2d9 Mon Sep 17 00:00:00 2001 From: Jun Nie Date: Fri, 6 Jan 2017 12:24:42 +0800 Subject: [PATCH 025/145] Documentation: synopsys-dw-mshc: add binding for fifo quirks Add fifo-addr property and fifo-watermark-quirk property to synopsys-dw-mshc bindings. It is intended to provide more dt interface to support SoCs specific configuration. Signed-off-by: Jun Nie Acked-by: Rob Herring Signed-off-by: Jaehoon Chung Signed-off-by: Ulf Hansson --- .../devicetree/bindings/mmc/synopsys-dw-mshc.txt | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Documentation/devicetree/bindings/mmc/synopsys-dw-mshc.txt b/Documentation/devicetree/bindings/mmc/synopsys-dw-mshc.txt index 7fd17c3da116..bca30b69b8a1 100644 --- a/Documentation/devicetree/bindings/mmc/synopsys-dw-mshc.txt +++ b/Documentation/devicetree/bindings/mmc/synopsys-dw-mshc.txt @@ -75,6 +75,17 @@ Optional properties: * card-detect-delay: Delay in milli-seconds before detecting card after card insert event. The default value is 0. +* data-addr: Override fifo address with value provided by DT. The default FIFO reg + offset is assumed as 0x100 (version < 0x240A) and 0x200(version >= 0x240A) by + driver. If the controller does not follow this rule, please use this property + to set fifo address in device tree. + +* fifo-watermark-aligned: Data done irq is expected if data length is less than + watermark in PIO mode. But fifo watermark is requested to be aligned with data + length in some SoC so that TX/RX irq can be generated with data done irq. Add this + watermark quirk to mark this requirement and force fifo watermark setting + accordingly. + * vmmc-supply: The phandle to the regulator to use for vmmc. If this is specified we'll defer probe until we can find this regulator. @@ -102,6 +113,8 @@ board specific portions as listed below. interrupts = <0 75 0>; #address-cells = <1>; #size-cells = <0>; + data-addr = <0x200>; + fifo-watermark-aligned; resets = <&rst 20>; reset-names = "reset"; }; From a0361c1a4d265ea36796149a29b48e41a5ba28d9 Mon Sep 17 00:00:00 2001 From: Jun Nie Date: Wed, 11 Jan 2017 15:35:35 +0900 Subject: [PATCH 026/145] mmc: dw_mmc: Add fifo address property The FIFO address may break default address assumption of 0x100 (version < 0x240A) and 0x200(version >= 0x240A) in current driver. The new property is introduced to override fifo address via DT node information. Signed-off-by: Jun Nie Reviewed-by: Shawn Lin Signed-off-by: Jaehoon Chung Signed-off-by: Ulf Hansson --- drivers/mmc/host/dw_mmc.c | 6 +++++- drivers/mmc/host/dw_mmc.h | 2 ++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 2d8932a20161..94d8fe321260 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -2976,6 +2976,8 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host) of_property_read_u32(np, "card-detect-delay", &pdata->detect_delay_ms); + of_property_read_u32(np, "data-addr", &host->data_addr_override); + if (!of_property_read_u32(np, "clock-frequency", &clock_frequency)) pdata->bus_hz = clock_frequency; @@ -3179,7 +3181,9 @@ int dw_mci_probe(struct dw_mci *host) host->verid = SDMMC_GET_VERID(mci_readl(host, VERID)); dev_info(host->dev, "Version ID is %04x\n", host->verid); - if (host->verid < DW_MMC_240A) + if (host->data_addr_override) + host->fifo_reg = host->regs + host->data_addr_override; + else if (host->verid < DW_MMC_240A) host->fifo_reg = host->regs + DATA_OFFSET; else host->fifo_reg = host->regs + DATA_240A_OFFSET; diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h index 231a46f142d2..e08e3272a5ad 100644 --- a/drivers/mmc/host/dw_mmc.h +++ b/drivers/mmc/host/dw_mmc.h @@ -114,6 +114,7 @@ struct dw_mci_dma_slave { * @ciu_clk: Pointer to card interface unit clock instance. * @slot: Slots sharing this MMC controller. * @fifo_depth: depth of FIFO. + * @data_addr_override: override fifo reg offset with this value. * @data_shift: log2 of FIFO item size. * @part_buf_start: Start index in part_buf. * @part_buf_count: Bytes of partial data in part_buf. @@ -161,6 +162,7 @@ struct dw_mci { spinlock_t irq_lock; void __iomem *regs; void __iomem *fifo_reg; + u32 data_addr_override; struct scatterlist *sg; struct sg_mapping_iter sg_miter; From d6fced8337f8466ad6df5dbbeefe5ab38c06d3ec Mon Sep 17 00:00:00 2001 From: Jun Nie Date: Wed, 11 Jan 2017 15:37:26 +0900 Subject: [PATCH 027/145] mmc: dw_mmc: Add fifo watermark alignment property Data done irq is expected if data length is less than watermark in PIO mode. But fifo watermark is requested to be aligned with data length in some SoC so that TX/RX irq can be generated with data done irq. Add the watermark alignment to mark this requirement and force fifo watermark setting accordingly. Signed-off-by: Jun Nie Reviewed-by: Shawn Lin Signed-off-by: Jaehoon Chung Signed-off-by: Ulf Hansson --- drivers/mmc/host/dw_mmc.c | 11 +++++++++-- drivers/mmc/host/dw_mmc.h | 3 +++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 94d8fe321260..c04a5769e2ea 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -1112,11 +1112,15 @@ static void dw_mci_submit_data(struct dw_mci *host, struct mmc_data *data) mci_writel(host, CTRL, temp); /* - * Use the initial fifoth_val for PIO mode. + * Use the initial fifoth_val for PIO mode. If wm_algined + * is set, we set watermark same as data size. * If next issued data may be transfered by DMA mode, * prev_blksz should be invalidated. */ - mci_writel(host, FIFOTH, host->fifoth_val); + if (host->wm_aligned) + dw_mci_adjust_fifoth(host, data); + else + mci_writel(host, FIFOTH, host->fifoth_val); host->prev_blksz = 0; } else { /* @@ -2978,6 +2982,9 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host) of_property_read_u32(np, "data-addr", &host->data_addr_override); + if (of_get_property(np, "fifo-watermark-aligned", NULL)) + host->wm_aligned = true; + if (!of_property_read_u32(np, "clock-frequency", &clock_frequency)) pdata->bus_hz = clock_frequency; diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h index e08e3272a5ad..ce347361f3dc 100644 --- a/drivers/mmc/host/dw_mmc.h +++ b/drivers/mmc/host/dw_mmc.h @@ -115,6 +115,8 @@ struct dw_mci_dma_slave { * @slot: Slots sharing this MMC controller. * @fifo_depth: depth of FIFO. * @data_addr_override: override fifo reg offset with this value. + * @wm_aligned: force fifo watermark equal with data length in PIO mode. + * Set as true if alignment is needed. * @data_shift: log2 of FIFO item size. * @part_buf_start: Start index in part_buf. * @part_buf_count: Bytes of partial data in part_buf. @@ -163,6 +165,7 @@ struct dw_mci { void __iomem *regs; void __iomem *fifo_reg; u32 data_addr_override; + bool wm_aligned; struct scatterlist *sg; struct sg_mapping_iter sg_miter; From 4c8a03c727d930b0633fa45fd8afcd1df88bb5b4 Mon Sep 17 00:00:00 2001 From: Jun Nie Date: Fri, 6 Jan 2017 12:24:45 +0800 Subject: [PATCH 028/145] mmc: dt-bindings: add ZTE ZX296718 MMC bindings Document the device-tree binding of ZTE MMC host on ZX296718 SoC. Signed-off-by: Jun Nie Acked-by: Rob Herring Signed-off-by: Jaehoon Chung Signed-off-by: Ulf Hansson --- .../devicetree/bindings/mmc/zx-dw-mshc.txt | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 Documentation/devicetree/bindings/mmc/zx-dw-mshc.txt diff --git a/Documentation/devicetree/bindings/mmc/zx-dw-mshc.txt b/Documentation/devicetree/bindings/mmc/zx-dw-mshc.txt new file mode 100644 index 000000000000..eaade0e5adeb --- /dev/null +++ b/Documentation/devicetree/bindings/mmc/zx-dw-mshc.txt @@ -0,0 +1,33 @@ +* ZTE specific extensions to the Synopsys Designware Mobile Storage + Host Controller + +The Synopsys designware mobile storage host controller is used to interface +a SoC with storage medium such as eMMC or SD/MMC cards. This file documents +differences between the core Synopsys dw mshc controller properties described +by synopsys-dw-mshc.txt and the properties used by the ZTE specific +extensions to the Synopsys Designware Mobile Storage Host Controller. + +Required Properties: + +* compatible: should be + - "zte,zx296718-dw-mshc": for ZX SoCs + +Example: + + mmc1: mmc@1110000 { + compatible = "zte,zx296718-dw-mshc"; + reg = <0x01110000 0x1000>; + interrupts = ; + fifo-depth = <32>; + data-addr = <0x200>; + fifo-watermark-aligned; + bus-width = <4>; + clock-frequency = <50000000>; + clocks = <&topcrm SD0_AHB>, <&topcrm SD0_WCLK>; + clock-names = "biu", "ciu"; + num-slots = <1>; + max-frequency = <50000000>; + cap-sdio-irq; + cap-sd-highspeed; + status = "disabled"; + }; From a8c643ad00f6374d7154a65d19b18934185dc40c Mon Sep 17 00:00:00 2001 From: Jun Nie Date: Fri, 6 Jan 2017 12:24:46 +0800 Subject: [PATCH 029/145] mmc: dw_mmc: zx: Initial support for ZX mmc controller This platform driver adds initial support for the DW host controller found on ZTE SoCs. It has been tested on ZX296718 EVB board currently. More support on timing tuning will be added when hardware is available. Signed-off-by: Jun Nie Signed-off-by: Jaehoon Chung Signed-off-by: Ulf Hansson --- drivers/mmc/host/Kconfig | 9 ++ drivers/mmc/host/Makefile | 1 + drivers/mmc/host/dw_mmc-zx.c | 241 +++++++++++++++++++++++++++++++++++ drivers/mmc/host/dw_mmc-zx.h | 31 +++++ 4 files changed, 282 insertions(+) create mode 100644 drivers/mmc/host/dw_mmc-zx.c create mode 100644 drivers/mmc/host/dw_mmc-zx.h diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index 2eb97014dc3f..f08691a58d7e 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -683,6 +683,15 @@ config MMC_DW_ROCKCHIP Synopsys DesignWare Memory Card Interface driver. Select this option for platforms based on RK3066, RK3188 and RK3288 SoC's. +config MMC_DW_ZX + tristate "ZTE specific extensions for Synopsys DW Memory Card Interface" + depends on MMC_DW && ARCH_ZX + select MMC_DW_PLTFM + help + This selects support for ZTE SoC specific extensions to the + Synopsys DesignWare Memory Card Interface driver. Select this option + for platforms based on ZX296718 SoC's. + config MMC_SH_MMCIF tristate "SuperH Internal MMCIF support" depends on HAS_DMA diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile index ccc9c4cba154..6d548c4ee2fa 100644 --- a/drivers/mmc/host/Makefile +++ b/drivers/mmc/host/Makefile @@ -48,6 +48,7 @@ obj-$(CONFIG_MMC_DW_EXYNOS) += dw_mmc-exynos.o obj-$(CONFIG_MMC_DW_K3) += dw_mmc-k3.o obj-$(CONFIG_MMC_DW_PCI) += dw_mmc-pci.o obj-$(CONFIG_MMC_DW_ROCKCHIP) += dw_mmc-rockchip.o +obj-$(CONFIG_MMC_DW_ZX) += dw_mmc-zx.o obj-$(CONFIG_MMC_SH_MMCIF) += sh_mmcif.o obj-$(CONFIG_MMC_JZ4740) += jz4740_mmc.o obj-$(CONFIG_MMC_VUB300) += vub300.o diff --git a/drivers/mmc/host/dw_mmc-zx.c b/drivers/mmc/host/dw_mmc-zx.c new file mode 100644 index 000000000000..d38e94ae2b85 --- /dev/null +++ b/drivers/mmc/host/dw_mmc-zx.c @@ -0,0 +1,241 @@ +/* + * ZX Specific Extensions for Synopsys DW Multimedia Card Interface driver + * + * Copyright (C) 2016, Linaro Ltd. + * Copyright (C) 2016, ZTE Corp. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dw_mmc.h" +#include "dw_mmc-pltfm.h" +#include "dw_mmc-zx.h" + +struct dw_mci_zx_priv_data { + struct regmap *sysc_base; +}; + +enum delay_type { + DELAY_TYPE_READ, /* read dqs delay */ + DELAY_TYPE_CLK, /* clk sample delay */ +}; + +static int dw_mci_zx_emmc_set_delay(struct dw_mci *host, unsigned int delay, + enum delay_type dflag) +{ + struct dw_mci_zx_priv_data *priv = host->priv; + struct regmap *sysc_base = priv->sysc_base; + unsigned int clksel; + unsigned int loop = 1000; + int ret; + + if (!sysc_base) + return -EINVAL; + + ret = regmap_update_bits(sysc_base, LB_AON_EMMC_CFG_REG0, + PARA_HALF_CLK_MODE | PARA_DLL_BYPASS_MODE | + PARA_PHASE_DET_SEL_MASK | + PARA_DLL_LOCK_NUM_MASK | + DLL_REG_SET | PARA_DLL_START_MASK, + PARA_DLL_START(4) | PARA_DLL_LOCK_NUM(4)); + if (ret) + return ret; + + ret = regmap_read(sysc_base, LB_AON_EMMC_CFG_REG1, &clksel); + if (ret) + return ret; + + if (dflag == DELAY_TYPE_CLK) { + clksel &= ~CLK_SAMP_DELAY_MASK; + clksel |= CLK_SAMP_DELAY(delay); + } else { + clksel &= ~READ_DQS_DELAY_MASK; + clksel |= READ_DQS_DELAY(delay); + } + + regmap_write(sysc_base, LB_AON_EMMC_CFG_REG1, clksel); + regmap_update_bits(sysc_base, LB_AON_EMMC_CFG_REG0, + PARA_DLL_START_MASK | PARA_DLL_LOCK_NUM_MASK | + DLL_REG_SET, + PARA_DLL_START(4) | PARA_DLL_LOCK_NUM(4) | + DLL_REG_SET); + + do { + ret = regmap_read(sysc_base, LB_AON_EMMC_CFG_REG2, &clksel); + if (ret) + return ret; + + } while (--loop && !(clksel & ZX_DLL_LOCKED)); + + if (!loop) { + dev_err(host->dev, "Error: %s dll lock fail\n", __func__); + return -EIO; + } + + return 0; +} + +static int dw_mci_zx_emmc_execute_tuning(struct dw_mci_slot *slot, u32 opcode) +{ + struct dw_mci *host = slot->host; + struct mmc_host *mmc = slot->mmc; + int ret, len = 0, start = 0, end = 0, delay, best = 0; + + for (delay = 1; delay < 128; delay++) { + ret = dw_mci_zx_emmc_set_delay(host, delay, DELAY_TYPE_CLK); + if (!ret && mmc_send_tuning(mmc, opcode, NULL)) { + if (start >= 0) { + end = delay - 1; + /* check and update longest good range */ + if ((end - start) > len) { + best = (start + end) >> 1; + len = end - start; + } + } + start = -1; + end = 0; + continue; + } + if (start < 0) + start = delay; + } + + if (start >= 0) { + end = delay - 1; + if ((end - start) > len) { + best = (start + end) >> 1; + len = end - start; + } + } + if (best < 0) + return -EIO; + + dev_info(host->dev, "%s best range: start %d end %d\n", __func__, + start, end); + return dw_mci_zx_emmc_set_delay(host, best, DELAY_TYPE_CLK); +} + +static int dw_mci_zx_prepare_hs400_tuning(struct dw_mci *host, + struct mmc_ios *ios) +{ + int ret; + + /* config phase shift as 90 degree */ + ret = dw_mci_zx_emmc_set_delay(host, 32, DELAY_TYPE_READ); + if (ret < 0) + return -EIO; + + return 0; +} + +static int dw_mci_zx_execute_tuning(struct dw_mci_slot *slot, u32 opcode) +{ + struct dw_mci *host = slot->host; + + if (host->verid == 0x290a) /* only for emmc */ + return dw_mci_zx_emmc_execute_tuning(slot, opcode); + /* TODO: Add 0x210a dedicated tuning for sd/sdio */ + + return 0; +} + +static int dw_mci_zx_parse_dt(struct dw_mci *host) +{ + struct device_node *np = host->dev->of_node; + struct device_node *node; + struct dw_mci_zx_priv_data *priv; + struct regmap *sysc_base; + int ret; + + /* syscon is needed only by emmc */ + node = of_parse_phandle(np, "zte,aon-syscon", 0); + if (node) { + sysc_base = syscon_node_to_regmap(node); + of_node_put(node); + + if (IS_ERR(sysc_base)) { + ret = PTR_ERR(sysc_base); + if (ret != -EPROBE_DEFER) + dev_err(host->dev, "Can't get syscon: %d\n", + ret); + return ret; + } + } else { + return 0; + } + + priv = devm_kzalloc(host->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + priv->sysc_base = sysc_base; + host->priv = priv; + + return 0; +} + +static unsigned long zx_dwmmc_caps[3] = { + MMC_CAP_CMD23, + MMC_CAP_CMD23, + MMC_CAP_CMD23, +}; + +static const struct dw_mci_drv_data zx_drv_data = { + .caps = zx_dwmmc_caps, + .execute_tuning = dw_mci_zx_execute_tuning, + .prepare_hs400_tuning = dw_mci_zx_prepare_hs400_tuning, + .parse_dt = dw_mci_zx_parse_dt, +}; + +static const struct of_device_id dw_mci_zx_match[] = { + { .compatible = "zte,zx296718-dw-mshc", .data = &zx_drv_data}, + {}, +}; +MODULE_DEVICE_TABLE(of, dw_mci_zx_match); + +static int dw_mci_zx_probe(struct platform_device *pdev) +{ + const struct dw_mci_drv_data *drv_data; + const struct of_device_id *match; + + match = of_match_node(dw_mci_zx_match, pdev->dev.of_node); + drv_data = match->data; + + return dw_mci_pltfm_register(pdev, drv_data); +} + +static const struct dev_pm_ops dw_mci_zx_dev_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) + SET_RUNTIME_PM_OPS(dw_mci_runtime_suspend, + dw_mci_runtime_resume, + NULL) +}; + +static struct platform_driver dw_mci_zx_pltfm_driver = { + .probe = dw_mci_zx_probe, + .remove = dw_mci_pltfm_remove, + .driver = { + .name = "dwmmc_zx", + .of_match_table = dw_mci_zx_match, + .pm = &dw_mci_zx_dev_pm_ops, + }, +}; + +module_platform_driver(dw_mci_zx_pltfm_driver); + +MODULE_DESCRIPTION("ZTE emmc/sd driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/mmc/host/dw_mmc-zx.h b/drivers/mmc/host/dw_mmc-zx.h new file mode 100644 index 000000000000..f369997a39ec --- /dev/null +++ b/drivers/mmc/host/dw_mmc-zx.h @@ -0,0 +1,31 @@ +#ifndef _DW_MMC_ZX_H_ +#define _DW_MMC_ZX_H_ + +/* ZX296718 SoC specific DLL register offset. */ +#define LB_AON_EMMC_CFG_REG0 0x1B0 +#define LB_AON_EMMC_CFG_REG1 0x1B4 +#define LB_AON_EMMC_CFG_REG2 0x1B8 + +/* LB_AON_EMMC_CFG_REG0 register defines */ +#define PARA_DLL_START(x) ((x) & 0xFF) +#define PARA_DLL_START_MASK 0xFF +#define DLL_REG_SET BIT(8) +#define PARA_DLL_LOCK_NUM(x) (((x) & 7) << 16) +#define PARA_DLL_LOCK_NUM_MASK (7 << 16) +#define PARA_PHASE_DET_SEL(x) (((x) & 7) << 20) +#define PARA_PHASE_DET_SEL_MASK (7 << 20) +#define PARA_DLL_BYPASS_MODE BIT(23) +#define PARA_HALF_CLK_MODE BIT(24) + +/* LB_AON_EMMC_CFG_REG1 register defines */ +#define READ_DQS_DELAY(x) ((x) & 0x7F) +#define READ_DQS_DELAY_MASK (0x7F) +#define READ_DQS_BYPASS_MODE BIT(7) +#define CLK_SAMP_DELAY(x) (((x) & 0x7F) << 8) +#define CLK_SAMP_DELAY_MASK (0x7F << 8) +#define CLK_SAMP_BYPASS_MODE BIT(15) + +/* LB_AON_EMMC_CFG_REG2 register defines */ +#define ZX_DLL_LOCKED BIT(2) + +#endif /* _DW_MMC_ZX_H_ */ From a6b448884a5f8eed5fec888f918aef26be338912 Mon Sep 17 00:00:00 2001 From: yangbo lu Date: Mon, 26 Dec 2016 17:46:29 +0800 Subject: [PATCH 030/145] mmc: sdhci-esdhc: clean up register definitions The eSDHC register definitions in header file were messy and confusing. This patch is to clean up these definitions. Signed-off-by: Yangbo Lu Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-esdhc.h | 37 +++++++++++++++++----------------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/drivers/mmc/host/sdhci-esdhc.h b/drivers/mmc/host/sdhci-esdhc.h index de132e281753..8cd8449c7bc5 100644 --- a/drivers/mmc/host/sdhci-esdhc.h +++ b/drivers/mmc/host/sdhci-esdhc.h @@ -24,30 +24,31 @@ SDHCI_QUIRK_PIO_NEEDS_DELAY | \ SDHCI_QUIRK_NO_HISPD_BIT) -#define ESDHC_PROCTL 0x28 - -#define ESDHC_SYSTEM_CONTROL 0x2c -#define ESDHC_CLOCK_MASK 0x0000fff0 -#define ESDHC_PREDIV_SHIFT 8 -#define ESDHC_DIVIDER_SHIFT 4 -#define ESDHC_CLOCK_PEREN 0x00000004 -#define ESDHC_CLOCK_HCKEN 0x00000002 -#define ESDHC_CLOCK_IPGEN 0x00000001 - /* pltfm-specific */ #define ESDHC_HOST_CONTROL_LE 0x20 /* - * P2020 interpretation of the SDHCI_HOST_CONTROL register + * eSDHC register definition */ -#define ESDHC_CTRL_4BITBUS (0x1 << 1) -#define ESDHC_CTRL_8BITBUS (0x2 << 1) -#define ESDHC_CTRL_BUSWIDTH_MASK (0x3 << 1) -/* OF-specific */ -#define ESDHC_DMA_SYSCTL 0x40c -#define ESDHC_DMA_SNOOP 0x00000040 +/* Protocol Control Register */ +#define ESDHC_PROCTL 0x28 +#define ESDHC_CTRL_4BITBUS (0x1 << 1) +#define ESDHC_CTRL_8BITBUS (0x2 << 1) +#define ESDHC_CTRL_BUSWIDTH_MASK (0x3 << 1) +#define ESDHC_HOST_CONTROL_RES 0x01 -#define ESDHC_HOST_CONTROL_RES 0x01 +/* System Control Register */ +#define ESDHC_SYSTEM_CONTROL 0x2c +#define ESDHC_CLOCK_MASK 0x0000fff0 +#define ESDHC_PREDIV_SHIFT 8 +#define ESDHC_DIVIDER_SHIFT 4 +#define ESDHC_CLOCK_PEREN 0x00000004 +#define ESDHC_CLOCK_HCKEN 0x00000002 +#define ESDHC_CLOCK_IPGEN 0x00000001 + +/* Control Register for DMA transfer */ +#define ESDHC_DMA_SYSCTL 0x40c +#define ESDHC_DMA_SNOOP 0x00000040 #endif /* _DRIVERS_MMC_SDHCI_ESDHC_H */ From e9acc77dd046b22c7ebf70e35f68968978445f8b Mon Sep 17 00:00:00 2001 From: yangbo lu Date: Mon, 26 Dec 2016 17:40:44 +0800 Subject: [PATCH 031/145] mmc: sdhci-of-esdhc: remove default broken-cd for ARM Initially all QorIQ platforms were PowerPC architecture and they didn't support card detection except several platforms. The driver added the quirk SDHCI_QUIRK_BROKEN_CARD_DETECTION as default and this made broken-cd property in dts node didn't work. Now QorIQ platform turns to ARM architecture and most of them could support card detection. However it's a large number of dts trees that need to be fixed with broken-cd if we remove the default SDHCI_QUIRK_BROKEN_CARD_DETECTION in driver. And the users don't want to see this. So this patch is to remove this default quirk just for ARM and keep it for PowerPC.(Note, QorIQ PowerPC platform only has big-endian eSDHC while QorIQ ARM platform has big-endian or little-endian eSDHC) This makes broken-cd property work again for ARM. Signed-off-by: Yangbo Lu Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-of-esdhc.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c index 9a6eb4492172..364f6b87a728 100644 --- a/drivers/mmc/host/sdhci-of-esdhc.c +++ b/drivers/mmc/host/sdhci-of-esdhc.c @@ -569,16 +569,19 @@ static const struct sdhci_ops sdhci_esdhc_le_ops = { }; static const struct sdhci_pltfm_data sdhci_esdhc_be_pdata = { - .quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_BROKEN_CARD_DETECTION - | SDHCI_QUIRK_NO_CARD_NO_RESET - | SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, + .quirks = ESDHC_DEFAULT_QUIRKS | +#ifdef CONFIG_PPC + SDHCI_QUIRK_BROKEN_CARD_DETECTION | +#endif + SDHCI_QUIRK_NO_CARD_NO_RESET | + SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, .ops = &sdhci_esdhc_be_ops, }; static const struct sdhci_pltfm_data sdhci_esdhc_le_pdata = { - .quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_BROKEN_CARD_DETECTION - | SDHCI_QUIRK_NO_CARD_NO_RESET - | SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, + .quirks = ESDHC_DEFAULT_QUIRKS | + SDHCI_QUIRK_NO_CARD_NO_RESET | + SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, .ops = &sdhci_esdhc_le_ops, }; @@ -643,8 +646,7 @@ static int sdhci_esdhc_probe(struct platform_device *pdev) of_device_is_compatible(np, "fsl,p5020-esdhc") || of_device_is_compatible(np, "fsl,p4080-esdhc") || of_device_is_compatible(np, "fsl,p1020-esdhc") || - of_device_is_compatible(np, "fsl,t1040-esdhc") || - of_device_is_compatible(np, "fsl,ls1021a-esdhc")) + of_device_is_compatible(np, "fsl,t1040-esdhc")) host->quirks &= ~SDHCI_QUIRK_BROKEN_CARD_DETECTION; if (of_device_is_compatible(np, "fsl,ls1021a-esdhc")) From 3bc702ed211f1a384aa1ca1ad852ef40c5757ded Mon Sep 17 00:00:00 2001 From: yong mao Date: Tue, 3 Jan 2017 16:49:57 +0800 Subject: [PATCH 032/145] mmc: mediatek: correct the implementation of msdc_card_busy msdc_card_busy only need check if the data0 is low. In sdio data1 irq mode, data1 may be low because of interruption. Signed-off-by: Yong Mao Signed-off-by: Chaotian Jing Signed-off-by: Ulf Hansson --- drivers/mmc/host/mtk-sd.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c index d33828efc253..8e32580c12b5 100644 --- a/drivers/mmc/host/mtk-sd.c +++ b/drivers/mmc/host/mtk-sd.c @@ -1075,11 +1075,8 @@ static int msdc_card_busy(struct mmc_host *mmc) struct msdc_host *host = mmc_priv(mmc); u32 status = readl(host->base + MSDC_PS); - /* check if any pin between dat[0:3] is low */ - if (((status >> 16) & 0xf) != 0xf) - return 1; - - return 0; + /* only check if data0 is low */ + return !(status & BIT(16)); } static void msdc_request_timeout(struct work_struct *work) From 6ac9b83772a0893d5e858f0f5fa1ad36d930d7de Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 2 Jan 2017 14:05:24 +0200 Subject: [PATCH 033/145] mmc: sdhci-pci: Remove unused member cd_con_id cd_con_id is not used and always NULL. Remove it to make code a bit more cleaner. Signed-off-by: Andy Shevchenko Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-pci-core.c | 3 +-- drivers/mmc/host/sdhci-pci.h | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/mmc/host/sdhci-pci-core.c b/drivers/mmc/host/sdhci-pci-core.c index 1a72d32af07f..5c275b7d0d53 100644 --- a/drivers/mmc/host/sdhci-pci-core.c +++ b/drivers/mmc/host/sdhci-pci-core.c @@ -424,7 +424,6 @@ static int byt_sdio_probe_slot(struct sdhci_pci_slot *slot) static int byt_sd_probe_slot(struct sdhci_pci_slot *slot) { slot->host->mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY; - slot->cd_con_id = NULL; slot->cd_idx = 0; slot->cd_override_level = true; if (slot->chip->pdev->device == PCI_DEVICE_ID_INTEL_BXT_SD || @@ -1817,7 +1816,7 @@ static struct sdhci_pci_slot *sdhci_pci_probe_slot( host->mmc->caps2 |= MMC_CAP2_NO_PRESCAN_POWERUP; if (slot->cd_idx >= 0) { - ret = mmc_gpiod_request_cd(host->mmc, slot->cd_con_id, slot->cd_idx, + ret = mmc_gpiod_request_cd(host->mmc, NULL, slot->cd_idx, slot->cd_override_level, 0, NULL); if (ret == -EPROBE_DEFER) goto remove; diff --git a/drivers/mmc/host/sdhci-pci.h b/drivers/mmc/host/sdhci-pci.h index 4abdaed72bd4..36f743464fcc 100644 --- a/drivers/mmc/host/sdhci-pci.h +++ b/drivers/mmc/host/sdhci-pci.h @@ -81,7 +81,6 @@ struct sdhci_pci_slot { int cd_gpio; int cd_irq; - char *cd_con_id; int cd_idx; bool cd_override_level; From c1ada71fb78ed885f2d403f8d18ae43656cf4e86 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 2 Jan 2017 14:05:25 +0200 Subject: [PATCH 034/145] mmc: slot-gpio: Don't override con_id when request descriptor The caller may supply connection ID, index, or both. All combinations are possible and mmc framework should not make any assumption on what exactly caller wants. Remove con_id override conditionals in mmc_gpiod_request_ro() and mmc_gpiod_request_cd(). Signed-off-by: Andy Shevchenko Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson --- drivers/mmc/core/slot-gpio.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/mmc/core/slot-gpio.c b/drivers/mmc/core/slot-gpio.c index babe591aea96..a8450a8701e4 100644 --- a/drivers/mmc/core/slot-gpio.c +++ b/drivers/mmc/core/slot-gpio.c @@ -235,9 +235,6 @@ int mmc_gpiod_request_cd(struct mmc_host *host, const char *con_id, struct gpio_desc *desc; int ret; - if (!con_id) - con_id = ctx->cd_label; - desc = devm_gpiod_get_index(host->parent, con_id, idx, GPIOD_IN); if (IS_ERR(desc)) return PTR_ERR(desc); @@ -289,9 +286,6 @@ int mmc_gpiod_request_ro(struct mmc_host *host, const char *con_id, struct gpio_desc *desc; int ret; - if (!con_id) - con_id = ctx->ro_label; - desc = devm_gpiod_get_index(host->parent, con_id, idx, GPIOD_IN); if (IS_ERR(desc)) return PTR_ERR(desc); From ad7014b3949b6c2b6ce46a546d6d204b5643e621 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Fri, 6 Jan 2017 09:38:33 +0100 Subject: [PATCH 035/145] mmc: host: tmio: drop superfluous exit path The probe exit path on error does nothing since commit 94b110aff8679b ("mmc: tmio: add tmio_mmc_host_alloc/free()"), so we can bail out immediately. Signed-off-by: Wolfram Sang Reviewed-by: Simon Horman Signed-off-by: Ulf Hansson --- drivers/mmc/host/tmio_mmc_pio.c | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c index 3ca97f3c3079..b11b088775a8 100644 --- a/drivers/mmc/host/tmio_mmc_pio.c +++ b/drivers/mmc/host/tmio_mmc_pio.c @@ -1143,7 +1143,7 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host, ret = mmc_of_parse(mmc); if (ret < 0) - goto host_free; + return ret; _host->pdata = pdata; platform_set_drvdata(pdev, mmc); @@ -1153,14 +1153,12 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host, ret = tmio_mmc_init_ocr(_host); if (ret < 0) - goto host_free; + return ret; _host->ctl = devm_ioremap(&pdev->dev, res_ctl->start, resource_size(res_ctl)); - if (!_host->ctl) { - ret = -ENOMEM; - goto host_free; - } + if (!_host->ctl) + return -ENOMEM; tmio_mmc_ops.card_busy = _host->card_busy; tmio_mmc_ops.start_signal_voltage_switch = _host->start_signal_voltage_switch; @@ -1198,10 +1196,8 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host, * Check the sanity of mmc->f_min to prevent tmio_mmc_set_clock() from * looping forever... */ - if (mmc->f_min == 0) { - ret = -EINVAL; - goto host_free; - } + if (mmc->f_min == 0) + return -EINVAL; /* * While using internal tmio hardware logic for card detection, we need @@ -1266,10 +1262,6 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host, } return 0; - -host_free: - - return ret; } EXPORT_SYMBOL(tmio_mmc_host_probe); From 457e4f7f668d69bc105b3619c5ff2769506adb89 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Sun, 8 Jan 2017 18:44:26 +0100 Subject: [PATCH 036/145] mmc: mmc_test: Use kmalloc_array() in mmc_test_area_init() * A multiplication for the size determination of a memory allocation indicated that an array data structure should be processed. Thus use the corresponding function "kmalloc_array". This issue was detected by using the Coccinelle software. * Replace the specification of a data structure by a pointer dereference to make the corresponding size determination a bit safer according to the Linux coding style convention. Signed-off-by: Markus Elfring Reviewed-by: Linus Walleij Reviewed-by: Shawn Lin Reviewed-by: Andy Shevchenko Signed-off-by: Ulf Hansson --- drivers/mmc/core/mmc_test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mmc/core/mmc_test.c b/drivers/mmc/core/mmc_test.c index bd8eb9bfc153..de0d675ef37f 100644 --- a/drivers/mmc/core/mmc_test.c +++ b/drivers/mmc/core/mmc_test.c @@ -1579,7 +1579,7 @@ static int mmc_test_area_init(struct mmc_test_card *test, int erase, int fill) if (!t->mem) return -ENOMEM; - t->sg = kmalloc(sizeof(struct scatterlist) * t->max_segs, GFP_KERNEL); + t->sg = kmalloc_array(t->max_segs, sizeof(*t->sg), GFP_KERNEL); if (!t->sg) { ret = -ENOMEM; goto out_free; From 74536bc0834fbfd5ead74beef20f9ba387df6a5a Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Sun, 8 Jan 2017 19:05:37 +0100 Subject: [PATCH 037/145] mmc: mmc_test: Fix a typo in a comment line Add a missing character in the function description. Signed-off-by: Markus Elfring Reviewed-by: Linus Walleij Reviewed-by: Shawn Lin Reviewed-by: Andy Shevchenko Signed-off-by: Ulf Hansson --- drivers/mmc/core/mmc_test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mmc/core/mmc_test.c b/drivers/mmc/core/mmc_test.c index de0d675ef37f..69c879822e2b 100644 --- a/drivers/mmc/core/mmc_test.c +++ b/drivers/mmc/core/mmc_test.c @@ -1533,7 +1533,7 @@ static int mmc_test_area_cleanup(struct mmc_test_card *test) /* * Initialize an area for testing large transfers. The test area is set to the - * middle of the card because cards may have different charateristics at the + * middle of the card because cards may have different characteristics at the * front (for FAT file system optimization). Optionally, the area is erased * (if the card supports it) which may improve write performance. Optionally, * the area is filled with data for subsequent read tests. From dc3a5fe6ec115ee1d9d1c2ee8004c9a5193b2435 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Sun, 8 Jan 2017 19:48:28 +0100 Subject: [PATCH 038/145] mmc: mmc_test: Use seq_puts() in mtf_testlist_show() The script "checkpatch.pl" pointed information out like the following. WARNING: Prefer seq_puts to seq_printf Thus fix the affected source code place. Signed-off-by: Markus Elfring Reviewed-by: Linus Walleij Reviewed-by: Shawn Lin Reviewed-by: Andy Shevchenko Signed-off-by: Ulf Hansson --- drivers/mmc/core/mmc_test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mmc/core/mmc_test.c b/drivers/mmc/core/mmc_test.c index 69c879822e2b..1641b863c3c7 100644 --- a/drivers/mmc/core/mmc_test.c +++ b/drivers/mmc/core/mmc_test.c @@ -3163,7 +3163,7 @@ static int mtf_testlist_show(struct seq_file *sf, void *data) mutex_lock(&mmc_test_lock); - seq_printf(sf, "0:\tRun all tests\n"); + seq_puts(sf, "0:\tRun all tests\n"); for (i = 0; i < ARRAY_SIZE(mmc_test_cases); i++) seq_printf(sf, "%d:\t%s\n", i+1, mmc_test_cases[i].name); From fda02ea814f92d11a2400ec583b4d83cbb633ad0 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Sun, 8 Jan 2017 20:25:39 +0100 Subject: [PATCH 039/145] mmc: mmc_test: Add some spaces for better code readability Use space characters at some source code places according to the Linux coding style convention. Signed-off-by: Markus Elfring Reviewed-by: Linus Walleij Reviewed-by: Shawn Lin Reviewed-by: Andy Shevchenko Signed-off-by: Ulf Hansson --- drivers/mmc/core/mmc_test.c | 42 ++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/drivers/mmc/core/mmc_test.c b/drivers/mmc/core/mmc_test.c index 1641b863c3c7..c4fc2649cb34 100644 --- a/drivers/mmc/core/mmc_test.c +++ b/drivers/mmc/core/mmc_test.c @@ -641,11 +641,11 @@ static int __mmc_test_prepare(struct mmc_test_card *test, int write) if (write) memset(test->buffer, 0xDF, 512); else { - for (i = 0;i < 512;i++) + for (i = 0; i < 512; i++) test->buffer[i] = i; } - for (i = 0;i < BUFFER_SIZE / 512;i++) { + for (i = 0; i < BUFFER_SIZE / 512; i++) { ret = mmc_test_buffer_transfer(test, test->buffer, i, 512, 1); if (ret) return ret; @@ -674,7 +674,7 @@ static int mmc_test_cleanup(struct mmc_test_card *test) memset(test->buffer, 0, 512); - for (i = 0;i < BUFFER_SIZE / 512;i++) { + for (i = 0; i < BUFFER_SIZE / 512; i++) { ret = mmc_test_buffer_transfer(test, test->buffer, i, 512, 1); if (ret) return ret; @@ -946,7 +946,7 @@ static int mmc_test_transfer(struct mmc_test_card *test, unsigned long flags; if (write) { - for (i = 0;i < blocks * blksz;i++) + for (i = 0; i < blocks * blksz; i++) test->scratch[i] = i; } else { memset(test->scratch, 0, BUFFER_SIZE); @@ -980,7 +980,7 @@ static int mmc_test_transfer(struct mmc_test_card *test, memset(test->buffer, 0, sectors * 512); - for (i = 0;i < sectors;i++) { + for (i = 0; i < sectors; i++) { ret = mmc_test_buffer_transfer(test, test->buffer + i * 512, dev_addr + i, 512, 0); @@ -988,12 +988,12 @@ static int mmc_test_transfer(struct mmc_test_card *test, return ret; } - for (i = 0;i < blocks * blksz;i++) { + for (i = 0; i < blocks * blksz; i++) { if (test->buffer[i] != (u8)i) return RESULT_FAIL; } - for (;i < sectors * 512;i++) { + for (; i < sectors * 512; i++) { if (test->buffer[i] != 0xDF) return RESULT_FAIL; } @@ -1001,7 +1001,7 @@ static int mmc_test_transfer(struct mmc_test_card *test, local_irq_save(flags); sg_copy_to_buffer(sg, sg_len, test->scratch, BUFFER_SIZE); local_irq_restore(flags); - for (i = 0;i < blocks * blksz;i++) { + for (i = 0; i < blocks * blksz; i++) { if (test->scratch[i] != (u8)i) return RESULT_FAIL; } @@ -1086,7 +1086,7 @@ static int mmc_test_multi_write(struct mmc_test_card *test) sg_init_one(&sg, test->buffer, size); - return mmc_test_transfer(test, &sg, 1, 0, size/512, 512, 1); + return mmc_test_transfer(test, &sg, 1, 0, size / 512, 512, 1); } static int mmc_test_multi_read(struct mmc_test_card *test) @@ -1107,7 +1107,7 @@ static int mmc_test_multi_read(struct mmc_test_card *test) sg_init_one(&sg, test->buffer, size); - return mmc_test_transfer(test, &sg, 1, 0, size/512, 512, 0); + return mmc_test_transfer(test, &sg, 1, 0, size / 512, 512, 0); } static int mmc_test_pow2_write(struct mmc_test_card *test) @@ -1118,7 +1118,7 @@ static int mmc_test_pow2_write(struct mmc_test_card *test) if (!test->card->csd.write_partial) return RESULT_UNSUP_CARD; - for (i = 1; i < 512;i <<= 1) { + for (i = 1; i < 512; i <<= 1) { sg_init_one(&sg, test->buffer, i); ret = mmc_test_transfer(test, &sg, 1, 0, 1, i, 1); if (ret) @@ -1136,7 +1136,7 @@ static int mmc_test_pow2_read(struct mmc_test_card *test) if (!test->card->csd.read_partial) return RESULT_UNSUP_CARD; - for (i = 1; i < 512;i <<= 1) { + for (i = 1; i < 512; i <<= 1) { sg_init_one(&sg, test->buffer, i); ret = mmc_test_transfer(test, &sg, 1, 0, 1, i, 0); if (ret) @@ -1154,7 +1154,7 @@ static int mmc_test_weird_write(struct mmc_test_card *test) if (!test->card->csd.write_partial) return RESULT_UNSUP_CARD; - for (i = 3; i < 512;i += 7) { + for (i = 3; i < 512; i += 7) { sg_init_one(&sg, test->buffer, i); ret = mmc_test_transfer(test, &sg, 1, 0, 1, i, 1); if (ret) @@ -1172,7 +1172,7 @@ static int mmc_test_weird_read(struct mmc_test_card *test) if (!test->card->csd.read_partial) return RESULT_UNSUP_CARD; - for (i = 3; i < 512;i += 7) { + for (i = 3; i < 512; i += 7) { sg_init_one(&sg, test->buffer, i); ret = mmc_test_transfer(test, &sg, 1, 0, 1, i, 0); if (ret) @@ -1231,7 +1231,7 @@ static int mmc_test_align_multi_write(struct mmc_test_card *test) for (i = 1; i < TEST_ALIGN_END; i++) { sg_init_one(&sg, test->buffer + i, size); - ret = mmc_test_transfer(test, &sg, 1, 0, size/512, 512, 1); + ret = mmc_test_transfer(test, &sg, 1, 0, size / 512, 512, 1); if (ret) return ret; } @@ -1258,7 +1258,7 @@ static int mmc_test_align_multi_read(struct mmc_test_card *test) for (i = 1; i < TEST_ALIGN_END; i++) { sg_init_one(&sg, test->buffer + i, size); - ret = mmc_test_transfer(test, &sg, 1, 0, size/512, 512, 0); + ret = mmc_test_transfer(test, &sg, 1, 0, size / 512, 512, 0); if (ret) return ret; } @@ -1357,7 +1357,7 @@ static int mmc_test_multi_write_high(struct mmc_test_card *test) sg_init_table(&sg, 1); sg_set_page(&sg, test->highmem, size, 0); - return mmc_test_transfer(test, &sg, 1, 0, size/512, 512, 1); + return mmc_test_transfer(test, &sg, 1, 0, size / 512, 512, 1); } static int mmc_test_multi_read_high(struct mmc_test_card *test) @@ -1379,7 +1379,7 @@ static int mmc_test_multi_read_high(struct mmc_test_card *test) sg_init_table(&sg, 1); sg_set_page(&sg, test->highmem, size, 0); - return mmc_test_transfer(test, &sg, 1, 0, size/512, 512, 0); + return mmc_test_transfer(test, &sg, 1, 0, size / 512, 512, 0); } #else @@ -2147,7 +2147,7 @@ static int mmc_test_rw_multiple_sg_len(struct mmc_test_card *test, int i; for (i = 0 ; i < rw->len && ret == 0; i++) { - ret = mmc_test_rw_multiple(test, rw, 512*1024, rw->size, + ret = mmc_test_rw_multiple(test, rw, 512 * 1024, rw->size, rw->sg_len[i]); if (ret) break; @@ -2954,7 +2954,7 @@ static void mmc_test_run(struct mmc_test_card *test, int testcase) mmc_claim_host(test->card->host); - for (i = 0;i < ARRAY_SIZE(mmc_test_cases);i++) { + for (i = 0; i < ARRAY_SIZE(mmc_test_cases); i++) { struct mmc_test_general_result *gr; if (testcase && ((i + 1) != testcase)) @@ -3165,7 +3165,7 @@ static int mtf_testlist_show(struct seq_file *sf, void *data) seq_puts(sf, "0:\tRun all tests\n"); for (i = 0; i < ARRAY_SIZE(mmc_test_cases); i++) - seq_printf(sf, "%d:\t%s\n", i+1, mmc_test_cases[i].name); + seq_printf(sf, "%d:\t%s\n", i + 1, mmc_test_cases[i].name); mutex_unlock(&mmc_test_lock); From 7200449dc6a1f4556ad5da20df031bfbaf42fff5 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Sun, 8 Jan 2017 20:56:48 +0100 Subject: [PATCH 040/145] mmc: mmc_test: Combine substrings for 5 messages The script "checkpatch.pl" pointed information out like the following. WARNING: quoted string split across lines Thus fix affected source code places. Signed-off-by: Markus Elfring Reviewed-by: Linus Walleij Reviewed-by: Shawn Lin Reviewed-by: Andy Shevchenko Signed-off-by: Ulf Hansson --- drivers/mmc/core/mmc_test.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/drivers/mmc/core/mmc_test.c b/drivers/mmc/core/mmc_test.c index c4fc2649cb34..5c74fb4dfee6 100644 --- a/drivers/mmc/core/mmc_test.c +++ b/drivers/mmc/core/mmc_test.c @@ -277,8 +277,7 @@ static int mmc_test_wait_busy(struct mmc_test_card *test) if (!busy && mmc_test_busy(&cmd)) { busy = 1; if (test->card->host->caps & MMC_CAP_WAIT_WHILE_BUSY) - pr_info("%s: Warning: Host did not " - "wait for busy state to end.\n", + pr_info("%s: Warning: Host did not wait for busy state to end.\n", mmc_hostname(test->card->host)); } } while (mmc_test_busy(&cmd)); @@ -2967,8 +2966,7 @@ static void mmc_test_run(struct mmc_test_card *test, int testcase) if (mmc_test_cases[i].prepare) { ret = mmc_test_cases[i].prepare(test); if (ret) { - pr_info("%s: Result: Prepare " - "stage failed! (%d)\n", + pr_info("%s: Result: Prepare stage failed! (%d)\n", mmc_hostname(test->card->host), ret); continue; @@ -3005,13 +3003,11 @@ static void mmc_test_run(struct mmc_test_card *test, int testcase) mmc_hostname(test->card->host)); break; case RESULT_UNSUP_HOST: - pr_info("%s: Result: UNSUPPORTED " - "(by host)\n", + pr_info("%s: Result: UNSUPPORTED (by host)\n", mmc_hostname(test->card->host)); break; case RESULT_UNSUP_CARD: - pr_info("%s: Result: UNSUPPORTED " - "(by card)\n", + pr_info("%s: Result: UNSUPPORTED (by card)\n", mmc_hostname(test->card->host)); break; default: @@ -3026,8 +3022,7 @@ static void mmc_test_run(struct mmc_test_card *test, int testcase) if (mmc_test_cases[i].cleanup) { ret = mmc_test_cases[i].cleanup(test); if (ret) { - pr_info("%s: Warning: Cleanup " - "stage failed! (%d)\n", + pr_info("%s: Warning: Cleanup stage failed! (%d)\n", mmc_hostname(test->card->host), ret); } From 554d7c540ea0d30e03674a24d139dd8b5c1646c5 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Sun, 8 Jan 2017 21:25:44 +0100 Subject: [PATCH 041/145] mmc: mmc_test: Improve a size determination in five functions Replace the specification of a data structure by a pointer dereference as the parameter for the operator "sizeof" to make the corresponding size determination a bit safer according to the Linux coding style convention. Signed-off-by: Markus Elfring Reviewed-by: Linus Walleij Reviewed-by: Shawn Lin Reviewed-by: Andy Shevchenko Signed-off-by: Ulf Hansson --- drivers/mmc/core/mmc_test.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/mmc/core/mmc_test.c b/drivers/mmc/core/mmc_test.c index 5c74fb4dfee6..7784cce56895 100644 --- a/drivers/mmc/core/mmc_test.c +++ b/drivers/mmc/core/mmc_test.c @@ -356,7 +356,7 @@ static struct mmc_test_mem *mmc_test_alloc_mem(unsigned long min_sz, if (max_segs > max_page_cnt) max_segs = max_page_cnt; - mem = kzalloc(sizeof(struct mmc_test_mem), GFP_KERNEL); + mem = kzalloc(sizeof(*mem), GFP_KERNEL); if (!mem) return NULL; @@ -545,7 +545,7 @@ static void mmc_test_save_transfer_result(struct mmc_test_card *test, if (!test->gr) return; - tr = kmalloc(sizeof(struct mmc_test_transfer_result), GFP_KERNEL); + tr = kmalloc(sizeof(*tr), GFP_KERNEL); if (!tr) return; @@ -2973,8 +2973,7 @@ static void mmc_test_run(struct mmc_test_card *test, int testcase) } } - gr = kzalloc(sizeof(struct mmc_test_general_result), - GFP_KERNEL); + gr = kzalloc(sizeof(*gr), GFP_KERNEL); if (gr) { INIT_LIST_HEAD(&gr->tr_lst); @@ -3108,7 +3107,7 @@ static ssize_t mtf_test_write(struct file *file, const char __user *buf, if (ret) return ret; - test = kzalloc(sizeof(struct mmc_test_card), GFP_KERNEL); + test = kzalloc(sizeof(*test), GFP_KERNEL); if (!test) return -ENOMEM; @@ -3213,7 +3212,7 @@ static int __mmc_test_register_dbgfs_file(struct mmc_card *card, return -ENODEV; } - df = kmalloc(sizeof(struct mmc_test_dbgfs_file), GFP_KERNEL); + df = kmalloc(sizeof(*df), GFP_KERNEL); if (!df) { debugfs_remove(file); dev_err(&card->dev, From 3972a20b51c8bb887d13f5656d6fa93bf3d4fc46 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Sun, 8 Jan 2017 21:43:12 +0100 Subject: [PATCH 042/145] mmc: mmc_test: Use kcalloc() in mmc_test_alloc_mem() * The script "checkpatch.pl" pointed information out like the following. WARNING: Prefer kcalloc over kzalloc with multiply Thus fix the affected source code place. * Replace the specification of a data structure by a pointer dereference to make the corresponding size determination a bit safer according to the Linux coding style convention. Signed-off-by: Markus Elfring Reviewed-by: Linus Walleij Reviewed-by: Shawn Lin Reviewed-by: Andy Shevchenko Signed-off-by: Ulf Hansson --- drivers/mmc/core/mmc_test.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/mmc/core/mmc_test.c b/drivers/mmc/core/mmc_test.c index 7784cce56895..d350bd67b4f8 100644 --- a/drivers/mmc/core/mmc_test.c +++ b/drivers/mmc/core/mmc_test.c @@ -360,8 +360,7 @@ static struct mmc_test_mem *mmc_test_alloc_mem(unsigned long min_sz, if (!mem) return NULL; - mem->arr = kzalloc(sizeof(struct mmc_test_pages) * max_segs, - GFP_KERNEL); + mem->arr = kcalloc(max_segs, sizeof(*mem->arr), GFP_KERNEL); if (!mem->arr) goto out_free; From 63928d4789ebb3f7d35d9261089b3bcc98ae0632 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Sun, 8 Jan 2017 22:10:40 +0100 Subject: [PATCH 043/145] mmc: core: Use kmalloc_array() in mmc_alloc_sg() * A multiplication for the size determination of a memory allocation indicated that an array data structure should be processed. Thus use the corresponding function "kmalloc_array". This issue was detected by using the Coccinelle software. * Replace the specification of a data structure by a pointer dereference to make the corresponding size determination a bit safer according to the Linux coding style convention. Signed-off-by: Markus Elfring Reviewed-by: Linus Walleij Reviewed-by: Shawn Lin Reviewed-by: Andy Shevchenko Signed-off-by: Ulf Hansson --- drivers/mmc/core/queue.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mmc/core/queue.c b/drivers/mmc/core/queue.c index a6496d8027bc..b1986622c60e 100644 --- a/drivers/mmc/core/queue.c +++ b/drivers/mmc/core/queue.c @@ -152,7 +152,7 @@ static struct scatterlist *mmc_alloc_sg(int sg_len, int *err) { struct scatterlist *sg; - sg = kmalloc(sizeof(struct scatterlist)*sg_len, GFP_KERNEL); + sg = kmalloc_array(sg_len, sizeof(*sg), GFP_KERNEL); if (!sg) *err = -ENOMEM; else { From 0eb51a58ad823b2081c69ec1cf165833dd11c450 Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Mon, 9 Jan 2017 16:56:19 +0800 Subject: [PATCH 044/145] mmc: sdio: Factor out retry init card helper function Add new helper function, mmc_sdio_resend_if_cond, to be reused when trying to retry the init sequence. Signed-off-by: Shawn Lin Signed-off-by: Ulf Hansson --- drivers/mmc/core/sdio.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index ecbc52981ba5..f417adc9feb1 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -541,6 +541,15 @@ out: return err; } +static void mmc_sdio_resend_if_cond(struct mmc_host *host, + struct mmc_card *card) +{ + sdio_reset(host); + mmc_go_idle(host); + mmc_send_if_cond(host, host->ocr_avail); + mmc_remove_card(card); +} + /* * Handle the detection and initialisation of a card. * @@ -630,10 +639,7 @@ try_again: err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180, ocr_card); if (err == -EAGAIN) { - sdio_reset(host); - mmc_go_idle(host); - mmc_send_if_cond(host, host->ocr_avail); - mmc_remove_card(card); + mmc_sdio_resend_if_cond(host, card); retries--; goto try_again; } else if (err) { From 5fc3d80ef496c3bc3e8c09f056e3586fb681de56 Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Mon, 9 Jan 2017 16:56:20 +0800 Subject: [PATCH 045/145] mmc: sdio: don't use rocr to check if the card could support UHS mode Per SDIO Simplified Specification V3, section 3.1.2, A host that supports UHS-I sets S18R to 1 in the argument of CMD5 to request a change of the signal voltage to 1.8V. If the card supports UHS-I and the current signal voltage is 3.3V, S18A is set to 1 in the R4 response. If the signal voltage is already 1.8V, the card sets S18A to 0 so that host maintains the current signal voltage. UHS-I is supported in SD mode and S18A is always 0 in SPI mode. For the current code, if the signaling voltage is fixed 1.8v, so the card will set S18A to 0 for rocr and thus we would clear the R4_18V_PRESENT from ocr, which make core won't try to use uhs mode. To fix it, we expect sdio_read_cccr would fail if the uhs mode won't work at all. Note that it's interesting that some sdio cards still response S18A even the voltage is fixed to 1.8v and the CMD11 will also accepted and finish enabling UHS mode successfully. I guess this is why folks didn't notice this problem. Anyway, fix it. Signed-off-by: Shawn Lin Signed-off-by: Ulf Hansson --- drivers/mmc/core/sdio.c | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index f417adc9feb1..6810b3a8e130 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -633,7 +633,11 @@ try_again: * to switch to 1.8V signaling level. No 1.8v signalling if * UHS mode is not enabled to maintain compatibility and some * systems that claim 1.8v signalling in fact do not support - * it. + * it. Per SDIO spec v3, section 3.1.2, if the voltage is already + * 1.8v, the card sets S18A to 0 in the R4 response. So it will + * fails to check rocr & R4_18V_PRESENT, but we still need to + * try to init uhs card. sdio_read_cccr will take over this task + * to make sure which speed mode should work. */ if (!powered_resume && (rocr & ocr & R4_18V_PRESENT)) { err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180, @@ -645,9 +649,6 @@ try_again: } else if (err) { ocr &= ~R4_18V_PRESENT; } - err = 0; - } else { - ocr &= ~R4_18V_PRESENT; } /* @@ -704,11 +705,20 @@ try_again: } /* - * Read the common registers. + * Read the common registers. Note that we should try to + * validate whether UHS would work or not. */ err = sdio_read_cccr(card, ocr); - if (err) - goto remove; + if (err) { + mmc_sdio_resend_if_cond(host, card); + if (ocr & R4_18V_PRESENT) { + /* Retry init sequence, but without R4_18V_PRESENT. */ + retries = 0; + goto try_again; + } else { + goto remove; + } + } /* * Read the common CIS tuples. From dc0f585e839a857efd86968bfe65a905753182da Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Wed, 11 Jan 2017 12:14:49 +0800 Subject: [PATCH 046/145] mmc: vub300: Remove bogus check of irqs_queued It's unnecessary to check the irqs_queued value as it always needs to queue one if irq isn't enabled. Signed-off-by: Shawn Lin Signed-off-by: Ulf Hansson --- drivers/mmc/host/vub300.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/mmc/host/vub300.c b/drivers/mmc/host/vub300.c index bb3e0d1dd355..21ea776c6e07 100644 --- a/drivers/mmc/host/vub300.c +++ b/drivers/mmc/host/vub300.c @@ -640,8 +640,6 @@ static void __vub300_irqpoll_response(struct vub300_mmc_host *vub300) mutex_lock(&vub300->irq_mutex); if (vub300->irq_enabled) mmc_signal_sdio_irq(vub300->mmc); - else if (vub300->irqs_queued) - vub300->irqs_queued += 1; else vub300->irqs_queued += 1; vub300->irq_disabled = 0; From 8336bf68b57e1e736be8d4ef1f46a789fe7b9bde Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Wed, 11 Jan 2017 12:28:15 +0100 Subject: [PATCH 047/145] mmc: mxcmmc: Include interrupt.h in the platform data header The mxcmmc platform data header depends on interrupt.h. Don't rely on the public mmc header host.h to include it, bud instead make that dependency explicit. Signed-off-by: Ulf Hansson --- include/linux/platform_data/mmc-mxcmmc.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/linux/platform_data/mmc-mxcmmc.h b/include/linux/platform_data/mmc-mxcmmc.h index 29115f405af9..b0fdaa9bd185 100644 --- a/include/linux/platform_data/mmc-mxcmmc.h +++ b/include/linux/platform_data/mmc-mxcmmc.h @@ -1,6 +1,7 @@ #ifndef ASMARM_ARCH_MMC_H #define ASMARM_ARCH_MMC_H +#include #include struct device; From c31165d7400bb1ec12291170c9c4d072d5b0ba45 Mon Sep 17 00:00:00 2001 From: Shyam Sundar S K Date: Thu, 12 Jan 2017 18:09:00 +0530 Subject: [PATCH 048/145] mmc: sdhci-pci: Add support for HS200 tuning mode on AMD, eMMC-4.5.1 This patch adds support for HS200 tuning mode on AMD eMMC-4.5.1 Reviewed-by: Sen, Pankaj Reviewed-by: Shah, Nehal-bakulchandra Reviewed-by: Agrawal, Nitesh-kumar Signed-off-by: S-k, Shyam-sundar Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-pci-core.c | 94 ++++++++++++++++++++++++++++++- 1 file changed, 91 insertions(+), 3 deletions(-) diff --git a/drivers/mmc/host/sdhci-pci-core.c b/drivers/mmc/host/sdhci-pci-core.c index 5c275b7d0d53..982b3e349426 100644 --- a/drivers/mmc/host/sdhci-pci-core.c +++ b/drivers/mmc/host/sdhci-pci-core.c @@ -865,6 +865,86 @@ enum amd_chipset_gen { AMD_CHIPSET_UNKNOWN, }; +/* AMD registers */ +#define AMD_SD_AUTO_PATTERN 0xB8 +#define AMD_MSLEEP_DURATION 4 +#define AMD_SD_MISC_CONTROL 0xD0 +#define AMD_MAX_TUNE_VALUE 0x0B +#define AMD_AUTO_TUNE_SEL 0x10800 +#define AMD_FIFO_PTR 0x30 +#define AMD_BIT_MASK 0x1F + +static void amd_tuning_reset(struct sdhci_host *host) +{ + unsigned int val; + + val = sdhci_readw(host, SDHCI_HOST_CONTROL2); + val |= SDHCI_CTRL_PRESET_VAL_ENABLE | SDHCI_CTRL_EXEC_TUNING; + sdhci_writew(host, val, SDHCI_HOST_CONTROL2); + + val = sdhci_readw(host, SDHCI_HOST_CONTROL2); + val &= ~SDHCI_CTRL_EXEC_TUNING; + sdhci_writew(host, val, SDHCI_HOST_CONTROL2); +} + +static void amd_config_tuning_phase(struct pci_dev *pdev, u8 phase) +{ + unsigned int val; + + pci_read_config_dword(pdev, AMD_SD_AUTO_PATTERN, &val); + val &= ~AMD_BIT_MASK; + val |= (AMD_AUTO_TUNE_SEL | (phase << 1)); + pci_write_config_dword(pdev, AMD_SD_AUTO_PATTERN, val); +} + +static void amd_enable_manual_tuning(struct pci_dev *pdev) +{ + unsigned int val; + + pci_read_config_dword(pdev, AMD_SD_MISC_CONTROL, &val); + val |= AMD_FIFO_PTR; + pci_write_config_dword(pdev, AMD_SD_MISC_CONTROL, val); +} + +static int amd_execute_tuning(struct sdhci_host *host, u32 opcode) +{ + struct sdhci_pci_slot *slot = sdhci_priv(host); + struct pci_dev *pdev = slot->chip->pdev; + u8 valid_win = 0; + u8 valid_win_max = 0; + u8 valid_win_end = 0; + u8 ctrl, tune_around; + + amd_tuning_reset(host); + + for (tune_around = 0; tune_around < 12; tune_around++) { + amd_config_tuning_phase(pdev, tune_around); + + if (mmc_send_tuning(host->mmc, opcode, NULL)) { + valid_win = 0; + msleep(AMD_MSLEEP_DURATION); + ctrl = SDHCI_RESET_CMD | SDHCI_RESET_DATA; + sdhci_writeb(host, ctrl, SDHCI_SOFTWARE_RESET); + } else if (++valid_win > valid_win_max) { + valid_win_max = valid_win; + valid_win_end = tune_around; + } + } + + if (!valid_win_max) { + dev_err(&pdev->dev, "no tuning point found\n"); + return -EIO; + } + + amd_config_tuning_phase(pdev, valid_win_end - valid_win_max / 2); + + amd_enable_manual_tuning(pdev); + + host->mmc->retune_period = 0; + + return 0; +} + static int amd_probe(struct sdhci_pci_chip *chip) { struct pci_dev *smbus_dev; @@ -887,16 +967,24 @@ static int amd_probe(struct sdhci_pci_chip *chip) } } - if ((gen == AMD_CHIPSET_BEFORE_ML) || (gen == AMD_CHIPSET_CZ)) { + if (gen == AMD_CHIPSET_BEFORE_ML || gen == AMD_CHIPSET_CZ) chip->quirks2 |= SDHCI_QUIRK2_CLEAR_TRANSFERMODE_REG_BEFORE_CMD; - chip->quirks2 |= SDHCI_QUIRK2_BROKEN_HS200; - } return 0; } +static const struct sdhci_ops amd_sdhci_pci_ops = { + .set_clock = sdhci_set_clock, + .enable_dma = sdhci_pci_enable_dma, + .set_bus_width = sdhci_pci_set_bus_width, + .reset = sdhci_reset, + .set_uhs_signaling = sdhci_set_uhs_signaling, + .platform_execute_tuning = amd_execute_tuning, +}; + static const struct sdhci_pci_fixes sdhci_amd = { .probe = amd_probe, + .ops = &amd_sdhci_pci_ops, }; static const struct pci_device_id pci_ids[] = { From e87d2db2a2b534dad7ac0000c597b561c160880d Mon Sep 17 00:00:00 2001 From: yangbo lu Date: Mon, 26 Dec 2016 17:46:30 +0800 Subject: [PATCH 049/145] mmc: sdhci-of-esdhc: avoid clock glitch when frequency is changing The eSDHC_PRSSTAT[SDSTB] bit indicates whether the internal card clock is stable. This bit is for the host driver to poll clock status when changing the clock frequency. It is recommended to clear eSDHC_SYSCTL[SDCLKEN] to remove glitch on the card clock when the frequency is changing. This patch is to disable SDCLKEN bit before changing frequency and enable it after SDSTB bit is set. Signed-off-by: Yangbo Lu Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-esdhc.h | 5 +++++ drivers/mmc/host/sdhci-of-esdhc.c | 21 ++++++++++++++++++--- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/drivers/mmc/host/sdhci-esdhc.h b/drivers/mmc/host/sdhci-esdhc.h index 8cd8449c7bc5..ece8b37e51dd 100644 --- a/drivers/mmc/host/sdhci-esdhc.h +++ b/drivers/mmc/host/sdhci-esdhc.h @@ -31,6 +31,10 @@ * eSDHC register definition */ +/* Present State Register */ +#define ESDHC_PRSSTAT 0x24 +#define ESDHC_CLOCK_STABLE 0x00000008 + /* Protocol Control Register */ #define ESDHC_PROCTL 0x28 #define ESDHC_CTRL_4BITBUS (0x1 << 1) @@ -43,6 +47,7 @@ #define ESDHC_CLOCK_MASK 0x0000fff0 #define ESDHC_PREDIV_SHIFT 8 #define ESDHC_DIVIDER_SHIFT 4 +#define ESDHC_CLOCK_SDCLKEN 0x00000008 #define ESDHC_CLOCK_PEREN 0x00000004 #define ESDHC_CLOCK_HCKEN 0x00000002 #define ESDHC_CLOCK_IPGEN 0x00000001 diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c index 364f6b87a728..d3aa67142839 100644 --- a/drivers/mmc/host/sdhci-of-esdhc.c +++ b/drivers/mmc/host/sdhci-of-esdhc.c @@ -431,6 +431,7 @@ static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock) struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host); int pre_div = 1; int div = 1; + u32 timeout; u32 temp; host->mmc->actual_clock = 0; @@ -451,8 +452,8 @@ static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock) } temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL); - temp &= ~(ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN - | ESDHC_CLOCK_MASK); + temp &= ~(ESDHC_CLOCK_SDCLKEN | ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | + ESDHC_CLOCK_PEREN | ESDHC_CLOCK_MASK); sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL); while (host->max_clk / pre_div / 16 > clock && pre_div < 256) @@ -472,7 +473,21 @@ static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock) | (div << ESDHC_DIVIDER_SHIFT) | (pre_div << ESDHC_PREDIV_SHIFT)); sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL); - mdelay(1); + + /* Wait max 20 ms */ + timeout = 20; + while (!(sdhci_readl(host, ESDHC_PRSSTAT) & ESDHC_CLOCK_STABLE)) { + if (timeout == 0) { + pr_err("%s: Internal clock never stabilised.\n", + mmc_hostname(host->mmc)); + return; + } + timeout--; + mdelay(1); + } + + temp |= ESDHC_CLOCK_SDCLKEN; + sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL); } static void esdhc_pltfm_set_bus_width(struct sdhci_host *host, int width) From efd7be7bfc8eb8942ba3dc319f323cfd0eda99e2 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Tue, 10 Jan 2017 16:10:52 +0100 Subject: [PATCH 050/145] mmc: tmio: Remove redundant check of mmc->slot.cd_irq To validate whether native hotplug needs to be used, the tmio driver checks whether the mmc->slot.cd_irq has been successfully assigned. This check is redundant at its current place in tmio_mmc_host_probe(), as the mmc core assigns mmc->slot.cd_irq a valid value first when mmc_gpiod_request_cd_irq() is called. Therefore, let's just remove the check for now, as that also removes a layering violation of the tmio driver accessing core specific data via ->slot.cd_irq. Signed-off-by: Ulf Hansson Reviewed-by: Wolfram Sang --- drivers/mmc/host/tmio_mmc_pio.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c index b11b088775a8..908186adf52d 100644 --- a/drivers/mmc/host/tmio_mmc_pio.c +++ b/drivers/mmc/host/tmio_mmc_pio.c @@ -1175,8 +1175,7 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host, _host->native_hotplug = !(pdata->flags & TMIO_MMC_USE_GPIO_CD || mmc->caps & MMC_CAP_NEEDS_POLL || - !mmc_card_is_removable(mmc) || - mmc->slot.cd_irq >= 0); + !mmc_card_is_removable(mmc)); /* * On Gen2+, eMMC with NONREMOVABLE currently fails because native From bdf631082f7fd644bc9cf709692d285e1acf3c59 Mon Sep 17 00:00:00 2001 From: Masanari Iida Date: Fri, 6 Jan 2017 23:50:43 +0900 Subject: [PATCH 051/145] mmc: dt-bindings: Fix typo in mmc This patch fix some spelling typo found in devicetree/bindings/mmc. Signed-off-by: Masanari Iida Signed-off-by: Ulf Hansson --- Documentation/devicetree/bindings/mmc/amlogic,meson-gx.txt | 2 +- Documentation/devicetree/bindings/mmc/sdhci-st.txt | 2 +- Documentation/devicetree/bindings/mmc/sdhci.txt | 2 +- Documentation/devicetree/bindings/mmc/synopsys-dw-mshc.txt | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Documentation/devicetree/bindings/mmc/amlogic,meson-gx.txt b/Documentation/devicetree/bindings/mmc/amlogic,meson-gx.txt index 7f95ec400863..50bf611a4d2c 100644 --- a/Documentation/devicetree/bindings/mmc/amlogic,meson-gx.txt +++ b/Documentation/devicetree/bindings/mmc/amlogic,meson-gx.txt @@ -17,7 +17,7 @@ Required properties: "core" - Main peripheral bus clock "clkin0" - Parent clock of internal mux "clkin1" - Other parent clock of internal mux - The driver has an interal mux clock which switches between clkin0 and clkin1 depending on the + The driver has an internal mux clock which switches between clkin0 and clkin1 depending on the clock rate requested by the MMC core. Example: diff --git a/Documentation/devicetree/bindings/mmc/sdhci-st.txt b/Documentation/devicetree/bindings/mmc/sdhci-st.txt index 3cd4c43a3260..230fd696eb92 100644 --- a/Documentation/devicetree/bindings/mmc/sdhci-st.txt +++ b/Documentation/devicetree/bindings/mmc/sdhci-st.txt @@ -38,7 +38,7 @@ Optional properties: - bus-width: Number of data lines. See: Documentation/devicetree/bindings/mmc/mmc.txt. -- max-frequency: Can be 200MHz, 100Mz or 50MHz (default) and used for +- max-frequency: Can be 200MHz, 100MHz or 50MHz (default) and used for configuring the CCONFIG3 in the mmcss. See: Documentation/devicetree/bindings/mmc/mmc.txt. diff --git a/Documentation/devicetree/bindings/mmc/sdhci.txt b/Documentation/devicetree/bindings/mmc/sdhci.txt index 1c95a1a555c3..0e9923a64024 100644 --- a/Documentation/devicetree/bindings/mmc/sdhci.txt +++ b/Documentation/devicetree/bindings/mmc/sdhci.txt @@ -5,7 +5,7 @@ host controllers refer to the mmc[1] bindings. Optional properties: - sdhci-caps-mask: The sdhci capabilities register is incorrect. This 64bit - property corresponds to the bits in the sdhci capabilty register. If the bit + property corresponds to the bits in the sdhci capability register. If the bit is on in the mask then the bit is incorrect in the register and should be turned off, before applying sdhci-caps. - sdhci-caps: The sdhci capabilities register is incorrect. This 64bit diff --git a/Documentation/devicetree/bindings/mmc/synopsys-dw-mshc.txt b/Documentation/devicetree/bindings/mmc/synopsys-dw-mshc.txt index bca30b69b8a1..9cb55ca57461 100644 --- a/Documentation/devicetree/bindings/mmc/synopsys-dw-mshc.txt +++ b/Documentation/devicetree/bindings/mmc/synopsys-dw-mshc.txt @@ -16,7 +16,7 @@ Required Properties: each child-node representing a supported slot. There should be atleast one child node representing a card slot. The name of the child node representing the slot is recommended to be slot@n where n is the unique number of the slot - connnected to the controller. The following are optional properties which + connected to the controller. The following are optional properties which can be included in the slot child node. * reg: specifies the physical slot number. The valid values of this From 40d727a2defa176b78159d445bcf7afcc2ed9021 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Fri, 13 Jan 2017 14:14:02 +0100 Subject: [PATCH 052/145] ARM: pxa: Don't rely on public mmc header to include leds.h Some of the pxa platforms, balloon3, colibri-pxa270-income, corgi, trizeps4, vpac270, zeus and zylonite depends on leds.h. Explicitly include it instead of relying on the public mmc header host.h. Cc: Daniel Mack Cc: Haojian Zhuang Cc: Robert Jarzmik Cc: Signed-off-by: Ulf Hansson Acked-by: Robert Jarzmik --- arch/arm/mach-pxa/balloon3.c | 1 + arch/arm/mach-pxa/colibri-pxa270-income.c | 1 + arch/arm/mach-pxa/corgi.c | 1 + arch/arm/mach-pxa/trizeps4.c | 1 + arch/arm/mach-pxa/vpac270.c | 1 + arch/arm/mach-pxa/zeus.c | 1 + arch/arm/mach-pxa/zylonite.c | 1 + 7 files changed, 7 insertions(+) diff --git a/arch/arm/mach-pxa/balloon3.c b/arch/arm/mach-pxa/balloon3.c index 8a3c409294bf..d452a49c0396 100644 --- a/arch/arm/mach-pxa/balloon3.c +++ b/arch/arm/mach-pxa/balloon3.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include diff --git a/arch/arm/mach-pxa/colibri-pxa270-income.c b/arch/arm/mach-pxa/colibri-pxa270-income.c index 8cff770e6a00..d7cf47d03618 100644 --- a/arch/arm/mach-pxa/colibri-pxa270-income.c +++ b/arch/arm/mach-pxa/colibri-pxa270-income.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include diff --git a/arch/arm/mach-pxa/corgi.c b/arch/arm/mach-pxa/corgi.c index 183cd3446f25..7270f0db3432 100644 --- a/arch/arm/mach-pxa/corgi.c +++ b/arch/arm/mach-pxa/corgi.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include diff --git a/arch/arm/mach-pxa/trizeps4.c b/arch/arm/mach-pxa/trizeps4.c index ea78bc5c4198..3dd13b44c311 100644 --- a/arch/arm/mach-pxa/trizeps4.c +++ b/arch/arm/mach-pxa/trizeps4.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include diff --git a/arch/arm/mach-pxa/vpac270.c b/arch/arm/mach-pxa/vpac270.c index c006ee902a8f..70ab3ad28237 100644 --- a/arch/arm/mach-pxa/vpac270.c +++ b/arch/arm/mach-pxa/vpac270.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include diff --git a/arch/arm/mach-pxa/zeus.c b/arch/arm/mach-pxa/zeus.c index 3b94ecfb9426..ecbcaee5a2d5 100644 --- a/arch/arm/mach-pxa/zeus.c +++ b/arch/arm/mach-pxa/zeus.c @@ -13,6 +13,7 @@ #include #include +#include #include #include #include diff --git a/arch/arm/mach-pxa/zylonite.c b/arch/arm/mach-pxa/zylonite.c index 3642389b301a..4268552d600d 100644 --- a/arch/arm/mach-pxa/zylonite.c +++ b/arch/arm/mach-pxa/zylonite.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include From f46f335cb4253972cc45ce886bc57bfa8c3654a2 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Fri, 13 Jan 2017 14:14:03 +0100 Subject: [PATCH 053/145] ARM: davinci: Don't rely on public mmc header to include leds.h Some of the davinci boards, da850-evm, dm644x-evm and neuros-osd2 depends on leds.h. Explicitly include it instead of relying on the public mmc header host.h. Cc: Sekhar Nori Cc: Kevin Hilman Cc: Signed-off-by: Ulf Hansson Acked-by: Sekhar Nori --- arch/arm/mach-davinci/board-da850-evm.c | 1 + arch/arm/mach-davinci/board-dm644x-evm.c | 1 + arch/arm/mach-davinci/board-neuros-osd2.c | 1 + 3 files changed, 3 insertions(+) diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c index aac3ab1a044f..df3ca38778af 100644 --- a/arch/arm/mach-davinci/board-da850-evm.c +++ b/arch/arm/mach-davinci/board-da850-evm.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include diff --git a/arch/arm/mach-davinci/board-dm644x-evm.c b/arch/arm/mach-davinci/board-dm644x-evm.c index 521e40977265..023480b75244 100644 --- a/arch/arm/mach-davinci/board-dm644x-evm.c +++ b/arch/arm/mach-davinci/board-dm644x-evm.c @@ -25,6 +25,7 @@ #include #include #include +#include #include diff --git a/arch/arm/mach-davinci/board-neuros-osd2.c b/arch/arm/mach-davinci/board-neuros-osd2.c index ad10017203c1..0a7838852649 100644 --- a/arch/arm/mach-davinci/board-neuros-osd2.c +++ b/arch/arm/mach-davinci/board-neuros-osd2.c @@ -25,6 +25,7 @@ */ #include #include +#include #include #include #include From 981f18e646d31f4eb171850489079b110f9cdd4b Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Fri, 13 Jan 2017 14:14:04 +0100 Subject: [PATCH 054/145] ARM: davinci: Don't rely on public mmc header to include interrupt.h The davinci board omapl138-hawk, depends on interrupt.h. Explicitly include it instead of relying on the public mmc header host.h. Cc: Sekhar Nori Cc: Kevin Hilman Cc: Signed-off-by: Ulf Hansson Acked-by: Sekhar Nori --- arch/arm/mach-davinci/board-omapl138-hawk.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/mach-davinci/board-omapl138-hawk.c b/arch/arm/mach-davinci/board-omapl138-hawk.c index 41d5500996b2..a3e78074be70 100644 --- a/arch/arm/mach-davinci/board-omapl138-hawk.c +++ b/arch/arm/mach-davinci/board-omapl138-hawk.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include From d815cf8f33ef87bb2696febeb7b1592a77cf1514 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Fri, 13 Jan 2017 14:14:05 +0100 Subject: [PATCH 055/145] MIPS: Alchemy: Don't rely on public mmc header to include interrupt.h The MIPS Alchemy db1300 dev board depends on interrupt.h. Explicitly include it instead of relying on the public mmc header host.h. Cc: Ralf Baechle Cc: Signed-off-by: Ulf Hansson Acked-by: Ralf Baechle --- arch/mips/alchemy/devboards/db1300.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/mips/alchemy/devboards/db1300.c b/arch/mips/alchemy/devboards/db1300.c index d3c087f59f1a..a5504f57cb00 100644 --- a/arch/mips/alchemy/devboards/db1300.c +++ b/arch/mips/alchemy/devboards/db1300.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include From e1c6ec26b853e9062f0b3daaf695c546d0702953 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 20 Jan 2017 21:08:12 +0100 Subject: [PATCH 056/145] mmc: s3cmci: include linux/interrupt.h for tasklet_struct I got this new build error on today's linux-next drivers/mmc/host/s3cmci.h:69:24: error: field 'pio_tasklet' has incomplete type struct tasklet_struct pio_tasklet; drivers/mmc/host/s3cmci.c: In function 's3cmci_enable_irq': drivers/mmc/host/s3cmci.c:390:4: error: implicit declaration of function 'enable_irq';did you mean 'enable_imask'? [-Werror=implicit-function-declaration] While I haven't found out why this happened now and not earlier, the solution is obvious, we should include the header that defines the structure. Signed-off-by: Arnd Bergmann Signed-off-by: Ulf Hansson --- drivers/mmc/host/s3cmci.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mmc/host/s3cmci.c b/drivers/mmc/host/s3cmci.c index 932a4b1fed33..7a173f8c455b 100644 --- a/drivers/mmc/host/s3cmci.c +++ b/drivers/mmc/host/s3cmci.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include From 8da007348bf52a91e5137d27d7dcd528edbb80ce Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Fri, 13 Jan 2017 14:14:06 +0100 Subject: [PATCH 057/145] mmc: core: First step in cleaning up public mmc header files This is the first step in cleaning up the public mmc header files. In this change we makes sure each header file builds standalone, as that helps to resolve dependencies. While changing this, it also seems reasonable to stop including other headers from inside a header itself which it don't depend upon. Additionally, in some cases such dependencies are better resolved by forward declaring the needed struct. Signed-off-by: Ulf Hansson Reviewed-by: Shawn Lin --- include/linux/mmc/card.h | 2 -- include/linux/mmc/core.h | 3 +-- include/linux/mmc/host.h | 9 ++------- include/linux/mmc/mmc.h | 2 ++ include/linux/mmc/slot-gpio.h | 3 +++ 5 files changed, 8 insertions(+), 11 deletions(-) diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h index 00449e51838a..ca64f5b67983 100644 --- a/include/linux/mmc/card.h +++ b/include/linux/mmc/card.h @@ -11,7 +11,6 @@ #define LINUX_MMC_CARD_H #include -#include #include struct mmc_cid { @@ -206,7 +205,6 @@ struct sdio_cis { }; struct mmc_host; -struct mmc_ios; struct sdio_func; struct sdio_func_tuple; diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h index e33cc748dcfe..64e2ddf33f38 100644 --- a/include/linux/mmc/core.h +++ b/include/linux/mmc/core.h @@ -8,10 +8,9 @@ #ifndef LINUX_MMC_CORE_H #define LINUX_MMC_CORE_H -#include #include +#include -struct request; struct mmc_data; struct mmc_request; diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index 8bc884121465..8d38c76b06d6 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -10,16 +10,12 @@ #ifndef LINUX_MMC_HOST_H #define LINUX_MMC_HOST_H -#include -#include -#include #include #include #include #include #include -#include #include struct mmc_ios { @@ -82,6 +78,8 @@ struct mmc_ios { bool enhanced_strobe; /* hs400es selection */ }; +struct mmc_host; + struct mmc_host_ops { /* * It is optional for the host to implement pre_req and post_req in @@ -162,9 +160,6 @@ struct mmc_host_ops { unsigned int direction, int blk_size); }; -struct mmc_card; -struct device; - struct mmc_async_req { /* active mmc request */ struct mmc_request *mrq; diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h index a0740829ff00..261772e3effe 100644 --- a/include/linux/mmc/mmc.h +++ b/include/linux/mmc/mmc.h @@ -24,6 +24,8 @@ #ifndef LINUX_MMC_MMC_H #define LINUX_MMC_MMC_H +#include + /* Standard MMC commands (4.1) type argument response */ /* class 1 */ #define MMC_GO_IDLE_STATE 0 /* bc */ diff --git a/include/linux/mmc/slot-gpio.h b/include/linux/mmc/slot-gpio.h index a7972cd3bc14..82f0d289f110 100644 --- a/include/linux/mmc/slot-gpio.h +++ b/include/linux/mmc/slot-gpio.h @@ -11,6 +11,9 @@ #ifndef MMC_SLOT_GPIO_H #define MMC_SLOT_GPIO_H +#include +#include + struct mmc_host; int mmc_gpio_get_ro(struct mmc_host *host); From 066185d690631478b16045d152b163a51a5e4847 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Fri, 13 Jan 2017 14:14:07 +0100 Subject: [PATCH 058/145] mmc: core: First step in cleaning up private mmc header files This is the first step in cleaning up the private mmc header files. In this change we makes sure each header file builds standalone, as that helps to resolve dependencies. While changing this, it also seems reasonable to stop including other headers from inside a header itself which it don't depend upon. Additionally, in some cases such dependencies are better resolved by forward declaring the needed struct. Signed-off-by: Ulf Hansson Reviewed-by: Shawn Lin --- drivers/mmc/core/block.h | 8 ++++++++ drivers/mmc/core/bus.h | 4 ++++ drivers/mmc/core/core.h | 4 ++++ drivers/mmc/core/host.h | 3 ++- drivers/mmc/core/mmc_ops.h | 5 +++++ drivers/mmc/core/pwrseq.h | 6 +++++- drivers/mmc/core/queue.h | 6 +++++- drivers/mmc/core/sd.h | 5 ++++- drivers/mmc/core/sd_ops.h | 5 +++++ drivers/mmc/core/sdio_bus.h | 3 +++ drivers/mmc/core/sdio_cis.h | 3 +++ drivers/mmc/core/sdio_ops.h | 4 ++++ drivers/mmc/core/slot-gpio.h | 2 ++ 13 files changed, 54 insertions(+), 4 deletions(-) diff --git a/drivers/mmc/core/block.h b/drivers/mmc/core/block.h index cdabb2ee74be..00b7483f2d6e 100644 --- a/drivers/mmc/core/block.h +++ b/drivers/mmc/core/block.h @@ -1 +1,9 @@ +#ifndef _MMC_CORE_BLOCK_H +#define _MMC_CORE_BLOCK_H + +struct mmc_queue; +struct request; + int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req); + +#endif diff --git a/drivers/mmc/core/bus.h b/drivers/mmc/core/bus.h index 00a19710b6b4..93b516ab6e88 100644 --- a/drivers/mmc/core/bus.h +++ b/drivers/mmc/core/bus.h @@ -11,6 +11,10 @@ #ifndef _MMC_CORE_BUS_H #define _MMC_CORE_BUS_H +struct mmc_host; +struct mmc_card; +struct device_type; + #define MMC_DEV_ATTR(name, fmt, args...) \ static ssize_t mmc_##name##_show (struct device *dev, struct device_attribute *attr, char *buf) \ { \ diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h index 0fa86a2afc26..29b91aea7878 100644 --- a/drivers/mmc/core/core.h +++ b/drivers/mmc/core/core.h @@ -12,6 +12,10 @@ #define _MMC_CORE_CORE_H #include +#include + +struct mmc_host; +struct mmc_card; #define MMC_CMD_RETRIES 3 diff --git a/drivers/mmc/core/host.h b/drivers/mmc/core/host.h index 992bf5397633..366ce79c3498 100644 --- a/drivers/mmc/core/host.h +++ b/drivers/mmc/core/host.h @@ -10,7 +10,8 @@ */ #ifndef _MMC_CORE_HOST_H #define _MMC_CORE_HOST_H -#include + +struct mmc_host; int mmc_register_host_class(void); void mmc_unregister_host_class(void); diff --git a/drivers/mmc/core/mmc_ops.h b/drivers/mmc/core/mmc_ops.h index abd525ed74be..e76365aa9587 100644 --- a/drivers/mmc/core/mmc_ops.h +++ b/drivers/mmc/core/mmc_ops.h @@ -12,6 +12,11 @@ #ifndef _MMC_MMC_OPS_H #define _MMC_MMC_OPS_H +#include + +struct mmc_host; +struct mmc_card; + int mmc_select_card(struct mmc_card *card); int mmc_deselect_cards(struct mmc_host *host); int mmc_set_dsr(struct mmc_host *host); diff --git a/drivers/mmc/core/pwrseq.h b/drivers/mmc/core/pwrseq.h index d69e751f148b..39c911aa6ebb 100644 --- a/drivers/mmc/core/pwrseq.h +++ b/drivers/mmc/core/pwrseq.h @@ -8,7 +8,11 @@ #ifndef _MMC_CORE_PWRSEQ_H #define _MMC_CORE_PWRSEQ_H -#include +#include + +struct mmc_host; +struct device; +struct module; struct mmc_pwrseq_ops { void (*pre_power_on)(struct mmc_host *host); diff --git a/drivers/mmc/core/queue.h b/drivers/mmc/core/queue.h index dac8c3d010dd..0cea02af79d1 100644 --- a/drivers/mmc/core/queue.h +++ b/drivers/mmc/core/queue.h @@ -1,6 +1,11 @@ #ifndef MMC_QUEUE_H #define MMC_QUEUE_H +#include +#include +#include +#include + static inline bool mmc_req_is_special(struct request *req) { return req && @@ -9,7 +14,6 @@ static inline bool mmc_req_is_special(struct request *req) req_op(req) == REQ_OP_SECURE_ERASE); } -struct request; struct task_struct; struct mmc_blk_data; diff --git a/drivers/mmc/core/sd.h b/drivers/mmc/core/sd.h index aab824a9a7f3..1ada9808c329 100644 --- a/drivers/mmc/core/sd.h +++ b/drivers/mmc/core/sd.h @@ -1,10 +1,13 @@ #ifndef _MMC_CORE_SD_H #define _MMC_CORE_SD_H -#include +#include extern struct device_type sd_type; +struct mmc_host; +struct mmc_card; + int mmc_sd_get_cid(struct mmc_host *host, u32 ocr, u32 *cid, u32 *rocr); int mmc_sd_get_csd(struct mmc_host *host, struct mmc_card *card); void mmc_decode_cid(struct mmc_card *card); diff --git a/drivers/mmc/core/sd_ops.h b/drivers/mmc/core/sd_ops.h index ffc2305d905f..ac7223cf33e3 100644 --- a/drivers/mmc/core/sd_ops.h +++ b/drivers/mmc/core/sd_ops.h @@ -12,6 +12,11 @@ #ifndef _MMC_SD_OPS_H #define _MMC_SD_OPS_H +#include + +struct mmc_card; +struct mmc_host; + int mmc_app_set_bus_width(struct mmc_card *card, int width); int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr); int mmc_send_if_cond(struct mmc_host *host, u32 ocr); diff --git a/drivers/mmc/core/sdio_bus.h b/drivers/mmc/core/sdio_bus.h index 567a76821ba7..b69a2540a076 100644 --- a/drivers/mmc/core/sdio_bus.h +++ b/drivers/mmc/core/sdio_bus.h @@ -11,6 +11,9 @@ #ifndef _MMC_CORE_SDIO_BUS_H #define _MMC_CORE_SDIO_BUS_H +struct mmc_card; +struct sdio_func; + struct sdio_func *sdio_alloc_func(struct mmc_card *card); int sdio_add_func(struct sdio_func *func); void sdio_remove_func(struct sdio_func *func); diff --git a/drivers/mmc/core/sdio_cis.h b/drivers/mmc/core/sdio_cis.h index 4d903c2e425e..16aa563faa00 100644 --- a/drivers/mmc/core/sdio_cis.h +++ b/drivers/mmc/core/sdio_cis.h @@ -14,6 +14,9 @@ #ifndef _MMC_SDIO_CIS_H #define _MMC_SDIO_CIS_H +struct mmc_card; +struct sdio_func; + int sdio_read_common_cis(struct mmc_card *card); void sdio_free_common_cis(struct mmc_card *card); diff --git a/drivers/mmc/core/sdio_ops.h b/drivers/mmc/core/sdio_ops.h index 5660c7f459e9..e1c36d64572c 100644 --- a/drivers/mmc/core/sdio_ops.h +++ b/drivers/mmc/core/sdio_ops.h @@ -12,8 +12,12 @@ #ifndef _MMC_SDIO_OPS_H #define _MMC_SDIO_OPS_H +#include #include +struct mmc_host; +struct mmc_card; + 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, unsigned addr, u8 in, u8* out); diff --git a/drivers/mmc/core/slot-gpio.h b/drivers/mmc/core/slot-gpio.h index 8c1854dc5d58..a06fd843f025 100644 --- a/drivers/mmc/core/slot-gpio.h +++ b/drivers/mmc/core/slot-gpio.h @@ -8,6 +8,8 @@ #ifndef _MMC_CORE_SLOTGPIO_H #define _MMC_CORE_SLOTGPIO_H +struct mmc_host; + int mmc_gpio_alloc(struct mmc_host *host); #endif From 55244c5659b5e73a969b285a2e763223d8aab979 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Fri, 13 Jan 2017 14:14:08 +0100 Subject: [PATCH 059/145] mmc: core: Move public functions from core.h to private headers A significant amount of functions are available through the public mmc core.h header file. Let's slim down this public mmc interface, as to prevent users from abusing it, by moving some of the functions to private mmc header files. This change concentrates on moving the functions into private mmc headers, following changes may continue with additional clean-ups, as an example some functions can be turned into static. Signed-off-by: Ulf Hansson Reviewed-by: Linus Walleij Reviewed-by: Shawn Lin --- drivers/mmc/core/block.c | 3 +++ drivers/mmc/core/core.h | 37 ++++++++++++++++++++++++++- drivers/mmc/core/mmc_ops.h | 9 +++++++ drivers/mmc/core/mmc_test.c | 2 ++ drivers/mmc/core/queue.c | 1 + drivers/mmc/core/sd_ops.h | 4 +++ drivers/mmc/core/sdio_io.c | 1 + drivers/mmc/core/sdio_irq.c | 1 + drivers/mmc/core/sdio_ops.h | 1 + include/linux/mmc/core.h | 50 ------------------------------------- 10 files changed, 58 insertions(+), 51 deletions(-) diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index 6adc3ce28447..41b5dbcd5b5a 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -47,6 +47,9 @@ #include "queue.h" #include "block.h" +#include "core.h" +#include "mmc_ops.h" +#include "sd_ops.h" MODULE_ALIAS("mmc:block"); #ifdef MODULE_PARAM_PREFIX diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h index 29b91aea7878..8a95c82554be 100644 --- a/drivers/mmc/core/core.h +++ b/drivers/mmc/core/core.h @@ -16,6 +16,7 @@ struct mmc_host; struct mmc_card; +struct mmc_request; #define MMC_CMD_RETRIES 3 @@ -73,6 +74,7 @@ void mmc_start_host(struct mmc_host *host); void mmc_stop_host(struct mmc_host *host); int _mmc_detect_card_removed(struct mmc_host *host); +int mmc_detect_card_removed(struct mmc_host *host); int mmc_attach_mmc(struct mmc_host *host); int mmc_attach_sd(struct mmc_host *host); @@ -102,5 +104,38 @@ static inline void mmc_register_pm_notifier(struct mmc_host *host) { } static inline void mmc_unregister_pm_notifier(struct mmc_host *host) { } #endif -#endif +void mmc_wait_for_req_done(struct mmc_host *host, struct mmc_request *mrq); +bool mmc_is_req_done(struct mmc_host *host, struct mmc_request *mrq); +int mmc_erase(struct mmc_card *card, unsigned int from, unsigned int nr, + unsigned int arg); +int mmc_can_erase(struct mmc_card *card); +int mmc_can_trim(struct mmc_card *card); +int mmc_can_discard(struct mmc_card *card); +int mmc_can_sanitize(struct mmc_card *card); +int mmc_can_secure_erase_trim(struct mmc_card *card); +int mmc_erase_group_aligned(struct mmc_card *card, unsigned int from, + unsigned int nr); +unsigned int mmc_calc_max_discard(struct mmc_card *card); + +int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen); +int mmc_set_blockcount(struct mmc_card *card, unsigned int blockcount, + bool is_rel_write); + +int __mmc_claim_host(struct mmc_host *host, atomic_t *abort); +void mmc_release_host(struct mmc_host *host); +void mmc_get_card(struct mmc_card *card); +void mmc_put_card(struct mmc_card *card); + +/** + * mmc_claim_host - exclusively claim a host + * @host: mmc host to claim + * + * Claim a host for a set of operations. + */ +static inline void mmc_claim_host(struct mmc_host *host) +{ + __mmc_claim_host(host, NULL); +} + +#endif diff --git a/drivers/mmc/core/mmc_ops.h b/drivers/mmc/core/mmc_ops.h index e76365aa9587..74beea8a9c7e 100644 --- a/drivers/mmc/core/mmc_ops.h +++ b/drivers/mmc/core/mmc_ops.h @@ -31,12 +31,21 @@ int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp); int mmc_spi_set_crc(struct mmc_host *host, int use_crc); int mmc_bus_test(struct mmc_card *card, u8 bus_width); int mmc_send_hpi_cmd(struct mmc_card *card, u32 *status); +int mmc_interrupt_hpi(struct mmc_card *card); int mmc_can_ext_csd(struct mmc_card *card); +int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd); int mmc_switch_status(struct mmc_card *card); int __mmc_switch_status(struct mmc_card *card, bool crc_err_fatal); int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value, unsigned int timeout_ms, unsigned char timing, bool use_busy_signal, bool send_status, bool retry_crc_err); +int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value, + unsigned int timeout_ms); +int mmc_stop_bkops(struct mmc_card *card); +int mmc_read_bkops_status(struct mmc_card *card); +void mmc_start_bkops(struct mmc_card *card, bool from_exception); +int mmc_can_reset(struct mmc_card *card); +int mmc_flush_cache(struct mmc_card *card); #endif diff --git a/drivers/mmc/core/mmc_test.c b/drivers/mmc/core/mmc_test.c index d350bd67b4f8..8075ad133b7d 100644 --- a/drivers/mmc/core/mmc_test.c +++ b/drivers/mmc/core/mmc_test.c @@ -22,6 +22,8 @@ #include #include +#include "core.h" + #define RESULT_OK 0 #define RESULT_FAIL 1 #define RESULT_UNSUP_HOST 2 diff --git a/drivers/mmc/core/queue.c b/drivers/mmc/core/queue.c index b1986622c60e..8f5bf5f82aa7 100644 --- a/drivers/mmc/core/queue.c +++ b/drivers/mmc/core/queue.c @@ -20,6 +20,7 @@ #include "queue.h" #include "block.h" +#include "core.h" #define MMC_QUEUE_BOUNCESZ 65536 diff --git a/drivers/mmc/core/sd_ops.h b/drivers/mmc/core/sd_ops.h index ac7223cf33e3..784f8e6b6baa 100644 --- a/drivers/mmc/core/sd_ops.h +++ b/drivers/mmc/core/sd_ops.h @@ -16,6 +16,7 @@ struct mmc_card; struct mmc_host; +struct mmc_command; int mmc_app_set_bus_width(struct mmc_card *card, int width); int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr); @@ -25,6 +26,9 @@ int mmc_app_send_scr(struct mmc_card *card, u32 *scr); int mmc_sd_switch(struct mmc_card *card, int mode, int group, u8 value, u8 *resp); int mmc_app_sd_status(struct mmc_card *card, void *ssr); +int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card); +int mmc_wait_for_app_cmd(struct mmc_host *host, struct mmc_card *card, + struct mmc_command *cmd, int retries); #endif diff --git a/drivers/mmc/core/sdio_io.c b/drivers/mmc/core/sdio_io.c index 406e5f037e32..76fe6d599b77 100644 --- a/drivers/mmc/core/sdio_io.c +++ b/drivers/mmc/core/sdio_io.c @@ -16,6 +16,7 @@ #include #include "sdio_ops.h" +#include "core.h" /** * sdio_claim_host - exclusively claim a bus for a certain SDIO function diff --git a/drivers/mmc/core/sdio_irq.c b/drivers/mmc/core/sdio_irq.c index f1faf9acc007..d0846350e2fe 100644 --- a/drivers/mmc/core/sdio_irq.c +++ b/drivers/mmc/core/sdio_irq.c @@ -27,6 +27,7 @@ #include #include "sdio_ops.h" +#include "core.h" static int process_sdio_pending_irqs(struct mmc_host *host) { diff --git a/drivers/mmc/core/sdio_ops.h b/drivers/mmc/core/sdio_ops.h index e1c36d64572c..bed8a8377fec 100644 --- a/drivers/mmc/core/sdio_ops.h +++ b/drivers/mmc/core/sdio_ops.h @@ -24,6 +24,7 @@ int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn, int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn, unsigned addr, int incr_addr, u8 *buf, unsigned blocks, unsigned blksz); int sdio_reset(struct mmc_host *host); +unsigned int mmc_align_data_size(struct mmc_card *card, unsigned int sz); static inline bool mmc_is_io_op(u32 opcode) { diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h index 64e2ddf33f38..e679a8678594 100644 --- a/include/linux/mmc/core.h +++ b/include/linux/mmc/core.h @@ -158,25 +158,13 @@ struct mmc_request { struct mmc_card; struct mmc_async_req; -extern int mmc_stop_bkops(struct mmc_card *); -extern int mmc_read_bkops_status(struct mmc_card *); extern struct mmc_async_req *mmc_start_req(struct mmc_host *, struct mmc_async_req *, enum mmc_blk_status *); -extern int mmc_interrupt_hpi(struct mmc_card *); extern void mmc_wait_for_req(struct mmc_host *, struct mmc_request *); -extern void mmc_wait_for_req_done(struct mmc_host *host, - struct mmc_request *mrq); -extern bool mmc_is_req_done(struct mmc_host *host, struct mmc_request *mrq); extern int mmc_wait_for_cmd(struct mmc_host *, struct mmc_command *, int); -extern int mmc_app_cmd(struct mmc_host *, struct mmc_card *); -extern int mmc_wait_for_app_cmd(struct mmc_host *, struct mmc_card *, - struct mmc_command *, int); -extern void mmc_start_bkops(struct mmc_card *card, bool from_exception); -extern int mmc_switch(struct mmc_card *, u8, u8, u8, unsigned int); extern int mmc_send_tuning(struct mmc_host *host, u32 opcode, int *cmd_error); extern int mmc_abort_tuning(struct mmc_host *host, u32 opcode); -extern int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd); #define MMC_ERASE_ARG 0x00000000 #define MMC_SECURE_ERASE_ARG 0x80000000 @@ -188,46 +176,8 @@ extern int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd); #define MMC_SECURE_ARGS 0x80000000 #define MMC_TRIM_ARGS 0x00008001 -extern int mmc_erase(struct mmc_card *card, unsigned int from, unsigned int nr, - unsigned int arg); -extern int mmc_can_erase(struct mmc_card *card); -extern int mmc_can_trim(struct mmc_card *card); -extern int mmc_can_discard(struct mmc_card *card); -extern int mmc_can_sanitize(struct mmc_card *card); -extern int mmc_can_secure_erase_trim(struct mmc_card *card); -extern int mmc_erase_group_aligned(struct mmc_card *card, unsigned int from, - unsigned int nr); -extern unsigned int mmc_calc_max_discard(struct mmc_card *card); - -extern int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen); -extern int mmc_set_blockcount(struct mmc_card *card, unsigned int blockcount, - bool is_rel_write); extern int mmc_hw_reset(struct mmc_host *host); -extern int mmc_can_reset(struct mmc_card *card); - extern void mmc_set_data_timeout(struct mmc_data *, const struct mmc_card *); -extern unsigned int mmc_align_data_size(struct mmc_card *, unsigned int); - -extern int __mmc_claim_host(struct mmc_host *host, atomic_t *abort); -extern void mmc_release_host(struct mmc_host *host); - -extern void mmc_get_card(struct mmc_card *card); -extern void mmc_put_card(struct mmc_card *card); - -extern int mmc_flush_cache(struct mmc_card *); - -extern int mmc_detect_card_removed(struct mmc_host *host); - -/** - * mmc_claim_host - exclusively claim a host - * @host: mmc host to claim - * - * Claim a host for a set of operations. - */ -static inline void mmc_claim_host(struct mmc_host *host) -{ - __mmc_claim_host(host, NULL); -} struct device_node; extern u32 mmc_vddrange_to_ocrmask(int vdd_min, int vdd_max); From 9e1bbc72727506c173cc6ed1d704cb2d7911d9d5 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Fri, 13 Jan 2017 14:14:09 +0100 Subject: [PATCH 060/145] mmc: core: Move some host specific public functions to host.h Ideally the public mmc header file, core.h, shouldn't contain interfaces particularly intended to be used by host drivers. Instead those should remain in the host.h header file. Therefore, let's move a couple functions from core.h to host.h. Signed-off-by: Ulf Hansson Reviewed-by: Linus Walleij Reviewed-by: Shawn Lin --- include/linux/mmc/core.h | 6 ------ include/linux/mmc/host.h | 6 ++++++ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h index e679a8678594..faacc90f8711 100644 --- a/include/linux/mmc/core.h +++ b/include/linux/mmc/core.h @@ -163,8 +163,6 @@ extern struct mmc_async_req *mmc_start_req(struct mmc_host *, enum mmc_blk_status *); extern void mmc_wait_for_req(struct mmc_host *, struct mmc_request *); extern int mmc_wait_for_cmd(struct mmc_host *, struct mmc_command *, int); -extern int mmc_send_tuning(struct mmc_host *host, u32 opcode, int *cmd_error); -extern int mmc_abort_tuning(struct mmc_host *host, u32 opcode); #define MMC_ERASE_ARG 0x00000000 #define MMC_SECURE_ERASE_ARG 0x80000000 @@ -179,8 +177,4 @@ extern int mmc_abort_tuning(struct mmc_host *host, u32 opcode); extern int mmc_hw_reset(struct mmc_host *host); extern void mmc_set_data_timeout(struct mmc_data *, const struct mmc_card *); -struct device_node; -extern u32 mmc_vddrange_to_ocrmask(int vdd_min, int vdd_max); -extern int mmc_of_parse_voltage(struct device_node *np, u32 *mask); - #endif /* LINUX_MMC_CORE_H */ diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index 8d38c76b06d6..7de05195bff6 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -392,11 +392,14 @@ struct mmc_host { unsigned long private[0] ____cacheline_aligned; }; +struct device_node; + struct mmc_host *mmc_alloc_host(int extra, struct device *); int mmc_add_host(struct mmc_host *); void mmc_remove_host(struct mmc_host *); void mmc_free_host(struct mmc_host *); int mmc_of_parse(struct mmc_host *host); +int mmc_of_parse_voltage(struct device_node *np, u32 *mask); static inline void *mmc_priv(struct mmc_host *host) { @@ -452,6 +455,7 @@ static inline int mmc_regulator_set_vqmmc(struct mmc_host *mmc, } #endif +u32 mmc_vddrange_to_ocrmask(int vdd_min, int vdd_max); int mmc_regulator_get_supply(struct mmc_host *mmc); static inline int mmc_card_is_removable(struct mmc_host *host) @@ -538,6 +542,8 @@ static inline bool mmc_can_retune(struct mmc_host *host) return host->can_retune == 1; } +int mmc_send_tuning(struct mmc_host *host, u32 opcode, int *cmd_error); +int mmc_abort_tuning(struct mmc_host *host, u32 opcode); void mmc_retune_pause(struct mmc_host *host); void mmc_retune_unpause(struct mmc_host *host); From c0a3e080f9294117a7d510a4f01a0b7c6dbcadae Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Fri, 13 Jan 2017 14:14:10 +0100 Subject: [PATCH 061/145] mmc: core: Move erase/trim/discard defines from public core.h to mmc.h As the public mmc.h header already contains similar defines for other mmc commands and arguments, let's move those for erase/trim/discard into here as well. Signed-off-by: Ulf Hansson Reviewed-by: Linus Walleij Reviewed-by: Shawn Lin --- include/linux/mmc/core.h | 10 ---------- include/linux/mmc/mmc.h | 13 ++++++++++++- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h index faacc90f8711..6440e10c86cd 100644 --- a/include/linux/mmc/core.h +++ b/include/linux/mmc/core.h @@ -164,16 +164,6 @@ extern struct mmc_async_req *mmc_start_req(struct mmc_host *, extern void mmc_wait_for_req(struct mmc_host *, struct mmc_request *); extern int mmc_wait_for_cmd(struct mmc_host *, struct mmc_command *, int); -#define MMC_ERASE_ARG 0x00000000 -#define MMC_SECURE_ERASE_ARG 0x80000000 -#define MMC_TRIM_ARG 0x00000001 -#define MMC_DISCARD_ARG 0x00000003 -#define MMC_SECURE_TRIM1_ARG 0x80000001 -#define MMC_SECURE_TRIM2_ARG 0x80008000 - -#define MMC_SECURE_ARGS 0x80000000 -#define MMC_TRIM_ARGS 0x00008001 - extern int mmc_hw_reset(struct mmc_host *host); extern void mmc_set_data_timeout(struct mmc_data *, const struct mmc_card *); diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h index 261772e3effe..8f7854324d2b 100644 --- a/include/linux/mmc/mmc.h +++ b/include/linux/mmc/mmc.h @@ -462,12 +462,23 @@ struct _mmc_csd { /* * MMC_SWITCH access modes */ - #define MMC_SWITCH_MODE_CMD_SET 0x00 /* Change the command set */ #define MMC_SWITCH_MODE_SET_BITS 0x01 /* Set bits which are 1 in value */ #define MMC_SWITCH_MODE_CLEAR_BITS 0x02 /* Clear bits which are 1 in value */ #define MMC_SWITCH_MODE_WRITE_BYTE 0x03 /* Set target to value */ +/* + * Erase/trim/discard + */ +#define MMC_ERASE_ARG 0x00000000 +#define MMC_SECURE_ERASE_ARG 0x80000000 +#define MMC_TRIM_ARG 0x00000001 +#define MMC_DISCARD_ARG 0x00000003 +#define MMC_SECURE_TRIM1_ARG 0x80000001 +#define MMC_SECURE_TRIM2_ARG 0x80008000 +#define MMC_SECURE_ARGS 0x80000000 +#define MMC_TRIM_ARGS 0x00008001 + #define mmc_driver_type_mask(n) (1 << (n)) #endif /* LINUX_MMC_MMC_H */ From 009b0fcea5dfe77663f7ec3927c7c50a97a7675c Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Fri, 13 Jan 2017 14:14:11 +0100 Subject: [PATCH 062/145] mmc: core: Remove unused struct _mmc_csd from public mmc.h header The struct _mmc_csd isn't being used and has been lurking around for a while. Let's kill it. Signed-off-by: Ulf Hansson Reviewed-by: Linus Walleij Reviewed-by: Shawn Lin --- include/linux/mmc/mmc.h | 44 ----------------------------------------- 1 file changed, 44 deletions(-) diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h index 8f7854324d2b..7406d9badda0 100644 --- a/include/linux/mmc/mmc.h +++ b/include/linux/mmc/mmc.h @@ -184,50 +184,6 @@ static inline bool mmc_op_multi(u32 opcode) #define R2_SPI_OUT_OF_RANGE (1 << 15) /* or CSD overwrite */ #define R2_SPI_CSD_OVERWRITE R2_SPI_OUT_OF_RANGE -/* These are unpacked versions of the actual responses */ - -struct _mmc_csd { - u8 csd_structure; - u8 spec_vers; - u8 taac; - u8 nsac; - u8 tran_speed; - u16 ccc; - u8 read_bl_len; - u8 read_bl_partial; - u8 write_blk_misalign; - u8 read_blk_misalign; - u8 dsr_imp; - u16 c_size; - u8 vdd_r_curr_min; - u8 vdd_r_curr_max; - u8 vdd_w_curr_min; - u8 vdd_w_curr_max; - u8 c_size_mult; - union { - struct { /* MMC system specification version 3.1 */ - u8 erase_grp_size; - u8 erase_grp_mult; - } v31; - struct { /* MMC system specification version 2.2 */ - u8 sector_size; - u8 erase_grp_size; - } v22; - } erase; - u8 wp_grp_size; - u8 wp_grp_enable; - u8 default_ecc; - u8 r2w_factor; - u8 write_bl_len; - u8 write_bl_partial; - u8 file_format_grp; - u8 copy; - u8 perm_write_protect; - u8 tmp_write_protect; - u8 file_format; - u8 ecc; -}; - /* * OCR bits are mostly in host.h */ From 136b0a471cd41b906dd4e00789cc998632a8cdd7 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Fri, 13 Jan 2017 14:14:12 +0100 Subject: [PATCH 063/145] mmc: omap: Don't use mmc_card_present() when validating for inserted card The mmc_card_present() function helps the mmc core to track an internal state of the card device. More importantly, it's not intended to be used by mmc host drivers to check for an inserted card. Therefore, let's stop using it and instead rely on checking for a valid pointer to a struct mmc_card, as it should be good enough. Cc: linux-omap@vger.kernel.org Cc: Tony Lindgren Cc: Jarkko Nikula Signed-off-by: Ulf Hansson Acked-by: Tony Lindgren Reviewed-by: Linus Walleij --- drivers/mmc/host/omap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c index be3c49fa7382..bd49f34d7654 100644 --- a/drivers/mmc/host/omap.c +++ b/drivers/mmc/host/omap.c @@ -893,7 +893,7 @@ static void mmc_omap_cover_handler(unsigned long param) * If no card is inserted, we postpone polling until * the cover has been closed. */ - if (slot->mmc->card == NULL || !mmc_card_present(slot->mmc->card)) + if (slot->mmc->card == NULL) return; mod_timer(&slot->cover_timer, From 2e4af7b6554a05406ac03f2792d0415c1ab9aeaa Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Fri, 13 Jan 2017 14:14:13 +0100 Subject: [PATCH 064/145] mmc: vub300: Don't use mmc_card_present() when validating for inserted card The mmc_card_present() function helps the mmc core to track an internal state of the card device. More importantly, it's not intended to be used by mmc host drivers to check for an inserted card. Therefore, let's stop using it and instead rely on checking for a valid pointer to a struct mmc_card, as it should be good enough. Signed-off-by: Ulf Hansson Reviewed-by: Linus Walleij --- drivers/mmc/host/vub300.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/mmc/host/vub300.c b/drivers/mmc/host/vub300.c index 21ea776c6e07..c061e7c704be 100644 --- a/drivers/mmc/host/vub300.c +++ b/drivers/mmc/host/vub300.c @@ -726,8 +726,7 @@ static void vub300_deadwork_thread(struct work_struct *work) */ } else if (vub300->card_present) { check_vub300_port_status(vub300); - } else if (vub300->mmc && vub300->mmc->card && - mmc_card_present(vub300->mmc->card)) { + } else if (vub300->mmc && vub300->mmc->card) { /* * the MMC core must not have responded * to the previous indication - lets @@ -1754,8 +1753,7 @@ static void vub300_cmndwork_thread(struct work_struct *work) int data_length; mutex_lock(&vub300->cmd_mutex); init_completion(&vub300->command_complete); - if (likely(vub300->vub_name[0]) || !vub300->mmc->card || - !mmc_card_present(vub300->mmc->card)) { + if (likely(vub300->vub_name[0]) || !vub300->mmc->card) { /* * the name of the EMPTY Pseudo firmware file * is used as a flag to indicate that the file From 4facdde11394d44b3869807841042d059f074a07 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Fri, 13 Jan 2017 14:14:14 +0100 Subject: [PATCH 065/145] mmc: core: Move public functions from card.h to private headers A significant amount of functions and other definitions are available through the public mmc card.h header file. Let's slim down this public mmc interface, as to prevent users from abusing it, by moving some of the functions/definitions to private mmc header files. This change concentrates on moving the functions into private mmc headers, following changes may continue with additional clean-ups. Signed-off-by: Ulf Hansson Reviewed-by: Linus Walleij Reviewed-by: Shawn Lin --- drivers/mmc/core/block.c | 2 + drivers/mmc/core/bus.c | 1 + drivers/mmc/core/bus.h | 14 ++- drivers/mmc/core/card.h | 223 +++++++++++++++++++++++++++++++++ drivers/mmc/core/core.c | 1 + drivers/mmc/core/debugfs.c | 1 + drivers/mmc/core/mmc.c | 13 ++ drivers/mmc/core/mmc_test.c | 2 + drivers/mmc/core/queue.c | 1 + drivers/mmc/core/quirks.c | 2 + drivers/mmc/core/sd.c | 1 + drivers/mmc/core/sdio.c | 1 + drivers/mmc/core/sdio_bus.c | 1 + drivers/mmc/core/sdio_io.c | 1 + drivers/mmc/core/sdio_irq.c | 1 + include/linux/mmc/card.h | 240 ------------------------------------ 16 files changed, 263 insertions(+), 242 deletions(-) create mode 100644 drivers/mmc/core/card.h diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index 41b5dbcd5b5a..a8300beae918 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -48,6 +48,8 @@ #include "queue.h" #include "block.h" #include "core.h" +#include "card.h" +#include "bus.h" #include "mmc_ops.h" #include "sd_ops.h" diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c index c64266f5a399..3be2e6a75cd9 100644 --- a/drivers/mmc/core/bus.c +++ b/drivers/mmc/core/bus.c @@ -23,6 +23,7 @@ #include #include "core.h" +#include "card.h" #include "sdio_cis.h" #include "bus.h" diff --git a/drivers/mmc/core/bus.h b/drivers/mmc/core/bus.h index 93b516ab6e88..72b0ef03f10a 100644 --- a/drivers/mmc/core/bus.h +++ b/drivers/mmc/core/bus.h @@ -11,9 +11,10 @@ #ifndef _MMC_CORE_BUS_H #define _MMC_CORE_BUS_H +#include + struct mmc_host; struct mmc_card; -struct device_type; #define MMC_DEV_ATTR(name, fmt, args...) \ static ssize_t mmc_##name##_show (struct device *dev, struct device_attribute *attr, char *buf) \ @@ -31,5 +32,14 @@ void mmc_remove_card(struct mmc_card *card); int mmc_register_bus(void); void mmc_unregister_bus(void); -#endif +struct mmc_driver { + struct device_driver drv; + int (*probe)(struct mmc_card *card); + void (*remove)(struct mmc_card *card); + void (*shutdown)(struct mmc_card *card); +}; +int mmc_register_driver(struct mmc_driver *drv); +void mmc_unregister_driver(struct mmc_driver *drv); + +#endif diff --git a/drivers/mmc/core/card.h b/drivers/mmc/core/card.h new file mode 100644 index 000000000000..95e8fc54eb21 --- /dev/null +++ b/drivers/mmc/core/card.h @@ -0,0 +1,223 @@ +/* + * Private header for the mmc subsystem + * + * Copyright (C) 2016 Linaro Ltd + * + * Author: Ulf Hansson + * + * License terms: GNU General Public License (GPL) version 2 + */ + +#ifndef _MMC_CORE_CARD_H +#define _MMC_CORE_CARD_H + +#include + +#define mmc_card_name(c) ((c)->cid.prod_name) +#define mmc_card_id(c) (dev_name(&(c)->dev)) +#define mmc_dev_to_card(d) container_of(d, struct mmc_card, dev) + +/* Card states */ +#define MMC_STATE_PRESENT (1<<0) /* present in sysfs */ +#define MMC_STATE_READONLY (1<<1) /* card is read-only */ +#define MMC_STATE_BLOCKADDR (1<<2) /* card uses block-addressing */ +#define MMC_CARD_SDXC (1<<3) /* card is SDXC */ +#define MMC_CARD_REMOVED (1<<4) /* card has been removed */ +#define MMC_STATE_DOING_BKOPS (1<<5) /* card is doing BKOPS */ +#define MMC_STATE_SUSPENDED (1<<6) /* card is suspended */ + +#define mmc_card_present(c) ((c)->state & MMC_STATE_PRESENT) +#define mmc_card_readonly(c) ((c)->state & MMC_STATE_READONLY) +#define mmc_card_blockaddr(c) ((c)->state & MMC_STATE_BLOCKADDR) +#define mmc_card_ext_capacity(c) ((c)->state & MMC_CARD_SDXC) +#define mmc_card_removed(c) ((c) && ((c)->state & MMC_CARD_REMOVED)) +#define mmc_card_doing_bkops(c) ((c)->state & MMC_STATE_DOING_BKOPS) +#define mmc_card_suspended(c) ((c)->state & MMC_STATE_SUSPENDED) + +#define mmc_card_set_present(c) ((c)->state |= MMC_STATE_PRESENT) +#define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY) +#define mmc_card_set_blockaddr(c) ((c)->state |= MMC_STATE_BLOCKADDR) +#define mmc_card_set_ext_capacity(c) ((c)->state |= MMC_CARD_SDXC) +#define mmc_card_set_removed(c) ((c)->state |= MMC_CARD_REMOVED) +#define mmc_card_set_doing_bkops(c) ((c)->state |= MMC_STATE_DOING_BKOPS) +#define mmc_card_clr_doing_bkops(c) ((c)->state &= ~MMC_STATE_DOING_BKOPS) +#define mmc_card_set_suspended(c) ((c)->state |= MMC_STATE_SUSPENDED) +#define mmc_card_clr_suspended(c) ((c)->state &= ~MMC_STATE_SUSPENDED) + +/* + * The world is not perfect and supplies us with broken mmc/sdio devices. + * For at least some of these bugs we need a work-around. + */ +struct mmc_fixup { + /* CID-specific fields. */ + const char *name; + + /* Valid revision range */ + u64 rev_start, rev_end; + + unsigned int manfid; + unsigned short oemid; + + /* SDIO-specific fields. You can use SDIO_ANY_ID here of course */ + u16 cis_vendor, cis_device; + + /* for MMC cards */ + unsigned int ext_csd_rev; + + void (*vendor_fixup)(struct mmc_card *card, int data); + int data; +}; + +#define CID_MANFID_ANY (-1u) +#define CID_OEMID_ANY ((unsigned short) -1) +#define CID_NAME_ANY (NULL) + +#define EXT_CSD_REV_ANY (-1u) + +#define CID_MANFID_SANDISK 0x2 +#define CID_MANFID_TOSHIBA 0x11 +#define CID_MANFID_MICRON 0x13 +#define CID_MANFID_SAMSUNG 0x15 +#define CID_MANFID_KINGSTON 0x70 +#define CID_MANFID_HYNIX 0x90 + +#define END_FIXUP { NULL } + +#define _FIXUP_EXT(_name, _manfid, _oemid, _rev_start, _rev_end, \ + _cis_vendor, _cis_device, \ + _fixup, _data, _ext_csd_rev) \ + { \ + .name = (_name), \ + .manfid = (_manfid), \ + .oemid = (_oemid), \ + .rev_start = (_rev_start), \ + .rev_end = (_rev_end), \ + .cis_vendor = (_cis_vendor), \ + .cis_device = (_cis_device), \ + .vendor_fixup = (_fixup), \ + .data = (_data), \ + .ext_csd_rev = (_ext_csd_rev), \ + } + +#define MMC_FIXUP_REV(_name, _manfid, _oemid, _rev_start, _rev_end, \ + _fixup, _data, _ext_csd_rev) \ + _FIXUP_EXT(_name, _manfid, \ + _oemid, _rev_start, _rev_end, \ + SDIO_ANY_ID, SDIO_ANY_ID, \ + _fixup, _data, _ext_csd_rev) \ + +#define MMC_FIXUP(_name, _manfid, _oemid, _fixup, _data) \ + MMC_FIXUP_REV(_name, _manfid, _oemid, 0, -1ull, _fixup, _data, \ + EXT_CSD_REV_ANY) + +#define MMC_FIXUP_EXT_CSD_REV(_name, _manfid, _oemid, _fixup, _data, \ + _ext_csd_rev) \ + MMC_FIXUP_REV(_name, _manfid, _oemid, 0, -1ull, _fixup, _data, \ + _ext_csd_rev) + +#define SDIO_FIXUP(_vendor, _device, _fixup, _data) \ + _FIXUP_EXT(CID_NAME_ANY, CID_MANFID_ANY, \ + CID_OEMID_ANY, 0, -1ull, \ + _vendor, _device, \ + _fixup, _data, EXT_CSD_REV_ANY) \ + +#define cid_rev(hwrev, fwrev, year, month) \ + (((u64) hwrev) << 40 | \ + ((u64) fwrev) << 32 | \ + ((u64) year) << 16 | \ + ((u64) month)) + +#define cid_rev_card(card) \ + cid_rev(card->cid.hwrev, \ + card->cid.fwrev, \ + card->cid.year, \ + card->cid.month) + +/* + * Unconditionally quirk add/remove. + */ +static inline void __maybe_unused add_quirk(struct mmc_card *card, int data) +{ + card->quirks |= data; +} + +static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data) +{ + card->quirks &= ~data; +} + +/* + * Quirk add/remove for MMC products. + */ +static inline void __maybe_unused add_quirk_mmc(struct mmc_card *card, int data) +{ + if (mmc_card_mmc(card)) + card->quirks |= data; +} + +static inline void __maybe_unused remove_quirk_mmc(struct mmc_card *card, + int data) +{ + if (mmc_card_mmc(card)) + card->quirks &= ~data; +} + +/* + * Quirk add/remove for SD products. + */ +static inline void __maybe_unused add_quirk_sd(struct mmc_card *card, int data) +{ + if (mmc_card_sd(card)) + card->quirks |= data; +} + +static inline void __maybe_unused remove_quirk_sd(struct mmc_card *card, + int data) +{ + if (mmc_card_sd(card)) + card->quirks &= ~data; +} + +static inline int mmc_card_lenient_fn0(const struct mmc_card *c) +{ + return c->quirks & MMC_QUIRK_LENIENT_FN0; +} + +static inline int mmc_blksz_for_byte_mode(const struct mmc_card *c) +{ + return c->quirks & MMC_QUIRK_BLKSZ_FOR_BYTE_MODE; +} + +static inline int mmc_card_disable_cd(const struct mmc_card *c) +{ + return c->quirks & MMC_QUIRK_DISABLE_CD; +} + +static inline int mmc_card_nonstd_func_interface(const struct mmc_card *c) +{ + return c->quirks & MMC_QUIRK_NONSTD_FUNC_IF; +} + +static inline int mmc_card_broken_byte_mode_512(const struct mmc_card *c) +{ + return c->quirks & MMC_QUIRK_BROKEN_BYTE_MODE_512; +} + +static inline int mmc_card_long_read_time(const struct mmc_card *c) +{ + return c->quirks & MMC_QUIRK_LONG_READ_TIME; +} + +static inline int mmc_card_broken_irq_polling(const struct mmc_card *c) +{ + return c->quirks & MMC_QUIRK_BROKEN_IRQ_POLLING; +} + +static inline int mmc_card_broken_hpi(const struct mmc_card *c) +{ + return c->quirks & MMC_QUIRK_BROKEN_HPI; +} + +void mmc_fixup_device(struct mmc_card *card, const struct mmc_fixup *table); + +#endif diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 3b34a751eea1..8c458255e55a 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -40,6 +40,7 @@ #include #include "core.h" +#include "card.h" #include "bus.h" #include "host.h" #include "sdio_bus.h" diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c index 30623b8b86a4..2843e6aef7ef 100644 --- a/drivers/mmc/core/debugfs.c +++ b/drivers/mmc/core/debugfs.c @@ -20,6 +20,7 @@ #include #include "core.h" +#include "card.h" #include "mmc_ops.h" #ifdef CONFIG_FAIL_MMC_REQUEST diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index ec2e85c7ae12..b91abe01aacc 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -21,6 +21,7 @@ #include #include "core.h" +#include "card.h" #include "host.h" #include "bus.h" #include "mmc_ops.h" @@ -307,6 +308,18 @@ static void mmc_manage_enhanced_area(struct mmc_card *card, u8 *ext_csd) } } +static void mmc_part_add(struct mmc_card *card, unsigned int size, + unsigned int part_cfg, char *name, int idx, bool ro, + int area_type) +{ + card->part[card->nr_parts].size = size; + card->part[card->nr_parts].part_cfg = part_cfg; + sprintf(card->part[card->nr_parts].name, name, idx); + card->part[card->nr_parts].force_ro = ro; + card->part[card->nr_parts].area_type = area_type; + card->nr_parts++; +} + static void mmc_manage_gp_partitions(struct mmc_card *card, u8 *ext_csd) { int idx; diff --git a/drivers/mmc/core/mmc_test.c b/drivers/mmc/core/mmc_test.c index 8075ad133b7d..8dd211584040 100644 --- a/drivers/mmc/core/mmc_test.c +++ b/drivers/mmc/core/mmc_test.c @@ -23,6 +23,8 @@ #include #include "core.h" +#include "card.h" +#include "bus.h" #define RESULT_OK 0 #define RESULT_FAIL 1 diff --git a/drivers/mmc/core/queue.c b/drivers/mmc/core/queue.c index 8f5bf5f82aa7..611f5c6d1950 100644 --- a/drivers/mmc/core/queue.c +++ b/drivers/mmc/core/queue.c @@ -21,6 +21,7 @@ #include "queue.h" #include "block.h" #include "core.h" +#include "card.h" #define MMC_QUEUE_BOUNCESZ 65536 diff --git a/drivers/mmc/core/quirks.c b/drivers/mmc/core/quirks.c index ca9cade317c7..bf25a9c88863 100644 --- a/drivers/mmc/core/quirks.c +++ b/drivers/mmc/core/quirks.c @@ -15,6 +15,8 @@ #include #include +#include "card.h" + #ifndef SDIO_VENDOR_ID_TI #define SDIO_VENDOR_ID_TI 0x0097 #endif diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index a614f37faf27..d66b08d6f509 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -22,6 +22,7 @@ #include #include "core.h" +#include "card.h" #include "bus.h" #include "mmc_ops.h" #include "sd.h" diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index 6810b3a8e130..5419c0dfad31 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -20,6 +20,7 @@ #include #include "core.h" +#include "card.h" #include "bus.h" #include "sd.h" #include "sdio_bus.h" diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c index 86f5b3223aae..e992a7f8a16f 100644 --- a/drivers/mmc/core/sdio_bus.c +++ b/drivers/mmc/core/sdio_bus.c @@ -25,6 +25,7 @@ #include #include "core.h" +#include "card.h" #include "sdio_cis.h" #include "sdio_bus.h" diff --git a/drivers/mmc/core/sdio_io.c b/drivers/mmc/core/sdio_io.c index 76fe6d599b77..74195d772f5a 100644 --- a/drivers/mmc/core/sdio_io.c +++ b/drivers/mmc/core/sdio_io.c @@ -17,6 +17,7 @@ #include "sdio_ops.h" #include "core.h" +#include "card.h" /** * sdio_claim_host - exclusively claim a bus for a certain SDIO function diff --git a/drivers/mmc/core/sdio_irq.c b/drivers/mmc/core/sdio_irq.c index d0846350e2fe..d29faf2addfe 100644 --- a/drivers/mmc/core/sdio_irq.c +++ b/drivers/mmc/core/sdio_irq.c @@ -28,6 +28,7 @@ #include "sdio_ops.h" #include "core.h" +#include "card.h" static int process_sdio_pending_irqs(struct mmc_host *host) { diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h index ca64f5b67983..29d00c91c25c 100644 --- a/include/linux/mmc/card.h +++ b/include/linux/mmc/card.h @@ -248,13 +248,6 @@ struct mmc_card { #define MMC_TYPE_SDIO 2 /* SDIO card */ #define MMC_TYPE_SD_COMBO 3 /* SD combo (IO+mem) card */ unsigned int state; /* (our) card state */ -#define MMC_STATE_PRESENT (1<<0) /* present in sysfs */ -#define MMC_STATE_READONLY (1<<1) /* card is read-only */ -#define MMC_STATE_BLOCKADDR (1<<2) /* card uses block-addressing */ -#define MMC_CARD_SDXC (1<<3) /* card is SDXC */ -#define MMC_CARD_REMOVED (1<<4) /* card has been removed */ -#define MMC_STATE_DOING_BKOPS (1<<5) /* card is doing BKOPS */ -#define MMC_STATE_SUSPENDED (1<<6) /* card is suspended */ unsigned int quirks; /* card quirks */ #define MMC_QUIRK_LENIENT_FN0 (1<<0) /* allow SDIO FN0 writes outside of the VS CCCR range */ #define MMC_QUIRK_BLKSZ_FOR_BYTE_MODE (1<<1) /* use func->cur_blksize */ @@ -273,7 +266,6 @@ struct mmc_card { #define MMC_QUIRK_TRIM_BROKEN (1<<12) /* Skip trim */ #define MMC_QUIRK_BROKEN_HPI (1<<13) /* Disable broken HPI support */ - unsigned int erase_size; /* erase size in sectors */ unsigned int erase_shift; /* if erase unit is power 2 */ unsigned int pref_erase; /* in sectors */ @@ -309,245 +301,13 @@ struct mmc_card { unsigned int nr_parts; }; -/* - * This function fill contents in mmc_part. - */ -static inline void mmc_part_add(struct mmc_card *card, unsigned int size, - unsigned int part_cfg, char *name, int idx, bool ro, - int area_type) -{ - card->part[card->nr_parts].size = size; - card->part[card->nr_parts].part_cfg = part_cfg; - sprintf(card->part[card->nr_parts].name, name, idx); - card->part[card->nr_parts].force_ro = ro; - card->part[card->nr_parts].area_type = area_type; - card->nr_parts++; -} - static inline bool mmc_large_sector(struct mmc_card *card) { return card->ext_csd.data_sector_size == 4096; } -/* - * The world is not perfect and supplies us with broken mmc/sdio devices. - * For at least some of these bugs we need a work-around. - */ - -struct mmc_fixup { - /* CID-specific fields. */ - const char *name; - - /* Valid revision range */ - u64 rev_start, rev_end; - - unsigned int manfid; - unsigned short oemid; - - /* SDIO-specfic fields. You can use SDIO_ANY_ID here of course */ - u16 cis_vendor, cis_device; - - /* for MMC cards */ - unsigned int ext_csd_rev; - - void (*vendor_fixup)(struct mmc_card *card, int data); - int data; -}; - -#define CID_MANFID_ANY (-1u) -#define CID_OEMID_ANY ((unsigned short) -1) -#define CID_NAME_ANY (NULL) - -#define EXT_CSD_REV_ANY (-1u) - -#define CID_MANFID_SANDISK 0x2 -#define CID_MANFID_TOSHIBA 0x11 -#define CID_MANFID_MICRON 0x13 -#define CID_MANFID_SAMSUNG 0x15 -#define CID_MANFID_KINGSTON 0x70 -#define CID_MANFID_HYNIX 0x90 - -#define END_FIXUP { NULL } - -#define _FIXUP_EXT(_name, _manfid, _oemid, _rev_start, _rev_end, \ - _cis_vendor, _cis_device, \ - _fixup, _data, _ext_csd_rev) \ - { \ - .name = (_name), \ - .manfid = (_manfid), \ - .oemid = (_oemid), \ - .rev_start = (_rev_start), \ - .rev_end = (_rev_end), \ - .cis_vendor = (_cis_vendor), \ - .cis_device = (_cis_device), \ - .vendor_fixup = (_fixup), \ - .data = (_data), \ - .ext_csd_rev = (_ext_csd_rev), \ - } - -#define MMC_FIXUP_REV(_name, _manfid, _oemid, _rev_start, _rev_end, \ - _fixup, _data, _ext_csd_rev) \ - _FIXUP_EXT(_name, _manfid, \ - _oemid, _rev_start, _rev_end, \ - SDIO_ANY_ID, SDIO_ANY_ID, \ - _fixup, _data, _ext_csd_rev) \ - -#define MMC_FIXUP(_name, _manfid, _oemid, _fixup, _data) \ - MMC_FIXUP_REV(_name, _manfid, _oemid, 0, -1ull, _fixup, _data, \ - EXT_CSD_REV_ANY) - -#define MMC_FIXUP_EXT_CSD_REV(_name, _manfid, _oemid, _fixup, _data, \ - _ext_csd_rev) \ - MMC_FIXUP_REV(_name, _manfid, _oemid, 0, -1ull, _fixup, _data, \ - _ext_csd_rev) - -#define SDIO_FIXUP(_vendor, _device, _fixup, _data) \ - _FIXUP_EXT(CID_NAME_ANY, CID_MANFID_ANY, \ - CID_OEMID_ANY, 0, -1ull, \ - _vendor, _device, \ - _fixup, _data, EXT_CSD_REV_ANY) \ - -#define cid_rev(hwrev, fwrev, year, month) \ - (((u64) hwrev) << 40 | \ - ((u64) fwrev) << 32 | \ - ((u64) year) << 16 | \ - ((u64) month)) - -#define cid_rev_card(card) \ - cid_rev(card->cid.hwrev, \ - card->cid.fwrev, \ - card->cid.year, \ - card->cid.month) - -/* - * Unconditionally quirk add/remove. - */ - -static inline void __maybe_unused add_quirk(struct mmc_card *card, int data) -{ - card->quirks |= data; -} - -static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data) -{ - card->quirks &= ~data; -} - #define mmc_card_mmc(c) ((c)->type == MMC_TYPE_MMC) #define mmc_card_sd(c) ((c)->type == MMC_TYPE_SD) #define mmc_card_sdio(c) ((c)->type == MMC_TYPE_SDIO) -#define mmc_card_present(c) ((c)->state & MMC_STATE_PRESENT) -#define mmc_card_readonly(c) ((c)->state & MMC_STATE_READONLY) -#define mmc_card_blockaddr(c) ((c)->state & MMC_STATE_BLOCKADDR) -#define mmc_card_ext_capacity(c) ((c)->state & MMC_CARD_SDXC) -#define mmc_card_removed(c) ((c) && ((c)->state & MMC_CARD_REMOVED)) -#define mmc_card_doing_bkops(c) ((c)->state & MMC_STATE_DOING_BKOPS) -#define mmc_card_suspended(c) ((c)->state & MMC_STATE_SUSPENDED) - -#define mmc_card_set_present(c) ((c)->state |= MMC_STATE_PRESENT) -#define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY) -#define mmc_card_set_blockaddr(c) ((c)->state |= MMC_STATE_BLOCKADDR) -#define mmc_card_set_ext_capacity(c) ((c)->state |= MMC_CARD_SDXC) -#define mmc_card_set_removed(c) ((c)->state |= MMC_CARD_REMOVED) -#define mmc_card_set_doing_bkops(c) ((c)->state |= MMC_STATE_DOING_BKOPS) -#define mmc_card_clr_doing_bkops(c) ((c)->state &= ~MMC_STATE_DOING_BKOPS) -#define mmc_card_set_suspended(c) ((c)->state |= MMC_STATE_SUSPENDED) -#define mmc_card_clr_suspended(c) ((c)->state &= ~MMC_STATE_SUSPENDED) - -/* - * Quirk add/remove for MMC products. - */ - -static inline void __maybe_unused add_quirk_mmc(struct mmc_card *card, int data) -{ - if (mmc_card_mmc(card)) - card->quirks |= data; -} - -static inline void __maybe_unused remove_quirk_mmc(struct mmc_card *card, - int data) -{ - if (mmc_card_mmc(card)) - card->quirks &= ~data; -} - -/* - * Quirk add/remove for SD products. - */ - -static inline void __maybe_unused add_quirk_sd(struct mmc_card *card, int data) -{ - if (mmc_card_sd(card)) - card->quirks |= data; -} - -static inline void __maybe_unused remove_quirk_sd(struct mmc_card *card, - int data) -{ - if (mmc_card_sd(card)) - card->quirks &= ~data; -} - -static inline int mmc_card_lenient_fn0(const struct mmc_card *c) -{ - return c->quirks & MMC_QUIRK_LENIENT_FN0; -} - -static inline int mmc_blksz_for_byte_mode(const struct mmc_card *c) -{ - return c->quirks & MMC_QUIRK_BLKSZ_FOR_BYTE_MODE; -} - -static inline int mmc_card_disable_cd(const struct mmc_card *c) -{ - return c->quirks & MMC_QUIRK_DISABLE_CD; -} - -static inline int mmc_card_nonstd_func_interface(const struct mmc_card *c) -{ - return c->quirks & MMC_QUIRK_NONSTD_FUNC_IF; -} - -static inline int mmc_card_broken_byte_mode_512(const struct mmc_card *c) -{ - return c->quirks & MMC_QUIRK_BROKEN_BYTE_MODE_512; -} - -static inline int mmc_card_long_read_time(const struct mmc_card *c) -{ - return c->quirks & MMC_QUIRK_LONG_READ_TIME; -} - -static inline int mmc_card_broken_irq_polling(const struct mmc_card *c) -{ - return c->quirks & MMC_QUIRK_BROKEN_IRQ_POLLING; -} - -static inline int mmc_card_broken_hpi(const struct mmc_card *c) -{ - return c->quirks & MMC_QUIRK_BROKEN_HPI; -} - -#define mmc_card_name(c) ((c)->cid.prod_name) -#define mmc_card_id(c) (dev_name(&(c)->dev)) - -#define mmc_dev_to_card(d) container_of(d, struct mmc_card, dev) - -/* - * MMC device driver (e.g., Flash card, I/O card...) - */ -struct mmc_driver { - struct device_driver drv; - int (*probe)(struct mmc_card *); - void (*remove)(struct mmc_card *); - void (*shutdown)(struct mmc_card *); -}; - -extern int mmc_register_driver(struct mmc_driver *); -extern void mmc_unregister_driver(struct mmc_driver *); - -extern void mmc_fixup_device(struct mmc_card *card, - const struct mmc_fixup *table); - #endif /* LINUX_MMC_CARD_H */ From 5857b29b96dcf208e4903ec6f20d132e6a77cac2 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Fri, 13 Jan 2017 14:14:15 +0100 Subject: [PATCH 066/145] mmc: core: Move public functions from host.h to private headers A significant amount of functions are available through the public mmc host.h header file. Let's slim down this public mmc interface, as to prevent users from abusing it, by moving some of the functions to private mmc host.h header file. This change concentrates on moving the functions into private mmc headers, following changes may continue with additional clean-ups. Signed-off-by: Ulf Hansson Reviewed-by: Linus Walleij Reviewed-by: Shawn Lin --- drivers/mmc/core/block.c | 1 + drivers/mmc/core/bus.c | 1 + drivers/mmc/core/debugfs.c | 1 + drivers/mmc/core/host.h | 49 ++++++++++++++++++++++++++++++++++++- drivers/mmc/core/mmc_test.c | 1 + drivers/mmc/core/sd.c | 1 + drivers/mmc/core/sdio.c | 1 + include/linux/mmc/host.h | 48 ++---------------------------------- 8 files changed, 56 insertions(+), 47 deletions(-) diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index a8300beae918..7bd03381810d 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -49,6 +49,7 @@ #include "block.h" #include "core.h" #include "card.h" +#include "host.h" #include "bus.h" #include "mmc_ops.h" #include "sd_ops.h" diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c index 3be2e6a75cd9..301246513a37 100644 --- a/drivers/mmc/core/bus.c +++ b/drivers/mmc/core/bus.c @@ -24,6 +24,7 @@ #include "core.h" #include "card.h" +#include "host.h" #include "sdio_cis.h" #include "bus.h" diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c index 2843e6aef7ef..a1fba5732d66 100644 --- a/drivers/mmc/core/debugfs.c +++ b/drivers/mmc/core/debugfs.c @@ -21,6 +21,7 @@ #include "core.h" #include "card.h" +#include "host.h" #include "mmc_ops.h" #ifdef CONFIG_FAIL_MMC_REQUEST diff --git a/drivers/mmc/core/host.h b/drivers/mmc/core/host.h index 366ce79c3498..fb6a76a03833 100644 --- a/drivers/mmc/core/host.h +++ b/drivers/mmc/core/host.h @@ -11,7 +11,7 @@ #ifndef _MMC_CORE_HOST_H #define _MMC_CORE_HOST_H -struct mmc_host; +#include int mmc_register_host_class(void); void mmc_unregister_host_class(void); @@ -21,6 +21,53 @@ void mmc_retune_disable(struct mmc_host *host); void mmc_retune_hold(struct mmc_host *host); void mmc_retune_release(struct mmc_host *host); int mmc_retune(struct mmc_host *host); +void mmc_retune_pause(struct mmc_host *host); +void mmc_retune_unpause(struct mmc_host *host); + +static inline void mmc_retune_recheck(struct mmc_host *host) +{ + if (host->hold_retune <= 1) + host->retune_now = 1; +} + +static inline int mmc_host_cmd23(struct mmc_host *host) +{ + return host->caps & MMC_CAP_CMD23; +} + +static inline int mmc_boot_partition_access(struct mmc_host *host) +{ + return !(host->caps2 & MMC_CAP2_BOOTPART_NOACC); +} + +static inline int mmc_host_uhs(struct mmc_host *host) +{ + return host->caps & + (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 | + MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 | + MMC_CAP_UHS_DDR50); +} + +static inline bool mmc_card_hs200(struct mmc_card *card) +{ + return card->host->ios.timing == MMC_TIMING_MMC_HS200; +} + +static inline bool mmc_card_ddr52(struct mmc_card *card) +{ + return card->host->ios.timing == MMC_TIMING_MMC_DDR52; +} + +static inline bool mmc_card_hs400(struct mmc_card *card) +{ + return card->host->ios.timing == MMC_TIMING_MMC_HS400; +} + +static inline bool mmc_card_hs400es(struct mmc_card *card) +{ + return card->host->ios.enhanced_strobe; +} + #endif diff --git a/drivers/mmc/core/mmc_test.c b/drivers/mmc/core/mmc_test.c index 8dd211584040..83d193c09d98 100644 --- a/drivers/mmc/core/mmc_test.c +++ b/drivers/mmc/core/mmc_test.c @@ -24,6 +24,7 @@ #include "core.h" #include "card.h" +#include "host.h" #include "bus.h" #define RESULT_OK 0 diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index d66b08d6f509..8b4f13943712 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -23,6 +23,7 @@ #include "core.h" #include "card.h" +#include "host.h" #include "bus.h" #include "mmc_ops.h" #include "sd.h" diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index 5419c0dfad31..261c88632c43 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -21,6 +21,7 @@ #include "core.h" #include "card.h" +#include "host.h" #include "bus.h" #include "sd.h" #include "sdio_bus.h" diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index 7de05195bff6..97699d55b2ae 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -473,56 +473,20 @@ static inline int mmc_card_wake_sdio_irq(struct mmc_host *host) return host->pm_flags & MMC_PM_WAKE_SDIO_IRQ; } -static inline int mmc_host_cmd23(struct mmc_host *host) -{ - return host->caps & MMC_CAP_CMD23; -} - -static inline int mmc_boot_partition_access(struct mmc_host *host) -{ - return !(host->caps2 & MMC_CAP2_BOOTPART_NOACC); -} - -static inline int mmc_host_uhs(struct mmc_host *host) -{ - return host->caps & - (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 | - MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 | - MMC_CAP_UHS_DDR50); -} - +/* TODO: Move to private header */ static inline int mmc_card_hs(struct mmc_card *card) { return card->host->ios.timing == MMC_TIMING_SD_HS || card->host->ios.timing == MMC_TIMING_MMC_HS; } +/* TODO: Move to private header */ static inline int mmc_card_uhs(struct mmc_card *card) { return card->host->ios.timing >= MMC_TIMING_UHS_SDR12 && card->host->ios.timing <= MMC_TIMING_UHS_DDR50; } -static inline bool mmc_card_hs200(struct mmc_card *card) -{ - return card->host->ios.timing == MMC_TIMING_MMC_HS200; -} - -static inline bool mmc_card_ddr52(struct mmc_card *card) -{ - return card->host->ios.timing == MMC_TIMING_MMC_DDR52; -} - -static inline bool mmc_card_hs400(struct mmc_card *card) -{ - return card->host->ios.timing == MMC_TIMING_MMC_HS400; -} - -static inline bool mmc_card_hs400es(struct mmc_card *card) -{ - return card->host->ios.enhanced_strobe; -} - void mmc_retune_timer_stop(struct mmc_host *host); static inline void mmc_retune_needed(struct mmc_host *host) @@ -531,12 +495,6 @@ static inline void mmc_retune_needed(struct mmc_host *host) host->need_retune = 1; } -static inline void mmc_retune_recheck(struct mmc_host *host) -{ - if (host->hold_retune <= 1) - host->retune_now = 1; -} - static inline bool mmc_can_retune(struct mmc_host *host) { return host->can_retune == 1; @@ -544,7 +502,5 @@ static inline bool mmc_can_retune(struct mmc_host *host) int mmc_send_tuning(struct mmc_host *host, u32 opcode, int *cmd_error); int mmc_abort_tuning(struct mmc_host *host, u32 opcode); -void mmc_retune_pause(struct mmc_host *host); -void mmc_retune_unpause(struct mmc_host *host); #endif /* LINUX_MMC_HOST_H */ From 23888bfe9bd730d42e326cc5f6f1188beb948f97 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Fri, 13 Jan 2017 14:14:16 +0100 Subject: [PATCH 067/145] mmc: core: Don't use extern declarations of public mmc functions Using extern when declaring functions in the public header, core.h, is redundant. Let's just remove the use of it. Signed-off-by: Ulf Hansson Reviewed-by: Linus Walleij Reviewed-by: Shawn Lin --- include/linux/mmc/core.h | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h index 6440e10c86cd..6dcb339fcd45 100644 --- a/include/linux/mmc/core.h +++ b/include/linux/mmc/core.h @@ -158,13 +158,14 @@ struct mmc_request { struct mmc_card; struct mmc_async_req; -extern struct mmc_async_req *mmc_start_req(struct mmc_host *, - struct mmc_async_req *, - enum mmc_blk_status *); -extern void mmc_wait_for_req(struct mmc_host *, struct mmc_request *); -extern int mmc_wait_for_cmd(struct mmc_host *, struct mmc_command *, int); +struct mmc_async_req *mmc_start_req(struct mmc_host *host, + struct mmc_async_req *areq, + enum mmc_blk_status *ret_stat); +void mmc_wait_for_req(struct mmc_host *host, struct mmc_request *mrq); +int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, + int retries); -extern int mmc_hw_reset(struct mmc_host *host); -extern void mmc_set_data_timeout(struct mmc_data *, const struct mmc_card *); +int mmc_hw_reset(struct mmc_host *host); +void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card); #endif /* LINUX_MMC_CORE_H */ From e28d6f048799acb0014491e6b74e580d84bd7916 Mon Sep 17 00:00:00 2001 From: Zhang Rui Date: Wed, 18 Jan 2017 17:46:18 +0800 Subject: [PATCH 068/145] mmc: sdhci-acpi: support deferred probe With commit 67bf5156edc4 ("gpio / ACPI: fix returned error from acpi_dev_gpio_irq_get()"), mmc_gpiod_request_cd() returns -EPROBE_DEFER if GPIO is not ready when sdhci-acpi driver is probed, and sdhci-acpi driver should be probed again later in this case. This fixes an order issue when both GPIO and sdhci-acpi drivers are built as modules. CC: stable@vger.kernel.org # v4.9 Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=177101 Tested-by: Jonas Aaberg Signed-off-by: Zhang Rui Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-acpi.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/host/sdhci-acpi.c b/drivers/mmc/host/sdhci-acpi.c index 278a5a435ab7..9dcb7048e3b1 100644 --- a/drivers/mmc/host/sdhci-acpi.c +++ b/drivers/mmc/host/sdhci-acpi.c @@ -467,7 +467,10 @@ static int sdhci_acpi_probe(struct platform_device *pdev) if (sdhci_acpi_flag(c, SDHCI_ACPI_SD_CD)) { bool v = sdhci_acpi_flag(c, SDHCI_ACPI_SD_CD_OVERRIDE_LEVEL); - if (mmc_gpiod_request_cd(host->mmc, NULL, 0, v, 0, NULL)) { + err = mmc_gpiod_request_cd(host->mmc, NULL, 0, v, 0, NULL); + if (err) { + if (err == -EPROBE_DEFER) + goto err_free; dev_warn(dev, "failed to setup card detect gpio\n"); c->use_runtime_pm = false; } From e81c022a00cd91b0d555d9d9194d421e3b8d642c Mon Sep 17 00:00:00 2001 From: Alexey Khoroshilov Date: Sat, 14 Jan 2017 01:52:51 +0300 Subject: [PATCH 069/145] mmc: wbsd: safer check if dma_addr is valid DMA address host->dma_addr can store a value that is not returned by the DMA API, so it is safer to check if is a valid DMA address indirectly. Signed-off-by: Alexey Khoroshilov Signed-off-by: Ulf Hansson --- drivers/mmc/host/wbsd.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/wbsd.c b/drivers/mmc/host/wbsd.c index 80a3b11f3217..bd04e8bae010 100644 --- a/drivers/mmc/host/wbsd.c +++ b/drivers/mmc/host/wbsd.c @@ -1437,11 +1437,14 @@ err: static void wbsd_release_dma(struct wbsd_host *host) { - if (!dma_mapping_error(mmc_dev(host->mmc), host->dma_addr)) { + /* + * host->dma_addr is valid here iff host->dma_buffer is not NULL. + */ + if (host->dma_buffer) { dma_unmap_single(mmc_dev(host->mmc), host->dma_addr, WBSD_DMA_SIZE, DMA_BIDIRECTIONAL); + kfree(host->dma_buffer); } - kfree(host->dma_buffer); if (host->dma >= 0) free_dma(host->dma); From 73a85069f91d35f6921fd9d9b2603f482b9c9bd1 Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Sat, 14 Jan 2017 17:29:18 +0000 Subject: [PATCH 070/145] mmc: mxs-mmc: Implement CMD23 support This patch implements support for multiblock transfers bounded by SET_BLOCK_COUNT (CMD23) on the MXS MMC host driver. Signed-off-by: Stefan Wahren Signed-off-by: Ulf Hansson --- drivers/mmc/host/mxs-mmc.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/drivers/mmc/host/mxs-mmc.c b/drivers/mmc/host/mxs-mmc.c index c8b8ac66ff7e..add1e70195ea 100644 --- a/drivers/mmc/host/mxs-mmc.c +++ b/drivers/mmc/host/mxs-mmc.c @@ -153,7 +153,11 @@ static void mxs_mmc_request_done(struct mxs_mmc_host *host) } } - if (data) { + if (cmd == mrq->sbc) { + /* Finished CMD23, now send actual command. */ + mxs_mmc_start_cmd(host, mrq->cmd); + return; + } else if (data) { dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len, ssp->dma_dir); /* @@ -166,7 +170,7 @@ static void mxs_mmc_request_done(struct mxs_mmc_host *host) data->bytes_xfered = 0; host->data = NULL; - if (mrq->stop) { + if (data->stop && (data->error || !mrq->sbc)) { mxs_mmc_start_cmd(host, mrq->stop); return; } @@ -495,7 +499,11 @@ static void mxs_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq) WARN_ON(host->mrq != NULL); host->mrq = mrq; - mxs_mmc_start_cmd(host, mrq->cmd); + + if (mrq->sbc) + mxs_mmc_start_cmd(host, mrq->sbc); + else + mxs_mmc_start_cmd(host, mrq->cmd); } static void mxs_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) @@ -642,7 +650,7 @@ static int mxs_mmc_probe(struct platform_device *pdev) /* set mmc core parameters */ mmc->ops = &mxs_mmc_ops; mmc->caps = MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED | - MMC_CAP_SDIO_IRQ | MMC_CAP_NEEDS_POLL; + MMC_CAP_SDIO_IRQ | MMC_CAP_NEEDS_POLL | MMC_CAP_CMD23; host->broken_cd = of_property_read_bool(np, "broken-cd"); From b54aaa8a4fd829ecffa140b04b59d08ffe20a790 Mon Sep 17 00:00:00 2001 From: Ritesh Harjani Date: Tue, 10 Jan 2017 12:30:45 +0530 Subject: [PATCH 071/145] mmc: sdhci-msm: Factor out sdhci_msm_hc_select_mode This factors out sdhci_msm_hc_select_mode to later use it during enhanced_strobe mode select. It also further breaks sdhci_msm_hc_select_mode into separate functions for configuring HS400 mode or other modes. Signed-off-by: Ritesh Harjani Tested-by: Jeremy McNicoll Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-msm.c | 201 ++++++++++++++++++++--------------- 1 file changed, 114 insertions(+), 87 deletions(-) diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index 32879b845b75..1e4264703335 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -464,6 +464,119 @@ static int msm_init_cm_dll(struct sdhci_host *host) return 0; } +static void msm_hc_select_default(struct sdhci_host *host) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); + u32 config; + + if (!msm_host->use_cdclp533) { + config = readl_relaxed(host->ioaddr + + CORE_VENDOR_SPEC3); + config &= ~CORE_PWRSAVE_DLL; + writel_relaxed(config, host->ioaddr + + CORE_VENDOR_SPEC3); + } + + config = readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC); + config &= ~CORE_HC_MCLK_SEL_MASK; + config |= CORE_HC_MCLK_SEL_DFLT; + writel_relaxed(config, host->ioaddr + CORE_VENDOR_SPEC); + + /* + * Disable HC_SELECT_IN to be able to use the UHS mode select + * configuration from Host Control2 register for all other + * modes. + * Write 0 to HC_SELECT_IN and HC_SELECT_IN_EN field + * in VENDOR_SPEC_FUNC + */ + config = readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC); + config &= ~CORE_HC_SELECT_IN_EN; + config &= ~CORE_HC_SELECT_IN_MASK; + writel_relaxed(config, host->ioaddr + CORE_VENDOR_SPEC); + + /* + * Make sure above writes impacting free running MCLK are completed + * before changing the clk_rate at GCC. + */ + wmb(); +} + +static void msm_hc_select_hs400(struct sdhci_host *host) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); + u32 config, dll_lock; + int rc; + + /* Select the divided clock (free running MCLK/2) */ + config = readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC); + config &= ~CORE_HC_MCLK_SEL_MASK; + config |= CORE_HC_MCLK_SEL_HS400; + + writel_relaxed(config, host->ioaddr + CORE_VENDOR_SPEC); + /* + * Select HS400 mode using the HC_SELECT_IN from VENDOR SPEC + * register + */ + if (msm_host->tuning_done && !msm_host->calibration_done) { + config = readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC); + config |= CORE_HC_SELECT_IN_HS400; + config |= CORE_HC_SELECT_IN_EN; + writel_relaxed(config, host->ioaddr + CORE_VENDOR_SPEC); + } + if (!msm_host->clk_rate && !msm_host->use_cdclp533) { + /* + * Poll on DLL_LOCK or DDR_DLL_LOCK bits in + * CORE_DLL_STATUS to be set. This should get set + * within 15 us at 200 MHz. + */ + rc = readl_relaxed_poll_timeout(host->ioaddr + + CORE_DLL_STATUS, + dll_lock, + (dll_lock & + (CORE_DLL_LOCK | + CORE_DDR_DLL_LOCK)), 10, + 1000); + if (rc == -ETIMEDOUT) + pr_err("%s: Unable to get DLL_LOCK/DDR_DLL_LOCK, dll_status: 0x%08x\n", + mmc_hostname(host->mmc), dll_lock); + } + /* + * Make sure above writes impacting free running MCLK are completed + * before changing the clk_rate at GCC. + */ + wmb(); +} + +/* + * sdhci_msm_hc_select_mode :- In general all timing modes are + * controlled via UHS mode select in Host Control2 register. + * eMMC specific HS200/HS400 doesn't have their respective modes + * defined here, hence we use these values. + * + * HS200 - SDR104 (Since they both are equivalent in functionality) + * HS400 - This involves multiple configurations + * Initially SDR104 - when tuning is required as HS200 + * Then when switching to DDR @ 400MHz (HS400) we use + * the vendor specific HC_SELECT_IN to control the mode. + * + * In addition to controlling the modes we also need to select the + * correct input clock for DLL depending on the mode. + * + * HS400 - divided clock (free running MCLK/2) + * All other modes - default (free running MCLK) + */ +void sdhci_msm_hc_select_mode(struct sdhci_host *host) +{ + struct mmc_ios ios = host->mmc->ios; + + if (ios.timing == MMC_TIMING_MMC_HS400) + msm_hc_select_hs400(host); + else + msm_hc_select_default(host); +} + static int sdhci_msm_cdclp533_calibration(struct sdhci_host *host) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); @@ -894,7 +1007,6 @@ static void sdhci_msm_set_clock(struct sdhci_host *host, unsigned int clock) struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); struct mmc_ios curr_ios = host->mmc->ios; - u32 config, dll_lock; int rc; if (!clock) { @@ -913,93 +1025,8 @@ static void sdhci_msm_set_clock(struct sdhci_host *host, unsigned int clock) curr_ios.timing == MMC_TIMING_MMC_DDR52 || curr_ios.timing == MMC_TIMING_MMC_HS400) clock *= 2; - /* - * In general all timing modes are controlled via UHS mode select in - * Host Control2 register. eMMC specific HS200/HS400 doesn't have - * their respective modes defined here, hence we use these values. - * - * HS200 - SDR104 (Since they both are equivalent in functionality) - * HS400 - This involves multiple configurations - * Initially SDR104 - when tuning is required as HS200 - * Then when switching to DDR @ 400MHz (HS400) we use - * the vendor specific HC_SELECT_IN to control the mode. - * - * In addition to controlling the modes we also need to select the - * correct input clock for DLL depending on the mode. - * - * HS400 - divided clock (free running MCLK/2) - * All other modes - default (free running MCLK) - */ - if (curr_ios.timing == MMC_TIMING_MMC_HS400) { - /* Select the divided clock (free running MCLK/2) */ - config = readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC); - config &= ~CORE_HC_MCLK_SEL_MASK; - config |= CORE_HC_MCLK_SEL_HS400; - writel_relaxed(config, host->ioaddr + CORE_VENDOR_SPEC); - /* - * Select HS400 mode using the HC_SELECT_IN from VENDOR SPEC - * register - */ - if (msm_host->tuning_done && !msm_host->calibration_done) { - /* - * Write 0x6 to HC_SELECT_IN and 1 to HC_SELECT_IN_EN - * field in VENDOR_SPEC_FUNC - */ - config = readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC); - config |= CORE_HC_SELECT_IN_HS400; - config |= CORE_HC_SELECT_IN_EN; - writel_relaxed(config, host->ioaddr + CORE_VENDOR_SPEC); - } - if (!msm_host->clk_rate && !msm_host->use_cdclp533) { - /* - * Poll on DLL_LOCK or DDR_DLL_LOCK bits in - * CORE_DLL_STATUS to be set. This should get set - * within 15 us at 200 MHz. - */ - rc = readl_relaxed_poll_timeout(host->ioaddr + - CORE_DLL_STATUS, - dll_lock, - (dll_lock & - (CORE_DLL_LOCK | - CORE_DDR_DLL_LOCK)), 10, - 1000); - if (rc == -ETIMEDOUT) - pr_err("%s: Unable to get DLL_LOCK/DDR_DLL_LOCK, dll_status: 0x%08x\n", - mmc_hostname(host->mmc), dll_lock); - } - } else { - if (!msm_host->use_cdclp533) { - config = readl_relaxed(host->ioaddr + - CORE_VENDOR_SPEC3); - config &= ~CORE_PWRSAVE_DLL; - writel_relaxed(config, host->ioaddr + - CORE_VENDOR_SPEC3); - } - - config = readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC); - config &= ~CORE_HC_MCLK_SEL_MASK; - config |= CORE_HC_MCLK_SEL_DFLT; - writel_relaxed(config, host->ioaddr + CORE_VENDOR_SPEC); - - /* - * Disable HC_SELECT_IN to be able to use the UHS mode select - * configuration from Host Control2 register for all other - * modes. - * Write 0 to HC_SELECT_IN and HC_SELECT_IN_EN field - * in VENDOR_SPEC_FUNC - */ - config = readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC); - config &= ~CORE_HC_SELECT_IN_EN; - config &= ~CORE_HC_SELECT_IN_MASK; - writel_relaxed(config, host->ioaddr + CORE_VENDOR_SPEC); - } - - /* - * Make sure above writes impacting free running MCLK are completed - * before changing the clk_rate at GCC. - */ - wmb(); + sdhci_msm_hc_select_mode(host); rc = clk_set_rate(msm_host->clk, clock); if (rc) { From 0fb8a3d46b0393a8580ed78a0bc9267869f76b3c Mon Sep 17 00:00:00 2001 From: Ritesh Harjani Date: Tue, 10 Jan 2017 12:30:46 +0530 Subject: [PATCH 072/145] mmc: sdhci-msm: Factor out function to set/get msm clock rate Factor out msm_set/get_clock_rate_for_bus_mode for it's later use in changing the tuning sequence for selecting HS400 bus speed mode. Signed-off-by: Ritesh Harjani Tested-by: Jeremy McNicoll Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-msm.c | 64 ++++++++++++++++++++++-------------- 1 file changed, 40 insertions(+), 24 deletions(-) diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index 1e4264703335..3fc496e24b23 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -138,6 +138,45 @@ struct sdhci_msm_host { bool use_cdclp533; }; +static unsigned int msm_get_clock_rate_for_bus_mode(struct sdhci_host *host, + unsigned int clock) +{ + struct mmc_ios ios = host->mmc->ios; + /* + * The SDHC requires internal clock frequency to be double the + * actual clock that will be set for DDR mode. The controller + * uses the faster clock(100/400MHz) for some of its parts and + * send the actual required clock (50/200MHz) to the card. + */ + if (ios.timing == MMC_TIMING_UHS_DDR50 || + ios.timing == MMC_TIMING_MMC_DDR52 || + ios.timing == MMC_TIMING_MMC_HS400) + clock *= 2; + return clock; +} + +static void msm_set_clock_rate_for_bus_mode(struct sdhci_host *host, + unsigned int clock) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); + struct mmc_ios curr_ios = host->mmc->ios; + int rc; + + clock = msm_get_clock_rate_for_bus_mode(host, clock); + rc = clk_set_rate(msm_host->clk, clock); + if (rc) { + pr_err("%s: Failed to set clock at rate %u at timing %d\n", + mmc_hostname(host->mmc), clock, + curr_ios.timing); + return; + } + msm_host->clk_rate = clock; + pr_debug("%s: Setting clock at rate %lu at timing %d\n", + mmc_hostname(host->mmc), clk_get_rate(msm_host->clk), + curr_ios.timing); +} + /* Platform specific tuning */ static inline int msm_dll_poll_ck_out_en(struct sdhci_host *host, u8 poll) { @@ -1006,8 +1045,6 @@ static void sdhci_msm_set_clock(struct sdhci_host *host, unsigned int clock) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); - struct mmc_ios curr_ios = host->mmc->ios; - int rc; if (!clock) { msm_host->clk_rate = clock; @@ -1015,32 +1052,11 @@ static void sdhci_msm_set_clock(struct sdhci_host *host, unsigned int clock) } spin_unlock_irq(&host->lock); - /* - * The SDHC requires internal clock frequency to be double the - * actual clock that will be set for DDR mode. The controller - * uses the faster clock(100/400MHz) for some of its parts and - * send the actual required clock (50/200MHz) to the card. - */ - if (curr_ios.timing == MMC_TIMING_UHS_DDR50 || - curr_ios.timing == MMC_TIMING_MMC_DDR52 || - curr_ios.timing == MMC_TIMING_MMC_HS400) - clock *= 2; sdhci_msm_hc_select_mode(host); - rc = clk_set_rate(msm_host->clk, clock); - if (rc) { - pr_err("%s: Failed to set clock at rate %u at timing %d\n", - mmc_hostname(host->mmc), clock, - curr_ios.timing); - goto out_lock; - } - msm_host->clk_rate = clock; - pr_debug("%s: Setting clock at rate %lu at timing %d\n", - mmc_hostname(host->mmc), clk_get_rate(msm_host->clk), - curr_ios.timing); + msm_set_clock_rate_for_bus_mode(host, clock); -out_lock: spin_lock_irq(&host->lock); out: __sdhci_msm_set_clock(host, clock); From db9bd1638115f76c09a9d5b58a01552d49ed1df5 Mon Sep 17 00:00:00 2001 From: Ritesh Harjani Date: Tue, 10 Jan 2017 12:30:47 +0530 Subject: [PATCH 073/145] mmc: sdhci-msm: Factor out sdhci_msm_hs400 Factor out sdhci_msm_hs400 used for DLL calibration in HS400 modes. This function will be needed for enhanced_strobe as well. Signed-off-by: Ritesh Harjani Tested-by: Jeremy McNicoll Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-msm.c | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index 3fc496e24b23..5a37c294b17a 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -884,6 +884,28 @@ retry: return rc; } +/* + * sdhci_msm_hs400 - Calibrate the DLL for HS400 bus speed mode operation. + * DLL operation is only needed for clock > 100MHz. For clock <= 100MHz + * fixed feedback clock is used. + */ +static void sdhci_msm_hs400(struct sdhci_host *host, struct mmc_ios *ios) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); + int ret; + + if (host->clock > CORE_FREQ_100MHZ && + msm_host->tuning_done && !msm_host->calibration_done) { + ret = sdhci_msm_hs400_dll_calibration(host); + if (!ret) + msm_host->calibration_done = true; + else + pr_err("%s: Failed to calibrate DLL for hs400 mode (%d)\n", + mmc_hostname(host->mmc), ret); + } +} + static void sdhci_msm_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs) { @@ -952,12 +974,10 @@ static void sdhci_msm_set_uhs_signaling(struct sdhci_host *host, sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2); spin_unlock_irq(&host->lock); - /* CDCLP533 HW calibration is only required for HS400 mode*/ - if (host->clock > CORE_FREQ_100MHZ && - msm_host->tuning_done && !msm_host->calibration_done && - mmc->ios.timing == MMC_TIMING_MMC_HS400) - if (!sdhci_msm_hs400_dll_calibration(host)) - msm_host->calibration_done = true; + + if (mmc->ios.timing == MMC_TIMING_MMC_HS400) + sdhci_msm_hs400(host, &mmc->ios); + spin_lock_irq(&host->lock); } From 5574ddcc60aaf71372f4f546acfd988ea433f50d Mon Sep 17 00:00:00 2001 From: Venkat Gopalakrishnan Date: Tue, 10 Jan 2017 12:30:48 +0530 Subject: [PATCH 074/145] mmc: sdhci-msm: Reset vendor specific func register on probe The vendor specific func register doesn't get reset when using the software reset register. The various bootloader's could leave this in an unknown state, hence reset this register to it's power on reset value during probe. Signed-off-by: Venkat Gopalakrishnan Signed-off-by: Ritesh Harjani Tested-by: Jeremy McNicoll Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-msm.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index 5a37c294b17a..a028568081a0 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -69,6 +69,7 @@ #define CORE_DLL_CLOCK_DISABLE BIT(21) #define CORE_VENDOR_SPEC 0x10c +#define CORE_VENDOR_SPEC_POR_VAL 0xa1c #define CORE_CLK_PWRSAVE BIT(1) #define CORE_HC_MCLK_SEL_DFLT (2 << 8) #define CORE_HC_MCLK_SEL_HS400 (3 << 8) @@ -1197,17 +1198,9 @@ static int sdhci_msm_probe(struct platform_device *pdev) goto clk_disable; } - config = readl_relaxed(msm_host->core_mem + CORE_POWER); - config |= CORE_SW_RST; - writel_relaxed(config, msm_host->core_mem + CORE_POWER); - - /* SW reset can take upto 10HCLK + 15MCLK cycles. (min 40us) */ - usleep_range(1000, 5000); - if (readl(msm_host->core_mem + CORE_POWER) & CORE_SW_RST) { - dev_err(&pdev->dev, "Stuck in reset\n"); - ret = -ETIMEDOUT; - goto clk_disable; - } + /* Reset the vendor spec register to power on reset state */ + writel_relaxed(CORE_VENDOR_SPEC_POR_VAL, + host->ioaddr + CORE_VENDOR_SPEC); /* Set HC_MODE_EN bit in HC_MODE register */ writel_relaxed(HC_MODE_EN, (msm_host->core_mem + CORE_HC_MODE)); From 083c9aa0ad480af8a4b4b0f6be3bdca847cc211d Mon Sep 17 00:00:00 2001 From: Subhash Jadavani Date: Tue, 10 Jan 2017 12:30:49 +0530 Subject: [PATCH 075/145] mmc: sdhci-msm: configure CORE_CSR_CDC_DELAY_CFG to recommended value Program CORE_CSR_CDC_DELAY_CFG for hardware recommended 1.25ns delay. We may see data CRC errors if it's programmed for any other delay value. Signed-off-by: Subhash Jadavani Signed-off-by: Ritesh Harjani Tested-by: Jeremy McNicoll Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-msm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index a028568081a0..84d29dd2cc9e 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -679,7 +679,7 @@ static int sdhci_msm_cdclp533_calibration(struct sdhci_host *host) writel_relaxed(0x4, host->ioaddr + CORE_CSR_CDC_CAL_TIMER_CFG1); writel_relaxed(0xCB732020, host->ioaddr + CORE_CSR_CDC_REFCOUNT_CFG); writel_relaxed(0xB19, host->ioaddr + CORE_CSR_CDC_COARSE_CAL_CFG); - writel_relaxed(0x3AC, host->ioaddr + CORE_CSR_CDC_DELAY_CFG); + writel_relaxed(0x4E2, host->ioaddr + CORE_CSR_CDC_DELAY_CFG); writel_relaxed(0x0, host->ioaddr + CORE_CDC_OFFSET_CFG); writel_relaxed(0x16334, host->ioaddr + CORE_CDC_SLAVE_DDA_CFG); From 8a8fa8797cea4e49119e437d254dd59b9ade16fd Mon Sep 17 00:00:00 2001 From: Ritesh Harjani Date: Tue, 10 Jan 2017 12:30:50 +0530 Subject: [PATCH 076/145] mmc: sdhci: Clear SDHCI_HS400_TUNING flag after platform_execute_tuning Clear SDHCI_HS400_TUNING flag after platform_execute_tuning so that platform_execute_tuning may use it if needed. Signed-off-by: Ritesh Harjani Tested-by: Jeremy McNicoll Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index a2efa25c7f3b..6fdd7a70f229 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -2114,7 +2114,6 @@ int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode) spin_lock_irqsave(&host->lock, flags); hs400_tuning = host->flags & SDHCI_HS400_TUNING; - host->flags &= ~SDHCI_HS400_TUNING; if (host->tuning_mode == SDHCI_TUNING_MODE_1) tuning_count = host->tuning_count; @@ -2156,7 +2155,9 @@ int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode) if (host->ops->platform_execute_tuning) { spin_unlock_irqrestore(&host->lock, flags); - return host->ops->platform_execute_tuning(host, opcode); + err = host->ops->platform_execute_tuning(host, opcode); + spin_lock_irqsave(&host->lock, flags); + goto out_unlock; } host->mmc->retune_period = tuning_count; @@ -2167,6 +2168,7 @@ int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode) sdhci_end_tuning(host); out_unlock: + host->flags &= ~SDHCI_HS400_TUNING; spin_unlock_irqrestore(&host->lock, flags); return err; From d7507aa1b988efd788846d62021e581bfca31ace Mon Sep 17 00:00:00 2001 From: Ritesh Harjani Date: Tue, 10 Jan 2017 12:30:51 +0530 Subject: [PATCH 077/145] mmc: sdhci-msm: Make HS400 tuning follow as per recommeneded HW sequence During tuning execution for HS400 mode, HW sequence recommends to select MCLK_SEL/2(0x3) in VENDOR_SPEC & sdhc msm clock at GCC to be 400MHZ (nearest supported clk). Add this change in tuning sequence during HS400 tuning. Signed-off-by: Ritesh Harjani Tested-by: Jeremy McNicoll Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-msm.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index 84d29dd2cc9e..fa9bce3167da 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -151,7 +151,8 @@ static unsigned int msm_get_clock_rate_for_bus_mode(struct sdhci_host *host, */ if (ios.timing == MMC_TIMING_UHS_DDR50 || ios.timing == MMC_TIMING_MMC_DDR52 || - ios.timing == MMC_TIMING_MMC_HS400) + ios.timing == MMC_TIMING_MMC_HS400 || + host->flags & SDHCI_HS400_TUNING) clock *= 2; return clock; } @@ -611,7 +612,8 @@ void sdhci_msm_hc_select_mode(struct sdhci_host *host) { struct mmc_ios ios = host->mmc->ios; - if (ios.timing == MMC_TIMING_MMC_HS400) + if (ios.timing == MMC_TIMING_MMC_HS400 || + host->flags & SDHCI_HS400_TUNING) msm_hc_select_hs400(host); else msm_hc_select_default(host); @@ -831,6 +833,16 @@ static int sdhci_msm_execute_tuning(struct sdhci_host *host, u32 opcode) ios.timing == MMC_TIMING_UHS_SDR104)) return 0; + /* + * For HS400 tuning in HS200 timing requires: + * - select MCLK/2 in VENDOR_SPEC + * - program MCLK to 400MHz (or nearest supported) in GCC + */ + if (host->flags & SDHCI_HS400_TUNING) { + sdhci_msm_hc_select_mode(host); + msm_set_clock_rate_for_bus_mode(host, ios.clock); + } + retry: /* First of all reset the tuning block */ rc = msm_init_cm_dll(host); From 44bf23128f48eabddb7cd6a44b369f0b1e66de97 Mon Sep 17 00:00:00 2001 From: Ritesh Harjani Date: Tue, 10 Jan 2017 12:30:52 +0530 Subject: [PATCH 078/145] mmc: sdhci-msm: Provide enhanced_strobe mode feature support This provides enhanced_strobe mode feature support in sdhci-msm driver. Signed-off-by: Ritesh Harjani Tested-by: Jeremy McNicoll Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-msm.c | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index fa9bce3167da..f9586977a7fa 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -103,6 +103,7 @@ #define CORE_DDR_200_CFG 0x184 #define CORE_CDC_T4_DLY_SEL BIT(0) +#define CORE_CMDIN_RCLK_EN BIT(1) #define CORE_START_CDC_TRAFFIC BIT(6) #define CORE_VENDOR_SPEC3 0x1b0 #define CORE_PWRSAVE_DLL BIT(3) @@ -547,6 +548,7 @@ static void msm_hc_select_hs400(struct sdhci_host *host) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); + struct mmc_ios ios = host->mmc->ios; u32 config, dll_lock; int rc; @@ -560,7 +562,8 @@ static void msm_hc_select_hs400(struct sdhci_host *host) * Select HS400 mode using the HC_SELECT_IN from VENDOR SPEC * register */ - if (msm_host->tuning_done && !msm_host->calibration_done) { + if ((msm_host->tuning_done || ios.enhanced_strobe) && + !msm_host->calibration_done) { config = readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC); config |= CORE_HC_SELECT_IN_HS400; config |= CORE_HC_SELECT_IN_EN; @@ -734,6 +737,7 @@ out: static int sdhci_msm_cm_dll_sdc4_calibration(struct sdhci_host *host) { + struct mmc_host *mmc = host->mmc; u32 dll_status, config; int ret; @@ -748,6 +752,12 @@ static int sdhci_msm_cm_dll_sdc4_calibration(struct sdhci_host *host) */ writel_relaxed(DDR_CONFIG_POR_VAL, host->ioaddr + CORE_DDR_CONFIG); + if (mmc->ios.enhanced_strobe) { + config = readl_relaxed(host->ioaddr + CORE_DDR_200_CFG); + config |= CORE_CMDIN_RCLK_EN; + writel_relaxed(config, host->ioaddr + CORE_DDR_200_CFG); + } + config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG_2); config |= CORE_DDR_CAL_EN; writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG_2); @@ -782,6 +792,7 @@ static int sdhci_msm_hs400_dll_calibration(struct sdhci_host *host) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); + struct mmc_host *mmc = host->mmc; int ret; u32 config; @@ -795,14 +806,17 @@ static int sdhci_msm_hs400_dll_calibration(struct sdhci_host *host) if (ret) goto out; - /* Set the selected phase in delay line hw block */ - ret = msm_config_cm_dll_phase(host, msm_host->saved_tuning_phase); - if (ret) - goto out; + if (!mmc->ios.enhanced_strobe) { + /* Set the selected phase in delay line hw block */ + ret = msm_config_cm_dll_phase(host, + msm_host->saved_tuning_phase); + if (ret) + goto out; + config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG); + config |= CORE_CMD_DAT_TRACK_SEL; + writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG); + } - config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG); - config |= CORE_CMD_DAT_TRACK_SEL; - writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG); if (msm_host->use_cdclp533) ret = sdhci_msm_cdclp533_calibration(host); else @@ -899,6 +913,7 @@ retry: /* * sdhci_msm_hs400 - Calibrate the DLL for HS400 bus speed mode operation. + * This needs to be done for both tuning and enhanced_strobe mode. * DLL operation is only needed for clock > 100MHz. For clock <= 100MHz * fixed feedback clock is used. */ @@ -909,7 +924,8 @@ static void sdhci_msm_hs400(struct sdhci_host *host, struct mmc_ios *ios) int ret; if (host->clock > CORE_FREQ_100MHZ && - msm_host->tuning_done && !msm_host->calibration_done) { + (msm_host->tuning_done || ios->enhanced_strobe) && + !msm_host->calibration_done) { ret = sdhci_msm_hs400_dll_calibration(host); if (!ret) msm_host->calibration_done = true; From dfcba5ffca989749d1fc49d5b82a2d007b1295b7 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 17 Jan 2017 21:26:01 +0100 Subject: [PATCH 079/145] mmc: host: tmio: disable clocks when unbinding Create a helper function to disable clocks and use it in remove(), too. Now, clk_summary in debugfs reports the clocks as disabled and unprepared after unbinding. Signed-off-by: Wolfram Sang Reviewed-by: Geert Uytterhoeven Signed-off-by: Ulf Hansson --- drivers/mmc/host/tmio_mmc_pio.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c index 908186adf52d..4a498ae7d6d7 100644 --- a/drivers/mmc/host/tmio_mmc_pio.c +++ b/drivers/mmc/host/tmio_mmc_pio.c @@ -900,6 +900,12 @@ static int tmio_mmc_clk_enable(struct tmio_mmc_host *host) return host->clk_enable(host); } +static void tmio_mmc_clk_disable(struct tmio_mmc_host *host) +{ + if (host->clk_disable) + host->clk_disable(host); +} + static void tmio_mmc_power_on(struct tmio_mmc_host *host, unsigned short vdd) { struct mmc_host *mmc = host->mmc; @@ -1284,6 +1290,8 @@ void tmio_mmc_host_remove(struct tmio_mmc_host *host) pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); + + tmio_mmc_clk_disable(host); } EXPORT_SYMBOL(tmio_mmc_host_remove); @@ -1298,8 +1306,7 @@ int tmio_mmc_host_runtime_suspend(struct device *dev) if (host->clk_cache) tmio_mmc_clk_stop(host); - if (host->clk_disable) - host->clk_disable(host); + tmio_mmc_clk_disable(host); return 0; } From e3fffc1f0b4750a2d6efc9a674b62c58477b8d20 Mon Sep 17 00:00:00 2001 From: Matt Ranostay Date: Mon, 23 Jan 2017 19:08:29 -0800 Subject: [PATCH 080/145] devicetree: document new marvell-8xxx and pwrseq-sd8787 options Cc: Rob Herring Cc: devicetree@vger.kernel.org Signed-off-by: Matt Ranostay Signed-off-by: Ulf Hansson Acked-by: Rob Herring --- .../bindings/mmc/mmc-pwrseq-sd8787.txt | 16 ++++++++++++++++ .../bindings/net/wireless/marvell-8xxx.txt | 7 ++++++- 2 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 Documentation/devicetree/bindings/mmc/mmc-pwrseq-sd8787.txt diff --git a/Documentation/devicetree/bindings/mmc/mmc-pwrseq-sd8787.txt b/Documentation/devicetree/bindings/mmc/mmc-pwrseq-sd8787.txt new file mode 100644 index 000000000000..22e9340e4ba2 --- /dev/null +++ b/Documentation/devicetree/bindings/mmc/mmc-pwrseq-sd8787.txt @@ -0,0 +1,16 @@ +* Marvell SD8787 power sequence provider + +Required properties: +- compatible: must be "mmc-pwrseq-sd8787". +- powerdown-gpios: contains a power down GPIO specifier with the + default active state +- reset-gpios: contains a reset GPIO specifier with the default + active state + +Example: + + wifi_pwrseq: wifi_pwrseq { + compatible = "mmc-pwrseq-sd8787"; + powerdown-gpios = <&twl_gpio 0 GPIO_ACTIVE_LOW>; + reset-gpios = <&twl_gpio 1 GPIO_ACTIVE_LOW>; + } diff --git a/Documentation/devicetree/bindings/net/wireless/marvell-8xxx.txt b/Documentation/devicetree/bindings/net/wireless/marvell-8xxx.txt index 980b16df74c3..0854451ff91d 100644 --- a/Documentation/devicetree/bindings/net/wireless/marvell-8xxx.txt +++ b/Documentation/devicetree/bindings/net/wireless/marvell-8xxx.txt @@ -1,4 +1,4 @@ -Marvell 8897/8997 (sd8897/sd8997/pcie8997) SDIO/PCIE devices +Marvell 8787/8897/8997 (sd8787/sd8897/sd8997/pcie8997) SDIO/PCIE devices ------ This node provides properties for controlling the Marvell SDIO/PCIE wireless device. @@ -8,6 +8,7 @@ connects the device to the system. Required properties: - compatible : should be one of the following: + * "marvell,sd8787" * "marvell,sd8897" * "marvell,sd8997" * "pci11ab,2b42" @@ -34,6 +35,9 @@ Optional properties: so that the wifi chip can wakeup host platform under certain condition. during system resume, the irq will be disabled to make sure unnecessary interrupt is not received. + - vmmc-supply: a phandle of a regulator, supplying VCC to the card + - mmc-pwrseq: phandle to the MMC power sequence node. See "mmc-pwrseq-*" + for documentation of MMC power sequence bindings. Example: @@ -46,6 +50,7 @@ so that firmware can wakeup host using this device side pin. &mmc3 { status = "okay"; vmmc-supply = <&wlan_en_reg>; + mmc-pwrseq = <&wifi_pwrseq>; bus-width = <4>; cap-power-off-card; keep-power-in-suspend; From de19b4c928ce4f2ab88fc49888627313fd2c49e4 Mon Sep 17 00:00:00 2001 From: Matt Ranostay Date: Mon, 23 Jan 2017 19:08:30 -0800 Subject: [PATCH 081/145] mmc: pwrseq: add support for Marvell SD8787 chip Allow power sequencing for the Marvell SD8787 Wifi/BT chip. This can be abstracted to other chipsets if needed in the future. Cc: Tony Lindgren Cc: Ulf Hansson Signed-off-by: Matt Ranostay Signed-off-by: Ulf Hansson --- drivers/mmc/core/Kconfig | 10 +++ drivers/mmc/core/Makefile | 1 + drivers/mmc/core/pwrseq_sd8787.c | 117 +++++++++++++++++++++++++++++++ 3 files changed, 128 insertions(+) create mode 100644 drivers/mmc/core/pwrseq_sd8787.c diff --git a/drivers/mmc/core/Kconfig b/drivers/mmc/core/Kconfig index cdfa8520a4b1..fc1ecdaaa9ca 100644 --- a/drivers/mmc/core/Kconfig +++ b/drivers/mmc/core/Kconfig @@ -12,6 +12,16 @@ config PWRSEQ_EMMC This driver can also be built as a module. If so, the module will be called pwrseq_emmc. +config PWRSEQ_SD8787 + tristate "HW reset support for SD8787 BT + Wifi module" + depends on OF && (MWIFIEX || BT_MRVL_SDIO) + help + This selects hardware reset support for the SD8787 BT + Wifi + module. By default this option is set to n. + + This driver can also be built as a module. If so, the module + will be called pwrseq_sd8787. + config PWRSEQ_SIMPLE tristate "Simple HW reset support for MMC" default y diff --git a/drivers/mmc/core/Makefile b/drivers/mmc/core/Makefile index b2a257dc644f..0f81464fa824 100644 --- a/drivers/mmc/core/Makefile +++ b/drivers/mmc/core/Makefile @@ -10,6 +10,7 @@ mmc_core-y := core.o bus.o host.o \ quirks.o slot-gpio.o mmc_core-$(CONFIG_OF) += pwrseq.o obj-$(CONFIG_PWRSEQ_SIMPLE) += pwrseq_simple.o +obj-$(CONFIG_PWRSEQ_SD8787) += pwrseq_sd8787.o obj-$(CONFIG_PWRSEQ_EMMC) += pwrseq_emmc.o mmc_core-$(CONFIG_DEBUG_FS) += debugfs.o obj-$(CONFIG_MMC_BLOCK) += mmc_block.o diff --git a/drivers/mmc/core/pwrseq_sd8787.c b/drivers/mmc/core/pwrseq_sd8787.c new file mode 100644 index 000000000000..1a21e14458d3 --- /dev/null +++ b/drivers/mmc/core/pwrseq_sd8787.c @@ -0,0 +1,117 @@ +/* + * pwrseq_sd8787.c - power sequence support for Marvell SD8787 BT + Wifi chip + * + * Copyright (C) 2016 Matt Ranostay + * + * Based on the original work pwrseq_simple.c + * Copyright (C) 2014 Linaro Ltd + * Author: Ulf Hansson + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "pwrseq.h" + +struct mmc_pwrseq_sd8787 { + struct mmc_pwrseq pwrseq; + struct gpio_desc *reset_gpio; + struct gpio_desc *pwrdn_gpio; +}; + +#define to_pwrseq_sd8787(p) container_of(p, struct mmc_pwrseq_sd8787, pwrseq) + +static void mmc_pwrseq_sd8787_pre_power_on(struct mmc_host *host) +{ + struct mmc_pwrseq_sd8787 *pwrseq = to_pwrseq_sd8787(host->pwrseq); + + gpiod_set_value_cansleep(pwrseq->reset_gpio, 1); + + msleep(300); + gpiod_set_value_cansleep(pwrseq->pwrdn_gpio, 1); +} + +static void mmc_pwrseq_sd8787_power_off(struct mmc_host *host) +{ + struct mmc_pwrseq_sd8787 *pwrseq = to_pwrseq_sd8787(host->pwrseq); + + gpiod_set_value_cansleep(pwrseq->pwrdn_gpio, 0); + gpiod_set_value_cansleep(pwrseq->reset_gpio, 0); +} + +static const struct mmc_pwrseq_ops mmc_pwrseq_sd8787_ops = { + .pre_power_on = mmc_pwrseq_sd8787_pre_power_on, + .power_off = mmc_pwrseq_sd8787_power_off, +}; + +static const struct of_device_id mmc_pwrseq_sd8787_of_match[] = { + { .compatible = "mmc-pwrseq-sd8787",}, + {/* sentinel */}, +}; +MODULE_DEVICE_TABLE(of, mmc_pwrseq_sd8787_of_match); + +static int mmc_pwrseq_sd8787_probe(struct platform_device *pdev) +{ + struct mmc_pwrseq_sd8787 *pwrseq; + struct device *dev = &pdev->dev; + + pwrseq = devm_kzalloc(dev, sizeof(*pwrseq), GFP_KERNEL); + if (!pwrseq) + return -ENOMEM; + + pwrseq->pwrdn_gpio = devm_gpiod_get(dev, "powerdown", GPIOD_OUT_LOW); + if (IS_ERR(pwrseq->pwrdn_gpio)) + return PTR_ERR(pwrseq->pwrdn_gpio); + + pwrseq->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(pwrseq->reset_gpio)) + return PTR_ERR(pwrseq->reset_gpio); + + pwrseq->pwrseq.dev = dev; + pwrseq->pwrseq.ops = &mmc_pwrseq_sd8787_ops; + pwrseq->pwrseq.owner = THIS_MODULE; + platform_set_drvdata(pdev, pwrseq); + + return mmc_pwrseq_register(&pwrseq->pwrseq); +} + +static int mmc_pwrseq_sd8787_remove(struct platform_device *pdev) +{ + struct mmc_pwrseq_sd8787 *pwrseq = platform_get_drvdata(pdev); + + mmc_pwrseq_unregister(&pwrseq->pwrseq); + + return 0; +} + +static struct platform_driver mmc_pwrseq_sd8787_driver = { + .probe = mmc_pwrseq_sd8787_probe, + .remove = mmc_pwrseq_sd8787_remove, + .driver = { + .name = "pwrseq_sd8787", + .of_match_table = mmc_pwrseq_sd8787_of_match, + }, +}; + +module_platform_driver(mmc_pwrseq_sd8787_driver); +MODULE_LICENSE("GPL v2"); From e4f38eb18aedd098b3019e82df07f583a5cbcc58 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 19 Jan 2017 21:07:16 +0100 Subject: [PATCH 082/145] mmc: host: tmio: refactor calls to sdio irq tmio_mmc_sdio_irq() is not used as a seperate irq handler anymore, so we can make it similar to the other irq helper functions, namely: * only give the host as argument function which is what it really needs * prefix function name with __ Signed-off-by: Wolfram Sang Acked-by: Simon Horman Signed-off-by: Ulf Hansson --- drivers/mmc/host/tmio_mmc_pio.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c index 4a498ae7d6d7..7cbfec7a5d94 100644 --- a/drivers/mmc/host/tmio_mmc_pio.c +++ b/drivers/mmc/host/tmio_mmc_pio.c @@ -709,9 +709,8 @@ static bool __tmio_mmc_sdcard_irq(struct tmio_mmc_host *host, return false; } -static void tmio_mmc_sdio_irq(int irq, void *devid) +static void __tmio_mmc_sdio_irq(struct tmio_mmc_host *host) { - struct tmio_mmc_host *host = devid; struct mmc_host *mmc = host->mmc; struct tmio_mmc_data *pdata = host->pdata; unsigned int ireg, status; @@ -752,7 +751,7 @@ irqreturn_t tmio_mmc_irq(int irq, void *devid) if (__tmio_mmc_sdcard_irq(host, ireg, status)) return IRQ_HANDLED; - tmio_mmc_sdio_irq(irq, devid); + __tmio_mmc_sdio_irq(host); return IRQ_HANDLED; } From 20dd03734cac41a0545dd24f5e81d8ff0c80874b Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 19 Jan 2017 21:07:17 +0100 Subject: [PATCH 083/145] mmc: host: tmio: SDIO_STATUS_QUIRK is rather SDIO_STATUS_SETBITS QUIRK sounds like there is something wrong, but actually there are just some bits which need to be 1. Rename it to be more clear. Signed-off-by: Wolfram Sang Signed-off-by: Ulf Hansson --- drivers/mmc/host/sh_mobile_sdhi.c | 6 ++---- drivers/mmc/host/tmio_mmc_pio.c | 2 +- include/linux/mfd/tmio.h | 6 ++---- 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/sh_mobile_sdhi.c index 59db14b4827c..8bebf35c7576 100644 --- a/drivers/mmc/host/sh_mobile_sdhi.c +++ b/drivers/mmc/host/sh_mobile_sdhi.c @@ -641,10 +641,8 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev) */ mmc_data->flags |= TMIO_MMC_HAVE_CMD12_CTRL; - /* - * All SDHI need SDIO_INFO1 reserved bit - */ - mmc_data->flags |= TMIO_MMC_SDIO_STATUS_QUIRK; + /* 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); if (ret < 0) diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c index 7cbfec7a5d94..6e1acb628edc 100644 --- a/drivers/mmc/host/tmio_mmc_pio.c +++ b/drivers/mmc/host/tmio_mmc_pio.c @@ -723,7 +723,7 @@ static void __tmio_mmc_sdio_irq(struct tmio_mmc_host *host) ireg = status & TMIO_SDIO_MASK_ALL & ~host->sdio_irq_mask; sdio_status = status & ~TMIO_SDIO_MASK_ALL; - if (pdata->flags & TMIO_MMC_SDIO_STATUS_QUIRK) + if (pdata->flags & TMIO_MMC_SDIO_STATUS_SETBITS) sdio_status |= 6; sd_ctrl_write16(host, CTL_SDIO_STATUS, sdio_status); diff --git a/include/linux/mfd/tmio.h b/include/linux/mfd/tmio.h index fba44abd05ba..a1520d88ebf3 100644 --- a/include/linux/mfd/tmio.h +++ b/include/linux/mfd/tmio.h @@ -94,10 +94,8 @@ */ #define TMIO_MMC_HAVE_CMD12_CTRL (1 << 7) -/* - * Some controllers needs to set 1 on SDIO status reserved bits - */ -#define TMIO_MMC_SDIO_STATUS_QUIRK (1 << 8) +/* Controller has some SDIO status bits which must be 1 */ +#define TMIO_MMC_SDIO_STATUS_SETBITS (1 << 8) /* * Some controllers have a 32-bit wide data port register From ee28981535f4261ed5d127ddf4d1a3f8778f520d Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 19 Jan 2017 21:07:18 +0100 Subject: [PATCH 084/145] mmc: tmio: discard obsolete SDIO irqs before enabling irqs Before enabling SDIO irqs, clear the status bit, so we discard old and stale interrupts. Needed to get two wireless cards working. Use the newly introduced macro in all places. Signed-off-by: Wolfram Sang Signed-off-by: Ulf Hansson --- drivers/mmc/host/tmio_mmc.h | 2 ++ drivers/mmc/host/tmio_mmc_pio.c | 13 +++++++++++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h index 9b2284483cdd..2b349d48fb9a 100644 --- a/drivers/mmc/host/tmio_mmc.h +++ b/drivers/mmc/host/tmio_mmc.h @@ -91,6 +91,8 @@ #define TMIO_SDIO_STAT_EXWT 0x8000 #define TMIO_SDIO_MASK_ALL 0xc007 +#define TMIO_SDIO_SETBITS_MASK 0x0006 + /* Define some IRQ masks */ /* This is the mask used at reset by the chip */ #define TMIO_MASK_ALL 0x837f031d diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c index 6e1acb628edc..6b789a739d4d 100644 --- a/drivers/mmc/host/tmio_mmc_pio.c +++ b/drivers/mmc/host/tmio_mmc_pio.c @@ -134,12 +134,21 @@ static void tmio_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable) struct tmio_mmc_host *host = mmc_priv(mmc); if (enable && !host->sdio_irq_enabled) { + u16 sdio_status; + /* Keep device active while SDIO irq is enabled */ pm_runtime_get_sync(mmc_dev(mmc)); - host->sdio_irq_enabled = true; + host->sdio_irq_enabled = true; host->sdio_irq_mask = TMIO_SDIO_MASK_ALL & ~TMIO_SDIO_STAT_IOIRQ; + + /* Clear obsolete interrupts before enabling */ + sdio_status = sd_ctrl_read16(host, CTL_SDIO_STATUS) & ~TMIO_SDIO_MASK_ALL; + if (host->pdata->flags & TMIO_MMC_SDIO_STATUS_SETBITS) + sdio_status |= TMIO_SDIO_SETBITS_MASK; + sd_ctrl_write16(host, CTL_SDIO_STATUS, sdio_status); + sd_ctrl_write16(host, CTL_SDIO_IRQ_MASK, host->sdio_irq_mask); } else if (!enable && host->sdio_irq_enabled) { host->sdio_irq_mask = TMIO_SDIO_MASK_ALL; @@ -724,7 +733,7 @@ static void __tmio_mmc_sdio_irq(struct tmio_mmc_host *host) sdio_status = status & ~TMIO_SDIO_MASK_ALL; if (pdata->flags & TMIO_MMC_SDIO_STATUS_SETBITS) - sdio_status |= 6; + sdio_status |= TMIO_SDIO_SETBITS_MASK; sd_ctrl_write16(host, CTL_SDIO_STATUS, sdio_status); From 57f8324501d9a810f15dde9f2d6873e788afc98d Mon Sep 17 00:00:00 2001 From: Jaehoon Chung Date: Tue, 24 Jan 2017 18:27:27 +0900 Subject: [PATCH 085/145] mmc: sdhci-s3c: remove the sdhci-s3c-regs header file Remove the sdhci-s3c-regs.h file. Instead, it located those defined values into sdhci-s3c.c. Signed-off-by: Jaehoon Chung Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-s3c-regs.h | 87 ------------------------------- drivers/mmc/host/sdhci-s3c.c | 70 ++++++++++++++++++++++++- 2 files changed, 69 insertions(+), 88 deletions(-) delete mode 100644 drivers/mmc/host/sdhci-s3c-regs.h diff --git a/drivers/mmc/host/sdhci-s3c-regs.h b/drivers/mmc/host/sdhci-s3c-regs.h deleted file mode 100644 index e34049ad44cc..000000000000 --- a/drivers/mmc/host/sdhci-s3c-regs.h +++ /dev/null @@ -1,87 +0,0 @@ -/* linux/arch/arm/plat-s3c/include/plat/regs-sdhci.h - * - * Copyright 2008 Openmoko, Inc. - * Copyright 2008 Simtec Electronics - * http://armlinux.simtec.co.uk/ - * Ben Dooks - * - * S3C Platform - SDHCI (HSMMC) register definitions - * - * 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 __PLAT_S3C_SDHCI_REGS_H -#define __PLAT_S3C_SDHCI_REGS_H __FILE__ - -#define S3C_SDHCI_CONTROL2 (0x80) -#define S3C_SDHCI_CONTROL3 (0x84) -#define S3C64XX_SDHCI_CONTROL4 (0x8C) - -#define S3C64XX_SDHCI_CTRL2_ENSTAASYNCCLR (1 << 31) -#define S3C64XX_SDHCI_CTRL2_ENCMDCNFMSK (1 << 30) -#define S3C_SDHCI_CTRL2_CDINVRXD3 (1 << 29) -#define S3C_SDHCI_CTRL2_SLCARDOUT (1 << 28) - -#define S3C_SDHCI_CTRL2_FLTCLKSEL_MASK (0xf << 24) -#define S3C_SDHCI_CTRL2_FLTCLKSEL_SHIFT (24) -#define S3C_SDHCI_CTRL2_FLTCLKSEL(_x) ((_x) << 24) - -#define S3C_SDHCI_CTRL2_LVLDAT_MASK (0xff << 16) -#define S3C_SDHCI_CTRL2_LVLDAT_SHIFT (16) -#define S3C_SDHCI_CTRL2_LVLDAT(_x) ((_x) << 16) - -#define S3C_SDHCI_CTRL2_ENFBCLKTX (1 << 15) -#define S3C_SDHCI_CTRL2_ENFBCLKRX (1 << 14) -#define S3C_SDHCI_CTRL2_SDCDSEL (1 << 13) -#define S3C_SDHCI_CTRL2_SDSIGPC (1 << 12) -#define S3C_SDHCI_CTRL2_ENBUSYCHKTXSTART (1 << 11) - -#define S3C_SDHCI_CTRL2_DFCNT_MASK (0x3 << 9) -#define S3C_SDHCI_CTRL2_DFCNT_SHIFT (9) -#define S3C_SDHCI_CTRL2_DFCNT_NONE (0x0 << 9) -#define S3C_SDHCI_CTRL2_DFCNT_4SDCLK (0x1 << 9) -#define S3C_SDHCI_CTRL2_DFCNT_16SDCLK (0x2 << 9) -#define S3C_SDHCI_CTRL2_DFCNT_64SDCLK (0x3 << 9) - -#define S3C_SDHCI_CTRL2_ENCLKOUTHOLD (1 << 8) -#define S3C_SDHCI_CTRL2_RWAITMODE (1 << 7) -#define S3C_SDHCI_CTRL2_DISBUFRD (1 << 6) -#define S3C_SDHCI_CTRL2_SELBASECLK_MASK (0x3 << 4) -#define S3C_SDHCI_CTRL2_SELBASECLK_SHIFT (4) -#define S3C_SDHCI_CTRL2_PWRSYNC (1 << 3) -#define S3C_SDHCI_CTRL2_ENCLKOUTMSKCON (1 << 1) -#define S3C_SDHCI_CTRL2_HWINITFIN (1 << 0) - -#define S3C_SDHCI_CTRL3_FCSEL3 (1 << 31) -#define S3C_SDHCI_CTRL3_FCSEL2 (1 << 23) -#define S3C_SDHCI_CTRL3_FCSEL1 (1 << 15) -#define S3C_SDHCI_CTRL3_FCSEL0 (1 << 7) - -#define S3C_SDHCI_CTRL3_FIA3_MASK (0x7f << 24) -#define S3C_SDHCI_CTRL3_FIA3_SHIFT (24) -#define S3C_SDHCI_CTRL3_FIA3(_x) ((_x) << 24) - -#define S3C_SDHCI_CTRL3_FIA2_MASK (0x7f << 16) -#define S3C_SDHCI_CTRL3_FIA2_SHIFT (16) -#define S3C_SDHCI_CTRL3_FIA2(_x) ((_x) << 16) - -#define S3C_SDHCI_CTRL3_FIA1_MASK (0x7f << 8) -#define S3C_SDHCI_CTRL3_FIA1_SHIFT (8) -#define S3C_SDHCI_CTRL3_FIA1(_x) ((_x) << 8) - -#define S3C_SDHCI_CTRL3_FIA0_MASK (0x7f << 0) -#define S3C_SDHCI_CTRL3_FIA0_SHIFT (0) -#define S3C_SDHCI_CTRL3_FIA0(_x) ((_x) << 0) - -#define S3C64XX_SDHCI_CONTROL4_DRIVE_MASK (0x3 << 16) -#define S3C64XX_SDHCI_CONTROL4_DRIVE_SHIFT (16) -#define S3C64XX_SDHCI_CONTROL4_DRIVE_2mA (0x0 << 16) -#define S3C64XX_SDHCI_CONTROL4_DRIVE_4mA (0x1 << 16) -#define S3C64XX_SDHCI_CONTROL4_DRIVE_7mA (0x2 << 16) -#define S3C64XX_SDHCI_CONTROL4_DRIVE_9mA (0x3 << 16) - -#define S3C64XX_SDHCI_CONTROL4_BUSY (1) - -#endif /* __PLAT_S3C_SDHCI_REGS_H */ diff --git a/drivers/mmc/host/sdhci-s3c.c b/drivers/mmc/host/sdhci-s3c.c index de219ca7ea7c..7a230a1e10aa 100644 --- a/drivers/mmc/host/sdhci-s3c.c +++ b/drivers/mmc/host/sdhci-s3c.c @@ -29,11 +29,79 @@ #include -#include "sdhci-s3c-regs.h" #include "sdhci.h" #define MAX_BUS_CLK (4) +#define S3C_SDHCI_CONTROL2 (0x80) +#define S3C_SDHCI_CONTROL3 (0x84) +#define S3C64XX_SDHCI_CONTROL4 (0x8C) + +#define S3C64XX_SDHCI_CTRL2_ENSTAASYNCCLR (1 << 31) +#define S3C64XX_SDHCI_CTRL2_ENCMDCNFMSK (1 << 30) +#define S3C_SDHCI_CTRL2_CDINVRXD3 (1 << 29) +#define S3C_SDHCI_CTRL2_SLCARDOUT (1 << 28) + +#define S3C_SDHCI_CTRL2_FLTCLKSEL_MASK (0xf << 24) +#define S3C_SDHCI_CTRL2_FLTCLKSEL_SHIFT (24) +#define S3C_SDHCI_CTRL2_FLTCLKSEL(_x) ((_x) << 24) + +#define S3C_SDHCI_CTRL2_LVLDAT_MASK (0xff << 16) +#define S3C_SDHCI_CTRL2_LVLDAT_SHIFT (16) +#define S3C_SDHCI_CTRL2_LVLDAT(_x) ((_x) << 16) + +#define S3C_SDHCI_CTRL2_ENFBCLKTX (1 << 15) +#define S3C_SDHCI_CTRL2_ENFBCLKRX (1 << 14) +#define S3C_SDHCI_CTRL2_SDCDSEL (1 << 13) +#define S3C_SDHCI_CTRL2_SDSIGPC (1 << 12) +#define S3C_SDHCI_CTRL2_ENBUSYCHKTXSTART (1 << 11) + +#define S3C_SDHCI_CTRL2_DFCNT_MASK (0x3 << 9) +#define S3C_SDHCI_CTRL2_DFCNT_SHIFT (9) +#define S3C_SDHCI_CTRL2_DFCNT_NONE (0x0 << 9) +#define S3C_SDHCI_CTRL2_DFCNT_4SDCLK (0x1 << 9) +#define S3C_SDHCI_CTRL2_DFCNT_16SDCLK (0x2 << 9) +#define S3C_SDHCI_CTRL2_DFCNT_64SDCLK (0x3 << 9) + +#define S3C_SDHCI_CTRL2_ENCLKOUTHOLD (1 << 8) +#define S3C_SDHCI_CTRL2_RWAITMODE (1 << 7) +#define S3C_SDHCI_CTRL2_DISBUFRD (1 << 6) +#define S3C_SDHCI_CTRL2_SELBASECLK_MASK (0x3 << 4) +#define S3C_SDHCI_CTRL2_SELBASECLK_SHIFT (4) +#define S3C_SDHCI_CTRL2_PWRSYNC (1 << 3) +#define S3C_SDHCI_CTRL2_ENCLKOUTMSKCON (1 << 1) +#define S3C_SDHCI_CTRL2_HWINITFIN (1 << 0) + +#define S3C_SDHCI_CTRL3_FCSEL3 (1 << 31) +#define S3C_SDHCI_CTRL3_FCSEL2 (1 << 23) +#define S3C_SDHCI_CTRL3_FCSEL1 (1 << 15) +#define S3C_SDHCI_CTRL3_FCSEL0 (1 << 7) + +#define S3C_SDHCI_CTRL3_FIA3_MASK (0x7f << 24) +#define S3C_SDHCI_CTRL3_FIA3_SHIFT (24) +#define S3C_SDHCI_CTRL3_FIA3(_x) ((_x) << 24) + +#define S3C_SDHCI_CTRL3_FIA2_MASK (0x7f << 16) +#define S3C_SDHCI_CTRL3_FIA2_SHIFT (16) +#define S3C_SDHCI_CTRL3_FIA2(_x) ((_x) << 16) + +#define S3C_SDHCI_CTRL3_FIA1_MASK (0x7f << 8) +#define S3C_SDHCI_CTRL3_FIA1_SHIFT (8) +#define S3C_SDHCI_CTRL3_FIA1(_x) ((_x) << 8) + +#define S3C_SDHCI_CTRL3_FIA0_MASK (0x7f << 0) +#define S3C_SDHCI_CTRL3_FIA0_SHIFT (0) +#define S3C_SDHCI_CTRL3_FIA0(_x) ((_x) << 0) + +#define S3C64XX_SDHCI_CONTROL4_DRIVE_MASK (0x3 << 16) +#define S3C64XX_SDHCI_CONTROL4_DRIVE_SHIFT (16) +#define S3C64XX_SDHCI_CONTROL4_DRIVE_2mA (0x0 << 16) +#define S3C64XX_SDHCI_CONTROL4_DRIVE_4mA (0x1 << 16) +#define S3C64XX_SDHCI_CONTROL4_DRIVE_7mA (0x2 << 16) +#define S3C64XX_SDHCI_CONTROL4_DRIVE_9mA (0x3 << 16) + +#define S3C64XX_SDHCI_CONTROL4_BUSY (1) + /** * struct sdhci_s3c - S3C SDHCI instance * @host: The SDHCI host created From e64aae82eac5397d9976142b9224d4a41424ee54 Mon Sep 17 00:00:00 2001 From: Jaehoon Chung Date: Tue, 24 Jan 2017 18:27:28 +0900 Subject: [PATCH 086/145] mmc: sdhci-s3c: use the bitops API for bit operation Use the bitops API instead of shifting directly. Signed-off-by: Jaehoon Chung Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-s3c.c | 39 ++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/drivers/mmc/host/sdhci-s3c.c b/drivers/mmc/host/sdhci-s3c.c index 7a230a1e10aa..3e5c83d435ae 100644 --- a/drivers/mmc/host/sdhci-s3c.c +++ b/drivers/mmc/host/sdhci-s3c.c @@ -37,10 +37,10 @@ #define S3C_SDHCI_CONTROL3 (0x84) #define S3C64XX_SDHCI_CONTROL4 (0x8C) -#define S3C64XX_SDHCI_CTRL2_ENSTAASYNCCLR (1 << 31) -#define S3C64XX_SDHCI_CTRL2_ENCMDCNFMSK (1 << 30) -#define S3C_SDHCI_CTRL2_CDINVRXD3 (1 << 29) -#define S3C_SDHCI_CTRL2_SLCARDOUT (1 << 28) +#define S3C64XX_SDHCI_CTRL2_ENSTAASYNCCLR BIT(31) +#define S3C64XX_SDHCI_CTRL2_ENCMDCNFMSK BIT(30) +#define S3C_SDHCI_CTRL2_CDINVRXD3 BIT(29) +#define S3C_SDHCI_CTRL2_SLCARDOUT BIT(28) #define S3C_SDHCI_CTRL2_FLTCLKSEL_MASK (0xf << 24) #define S3C_SDHCI_CTRL2_FLTCLKSEL_SHIFT (24) @@ -50,11 +50,11 @@ #define S3C_SDHCI_CTRL2_LVLDAT_SHIFT (16) #define S3C_SDHCI_CTRL2_LVLDAT(_x) ((_x) << 16) -#define S3C_SDHCI_CTRL2_ENFBCLKTX (1 << 15) -#define S3C_SDHCI_CTRL2_ENFBCLKRX (1 << 14) -#define S3C_SDHCI_CTRL2_SDCDSEL (1 << 13) -#define S3C_SDHCI_CTRL2_SDSIGPC (1 << 12) -#define S3C_SDHCI_CTRL2_ENBUSYCHKTXSTART (1 << 11) +#define S3C_SDHCI_CTRL2_ENFBCLKTX BIT(15) +#define S3C_SDHCI_CTRL2_ENFBCLKRX BIT(14) +#define S3C_SDHCI_CTRL2_SDCDSEL BIT(13) +#define S3C_SDHCI_CTRL2_SDSIGPC BIT(12) +#define S3C_SDHCI_CTRL2_ENBUSYCHKTXSTART BIT(11) #define S3C_SDHCI_CTRL2_DFCNT_MASK (0x3 << 9) #define S3C_SDHCI_CTRL2_DFCNT_SHIFT (9) @@ -63,19 +63,20 @@ #define S3C_SDHCI_CTRL2_DFCNT_16SDCLK (0x2 << 9) #define S3C_SDHCI_CTRL2_DFCNT_64SDCLK (0x3 << 9) -#define S3C_SDHCI_CTRL2_ENCLKOUTHOLD (1 << 8) -#define S3C_SDHCI_CTRL2_RWAITMODE (1 << 7) -#define S3C_SDHCI_CTRL2_DISBUFRD (1 << 6) +#define S3C_SDHCI_CTRL2_ENCLKOUTHOLD BIT(8) +#define S3C_SDHCI_CTRL2_RWAITMODE BIT(7) +#define S3C_SDHCI_CTRL2_DISBUFRD BIT(6) + #define S3C_SDHCI_CTRL2_SELBASECLK_MASK (0x3 << 4) #define S3C_SDHCI_CTRL2_SELBASECLK_SHIFT (4) -#define S3C_SDHCI_CTRL2_PWRSYNC (1 << 3) -#define S3C_SDHCI_CTRL2_ENCLKOUTMSKCON (1 << 1) -#define S3C_SDHCI_CTRL2_HWINITFIN (1 << 0) +#define S3C_SDHCI_CTRL2_PWRSYNC BIT(3) +#define S3C_SDHCI_CTRL2_ENCLKOUTMSKCON BIT(1) +#define S3C_SDHCI_CTRL2_HWINITFIN BIT(0) -#define S3C_SDHCI_CTRL3_FCSEL3 (1 << 31) -#define S3C_SDHCI_CTRL3_FCSEL2 (1 << 23) -#define S3C_SDHCI_CTRL3_FCSEL1 (1 << 15) -#define S3C_SDHCI_CTRL3_FCSEL0 (1 << 7) +#define S3C_SDHCI_CTRL3_FCSEL3 BIT(31) +#define S3C_SDHCI_CTRL3_FCSEL2 BIT(23) +#define S3C_SDHCI_CTRL3_FCSEL1 BIT(15) +#define S3C_SDHCI_CTRL3_FCSEL0 BIT(7) #define S3C_SDHCI_CTRL3_FIA3_MASK (0x7f << 24) #define S3C_SDHCI_CTRL3_FIA3_SHIFT (24) From 4e1f780032c56894e8d7b6685b029b718588f483 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 24 Jan 2017 11:17:52 +0100 Subject: [PATCH 087/145] mmc: block: break out mmc_blk_rw_cmd_abort() As a first step toward breaking apart the very complex function mmc_blk_issue_rw_rq() we break out the command abort code. This code assumes "ret" is != 0 and then repeatedly hammers blk_end_request() until the request to the block layer to end the request succeeds. Signed-off-by: Linus Walleij Signed-off-by: Ulf Hansson --- drivers/mmc/core/block.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index 7bd03381810d..14efe92a14ef 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -1598,6 +1598,17 @@ static int mmc_blk_cmd_err(struct mmc_blk_data *md, struct mmc_card *card, return ret; } +static void mmc_blk_rw_cmd_abort(struct mmc_card *card, struct request *req) +{ + int ret = 1; + + if (mmc_card_removed(card)) + req->rq_flags |= RQF_QUIET; + while (ret) + ret = blk_end_request(req, -EIO, + blk_rq_cur_bytes(req)); +} + static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc) { struct mmc_blk_data *md = mq->blkdata; @@ -1737,11 +1748,7 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc) return 1; cmd_abort: - if (mmc_card_removed(card)) - req->rq_flags |= RQF_QUIET; - while (ret) - ret = blk_end_request(req, -EIO, - blk_rq_cur_bytes(req)); + mmc_blk_rw_cmd_abort(card, req); start_new_req: if (rqc) { From efb5a05e70dfa79fe26133be9a239cbca8ea08c3 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 24 Jan 2017 11:17:53 +0100 Subject: [PATCH 088/145] mmc: block: break out mmc_blk_rw_start_new() As a step toward breaking apart the very complex function mmc_blk_issue_rw_rq() we break out the code to start a new request. Signed-off-by: Linus Walleij Signed-off-by: Ulf Hansson --- drivers/mmc/core/block.c | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index 14efe92a14ef..b60d1fb3a07a 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -1609,6 +1609,22 @@ static void mmc_blk_rw_cmd_abort(struct mmc_card *card, struct request *req) blk_rq_cur_bytes(req)); } +static void mmc_blk_rw_start_new(struct mmc_queue *mq, struct mmc_card *card, + struct request *req) +{ + if (!req) + return; + + if (mmc_card_removed(card)) { + req->rq_flags |= RQF_QUIET; + blk_end_request_all(req, -EIO); + } else { + mmc_blk_rw_rq_prep(mq->mqrq_cur, card, 0, mq); + mmc_start_req(card->host, + &mq->mqrq_cur->mmc_active, NULL); + } +} + static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc) { struct mmc_blk_data *md = mq->blkdata; @@ -1751,16 +1767,7 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc) mmc_blk_rw_cmd_abort(card, req); start_new_req: - if (rqc) { - if (mmc_card_removed(card)) { - rqc->rq_flags |= RQF_QUIET; - blk_end_request_all(rqc, -EIO); - } else { - mmc_blk_rw_rq_prep(mq->mqrq_cur, card, 0, mq); - mmc_start_req(card->host, - &mq->mqrq_cur->mmc_active, NULL); - } - } + mmc_blk_rw_start_new(mq, card, rqc); return 0; } From 6fb85d658308952142da6abb4e066dd22dd48c01 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 24 Jan 2017 11:17:54 +0100 Subject: [PATCH 089/145] mmc: block: do not assign mq_rq when aborting command The code in mmc_blk_issue_rq_rq() aborts a command if the request is not properly aligned on large sectors. As part of the path jumping out, it assigns the local variable mq_rq reflecting a MMC queue request to the current MMC queue request, which is confusing since the variable is not used after this jump. Signed-off-by: Linus Walleij Signed-off-by: Ulf Hansson --- drivers/mmc/core/block.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index b60d1fb3a07a..13e6fe060f26 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -1649,7 +1649,6 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc) !IS_ALIGNED(blk_rq_sectors(rqc), 8)) { pr_err("%s: Transfer size is not 4KB sector size aligned\n", rqc->rq_disk->disk_name); - mq_rq = mq->mqrq_cur; req = rqc; rqc = NULL; goto cmd_abort; From da0dbaffe354043bb0cd61c00c650c819d104b29 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 24 Jan 2017 11:17:55 +0100 Subject: [PATCH 090/145] mmc: block: inline command abortions Setting rqc to NULL followed by a goto to cmd_abort is just a way to do unconditional abort without starting any new command. Inline the calls to mmc_blk_rw_cmd_abort() and return immediately in those cases. Add some comments to the code flow so it is clear that this is where the asynchronous requests come back in and the result of them gets handled. Signed-off-by: Linus Walleij Signed-off-by: Ulf Hansson --- drivers/mmc/core/block.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index 13e6fe060f26..ea86a233cea4 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -1649,9 +1649,8 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc) !IS_ALIGNED(blk_rq_sectors(rqc), 8)) { pr_err("%s: Transfer size is not 4KB sector size aligned\n", rqc->rq_disk->disk_name); - req = rqc; - rqc = NULL; - goto cmd_abort; + mmc_blk_rw_cmd_abort(card, rqc); + return 0; } mmc_blk_rw_rq_prep(mq->mqrq_cur, card, 0, mq); @@ -1660,11 +1659,20 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc) areq = NULL; areq = mmc_start_req(card->host, areq, &status); if (!areq) { + /* + * We have just put the first request into the pipeline + * and there is nothing more to do until it is + * complete. + */ if (status == MMC_BLK_NEW_REQUEST) mq->flags |= MMC_QUEUE_NEW_REQUEST; return 0; } + /* + * An asynchronous request has been completed and we proceed + * to handle the result of it. + */ mq_rq = container_of(areq, struct mmc_queue_req, mmc_active); brq = &mq_rq->brq; req = mq_rq->req; @@ -1691,8 +1699,8 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc) pr_err("%s BUG rq_tot %d d_xfer %d\n", __func__, blk_rq_bytes(req), brq->data.bytes_xfered); - rqc = NULL; - goto cmd_abort; + mmc_blk_rw_cmd_abort(card, req); + return 0; } break; case MMC_BLK_CMD_ERR: From 7d552a48089b6a24b65abe9c49a184bae8364abe Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 24 Jan 2017 11:17:56 +0100 Subject: [PATCH 091/145] mmc: block: introduce new_areq and old_areq Recycling the same variable in an x=x+1 fashion may seem clever here but it makes the code terse and hard to follow for humans. Introduce a new_areq and old_areq variable so we see what is going on. Signed-off-by: Linus Walleij Signed-off-by: Ulf Hansson --- drivers/mmc/core/block.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index ea86a233cea4..fc71b6256d35 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -1634,7 +1634,8 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc) enum mmc_blk_status status; struct mmc_queue_req *mq_rq; struct request *req; - struct mmc_async_req *areq; + struct mmc_async_req *new_areq; + struct mmc_async_req *old_areq; if (!rqc && !mq->mqrq_prev->req) return 0; @@ -1654,11 +1655,12 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc) } mmc_blk_rw_rq_prep(mq->mqrq_cur, card, 0, mq); - areq = &mq->mqrq_cur->mmc_active; + new_areq = &mq->mqrq_cur->mmc_active; } else - areq = NULL; - areq = mmc_start_req(card->host, areq, &status); - if (!areq) { + new_areq = NULL; + + old_areq = mmc_start_req(card->host, new_areq, &status); + if (!old_areq) { /* * We have just put the first request into the pipeline * and there is nothing more to do until it is @@ -1673,7 +1675,7 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc) * An asynchronous request has been completed and we proceed * to handle the result of it. */ - mq_rq = container_of(areq, struct mmc_queue_req, mmc_active); + mq_rq = container_of(old_areq, struct mmc_queue_req, mmc_active); brq = &mq_rq->brq; req = mq_rq->req; type = rq_data_dir(req) == READ ? MMC_BLK_READ : MMC_BLK_WRITE; From df0615889651321712b0b429780617d35c1ed963 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 24 Jan 2017 11:17:57 +0100 Subject: [PATCH 092/145] mmc: block: stop passing around pointless return values The mmc_blk_issue_rq() function is called in exactly one place in queue.c and there the return value is ignored. So the functions called from that function that also meticulously return 0/1 do so for no good reason. Error reporting on the asynchronous requests are done upward to the block layer when the requests are eventually completed or fail, which may happen during the flow of the mmc_blk_issue_* functions directly (for "special commands") or later, when an asynchronous read/write request is completed. The issuing functions do not give rise to errors on their own, and there is nothing to return back to the caller in queue.c. Drop all return values and make the function return void. Signed-off-by: Linus Walleij Signed-off-by: Ulf Hansson --- drivers/mmc/core/block.c | 38 ++++++++++++++------------------------ drivers/mmc/core/block.h | 2 +- 2 files changed, 15 insertions(+), 25 deletions(-) diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index fc71b6256d35..6c8be1a80551 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -1149,7 +1149,7 @@ int mmc_access_rpmb(struct mmc_queue *mq) return false; } -static int mmc_blk_issue_discard_rq(struct mmc_queue *mq, struct request *req) +static void mmc_blk_issue_discard_rq(struct mmc_queue *mq, struct request *req) { struct mmc_blk_data *md = mq->blkdata; struct mmc_card *card = md->queue.card; @@ -1187,11 +1187,9 @@ static int mmc_blk_issue_discard_rq(struct mmc_queue *mq, struct request *req) mmc_blk_reset_success(md, type); fail: blk_end_request(req, err, blk_rq_bytes(req)); - - return err ? 0 : 1; } -static int mmc_blk_issue_secdiscard_rq(struct mmc_queue *mq, +static void mmc_blk_issue_secdiscard_rq(struct mmc_queue *mq, struct request *req) { struct mmc_blk_data *md = mq->blkdata; @@ -1254,11 +1252,9 @@ out_retry: mmc_blk_reset_success(md, type); out: blk_end_request(req, err, blk_rq_bytes(req)); - - return err ? 0 : 1; } -static int mmc_blk_issue_flush(struct mmc_queue *mq, struct request *req) +static void mmc_blk_issue_flush(struct mmc_queue *mq, struct request *req) { struct mmc_blk_data *md = mq->blkdata; struct mmc_card *card = md->queue.card; @@ -1269,8 +1265,6 @@ static int mmc_blk_issue_flush(struct mmc_queue *mq, struct request *req) ret = -EIO; blk_end_request_all(req, ret); - - return ret ? 0 : 1; } /* @@ -1625,7 +1619,7 @@ static void mmc_blk_rw_start_new(struct mmc_queue *mq, struct mmc_card *card, } } -static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc) +static void mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc) { struct mmc_blk_data *md = mq->blkdata; struct mmc_card *card = md->queue.card; @@ -1638,7 +1632,7 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc) struct mmc_async_req *old_areq; if (!rqc && !mq->mqrq_prev->req) - return 0; + return; do { if (rqc) { @@ -1651,7 +1645,7 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc) pr_err("%s: Transfer size is not 4KB sector size aligned\n", rqc->rq_disk->disk_name); mmc_blk_rw_cmd_abort(card, rqc); - return 0; + return; } mmc_blk_rw_rq_prep(mq->mqrq_cur, card, 0, mq); @@ -1668,7 +1662,7 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc) */ if (status == MMC_BLK_NEW_REQUEST) mq->flags |= MMC_QUEUE_NEW_REQUEST; - return 0; + return; } /* @@ -1702,7 +1696,7 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc) __func__, blk_rq_bytes(req), brq->data.bytes_xfered); mmc_blk_rw_cmd_abort(card, req); - return 0; + return; } break; case MMC_BLK_CMD_ERR: @@ -1770,18 +1764,16 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc) } } while (ret); - return 1; + return; cmd_abort: mmc_blk_rw_cmd_abort(card, req); start_new_req: mmc_blk_rw_start_new(mq, card, rqc); - - return 0; } -int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) +void mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) { int ret; struct mmc_blk_data *md = mq->blkdata; @@ -1797,7 +1789,6 @@ int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) if (req) { blk_end_request_all(req, -EIO); } - ret = 0; goto out; } @@ -1806,19 +1797,19 @@ int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) /* complete ongoing async transfer before issuing discard */ if (card->host->areq) mmc_blk_issue_rw_rq(mq, NULL); - ret = mmc_blk_issue_discard_rq(mq, req); + 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 (card->host->areq) mmc_blk_issue_rw_rq(mq, NULL); - ret = mmc_blk_issue_secdiscard_rq(mq, req); + mmc_blk_issue_secdiscard_rq(mq, req); } else if (req && req_op(req) == REQ_OP_FLUSH) { /* complete ongoing async transfer before issuing flush */ if (card->host->areq) mmc_blk_issue_rw_rq(mq, NULL); - ret = mmc_blk_issue_flush(mq, req); + mmc_blk_issue_flush(mq, req); } else { - ret = mmc_blk_issue_rw_rq(mq, req); + mmc_blk_issue_rw_rq(mq, req); } out: @@ -1830,7 +1821,6 @@ out: * the 'mmc_blk_issue_rq' with 'mqrq_prev->req'. */ mmc_put_card(card); - return ret; } static inline int mmc_blk_readonly(struct mmc_card *card) diff --git a/drivers/mmc/core/block.h b/drivers/mmc/core/block.h index 00b7483f2d6e..860ca7c8df86 100644 --- a/drivers/mmc/core/block.h +++ b/drivers/mmc/core/block.h @@ -4,6 +4,6 @@ struct mmc_queue; struct request; -int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req); +void mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req); #endif From dc012058d79aa781d74988c83e29a7398ad1e47b Mon Sep 17 00:00:00 2001 From: Kevin Hilman Date: Wed, 25 Jan 2017 16:01:39 -0800 Subject: [PATCH 093/145] mmc: meson: cleanup stray debug messages Cleanup some debug prints that cause needless noise during normal usage. Signed-off-by: Kevin Hilman Signed-off-by: Ulf Hansson --- drivers/mmc/host/meson-gx-mmc.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/mmc/host/meson-gx-mmc.c b/drivers/mmc/host/meson-gx-mmc.c index bf19d03ce2ee..5eca88bcd562 100644 --- a/drivers/mmc/host/meson-gx-mmc.c +++ b/drivers/mmc/host/meson-gx-mmc.c @@ -481,9 +481,9 @@ static void meson_mmc_start_cmd(struct mmc_host *mmc, struct mmc_command *cmd) blk_len = cfg & (CFG_BLK_LEN_MASK << CFG_BLK_LEN_SHIFT); blk_len >>= CFG_BLK_LEN_SHIFT; if (blk_len != ilog2(cmd->data->blksz)) { - dev_warn(host->dev, "%s: update blk_len %d -> %d\n", + dev_dbg(host->dev, "%s: update blk_len %d -> %d\n", __func__, blk_len, - ilog2(cmd->data->blksz)); + ilog2(cmd->data->blksz)); blk_len = ilog2(cmd->data->blksz); cfg &= ~(CFG_BLK_LEN_MASK << CFG_BLK_LEN_SHIFT); cfg |= blk_len << CFG_BLK_LEN_SHIFT; @@ -743,7 +743,8 @@ static int meson_mmc_probe(struct platform_device *pdev) ret = mmc_of_parse(mmc); if (ret) { - dev_warn(&pdev->dev, "error parsing DT: %d\n", ret); + if (ret != -EPROBE_DEFER) + dev_warn(&pdev->dev, "error parsing DT: %d\n", ret); goto free_host; } From 34a1654706c6cc20e7a9077063b307afe28ec66c Mon Sep 17 00:00:00 2001 From: Chris Brandt Date: Wed, 25 Jan 2017 15:28:08 -0500 Subject: [PATCH 094/145] mmc: sh_mobile_sdhi: add support for 2 clocks Some controllers have 2 clock sources instead of 1. The 2nd clock is for the internal card detect logic and must be enabled/disabled along with the main core clock for proper operation. Signed-off-by: Chris Brandt Signed-off-by: Ulf Hansson Reviewed-by: Wolfram Sang --- drivers/mmc/host/sh_mobile_sdhi.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/sh_mobile_sdhi.c index 8bebf35c7576..bc6be0dbea39 100644 --- a/drivers/mmc/host/sh_mobile_sdhi.c +++ b/drivers/mmc/host/sh_mobile_sdhi.c @@ -143,6 +143,7 @@ MODULE_DEVICE_TABLE(of, sh_mobile_sdhi_of_match); struct sh_mobile_sdhi { struct clk *clk; + struct clk *clk_cd; struct tmio_mmc_data mmc_data; struct tmio_mmc_dma dma_priv; struct pinctrl *pinctrl; @@ -190,6 +191,12 @@ static int sh_mobile_sdhi_clk_enable(struct tmio_mmc_host *host) if (ret < 0) return ret; + ret = clk_prepare_enable(priv->clk_cd); + if (ret < 0) { + clk_disable_unprepare(priv->clk); + return ret; + } + /* * The clock driver may not know what maximum frequency * actually works, so it should be set with the max-frequency @@ -255,6 +262,7 @@ static void sh_mobile_sdhi_clk_disable(struct tmio_mmc_host *host) struct sh_mobile_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) @@ -572,6 +580,21 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev) goto eprobe; } + /* + * Some controllers provide a 2nd clock just to run the internal card + * detection logic. Unfortunately, the existing driver architecture does + * not support a separation of clocks for runtime PM usage. When + * native hotplug is used, the tmio driver assumes that the core + * must continue to run for card detect to stay active, so we cannot + * disable it. + * Additionally, it is prohibited to supply a clock to the core but not + * to the card detect circuit. That leaves us with if separate clocks + * are presented, we must treat them both as virtually 1 clock. + */ + priv->clk_cd = devm_clk_get(&pdev->dev, "cd"); + if (IS_ERR(priv->clk_cd)) + priv->clk_cd = NULL; + priv->pinctrl = devm_pinctrl_get(&pdev->dev); if (!IS_ERR(priv->pinctrl)) { priv->pins_default = pinctrl_lookup_state(priv->pinctrl, From 62a4cdead56e5715c61aadd41ab66f49bd3170f1 Mon Sep 17 00:00:00 2001 From: Chris Brandt Date: Wed, 25 Jan 2017 15:28:09 -0500 Subject: [PATCH 095/145] mmc: sh_mobile_sdhi: explain clock bindings In the case of a single clock source, you don't need names. However, if the controller has 2 clock sources, you need to name them correctly so the driver can find the 2nd one. The 2nd clock is for the internal card detect logic. Signed-off-by: Chris Brandt Reviewed-by: Geert Uytterhoeven Signed-off-by: Ulf Hansson Reviewed-by: Wolfram Sang Acked-by: Rob Herring --- Documentation/devicetree/bindings/mmc/tmio_mmc.txt | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Documentation/devicetree/bindings/mmc/tmio_mmc.txt b/Documentation/devicetree/bindings/mmc/tmio_mmc.txt index a1650edfd2b7..4fd8b7acc510 100644 --- a/Documentation/devicetree/bindings/mmc/tmio_mmc.txt +++ b/Documentation/devicetree/bindings/mmc/tmio_mmc.txt @@ -25,6 +25,19 @@ Required properties: "renesas,sdhi-r8a7795" - SDHI IP on R8A7795 SoC "renesas,sdhi-r8a7796" - SDHI IP on R8A7796 SoC +- clocks: Most controllers only have 1 clock source per channel. However, on + some variations of this controller, the internal card detection + logic that exists in this controller is sectioned off to be run by a + separate second clock source to allow the main core clock to be turned + off to save power. + If 2 clocks are specified by the hardware, you must name them as + "core" and "cd". If the controller only has 1 clock, naming is not + required. + Below is the number clocks for each supported SoC: + 1: SH73A0, R8A73A4, R8A7740, R8A7778, R8A7779, R8A7790 + R8A7791, R8A7792, R8A7793, R8A7794, R8A7795, R8A7796 + 2: R7S72100 + Optional properties: - toshiba,mmc-wrprotect-disable: write-protect detection is unavailable - pinctrl-names: should be "default", "state_uhs" From a44efa4796249c6d4341935e90e9105d6e1a5f15 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Wed, 25 Jan 2017 10:12:10 +0100 Subject: [PATCH 096/145] mmc: core: Remove redundant code in mmc_set_signal_voltage() The mmc_set_signal_voltage() function is used for SD/SDIO when switching to 1.8V for UHS mode. Therefore let's remove the redundant code dealing with MMC_SIGNAL_VOLTAGE_330. Signed-off-by: Ulf Hansson Reviewed-by: Shawn Lin Tested-by: Jan Glauber Tested-by: Stefan Wahren --- drivers/mmc/core/core.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 8c458255e55a..bb819d49291e 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -1653,13 +1653,6 @@ int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage, u32 ocr) int err = 0; u32 clock; - /* - * Send CMD11 only if the request is to switch the card to - * 1.8V signalling. - */ - if (signal_voltage == MMC_SIGNAL_VOLTAGE_330) - return __mmc_set_signal_voltage(host, signal_voltage); - /* * If we cannot switch voltages, return failure so the caller * can continue without UHS mode From 2ed573b603f78289dd1435c94597aa25a97e2b76 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Wed, 25 Jan 2017 10:25:01 +0100 Subject: [PATCH 097/145] mmc: core: Clarify usage of mmc_set_signal_voltage() The mmc_set_signal_voltage() function is used for SD/SDIO when switching to 1.8V for UHS mode. To clarify this let's do the following changes. - We are always providing MMC_SIGNAL_VOLTAGE_180 as the signal_voltage parameter to the function. Then, let's just remove the parameter as it serves no purpose. - Rename the function to mmc_set_uhs_voltage(). Signed-off-by: Ulf Hansson Reviewed-by: Shawn Lin Tested-by: Jan Glauber Tested-by: Stefan Wahren --- drivers/mmc/core/core.c | 4 ++-- drivers/mmc/core/core.h | 2 +- drivers/mmc/core/sd.c | 3 +-- drivers/mmc/core/sdio.c | 3 +-- 4 files changed, 5 insertions(+), 7 deletions(-) diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index bb819d49291e..82c1a02b9c2a 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -1647,7 +1647,7 @@ int __mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage) } -int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage, u32 ocr) +int mmc_set_uhs_voltage(struct mmc_host *host, u32 ocr) { struct mmc_command cmd = {}; int err = 0; @@ -1691,7 +1691,7 @@ int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage, u32 ocr) host->ios.clock = 0; mmc_set_ios(host); - if (__mmc_set_signal_voltage(host, signal_voltage)) { + if (__mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180)) { /* * Voltages may not have been switched, but we've already * sent CMD11, so a power cycle is required anyway diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h index 8a95c82554be..aee23f54a7ed 100644 --- a/drivers/mmc/core/core.h +++ b/drivers/mmc/core/core.h @@ -48,7 +48,7 @@ void mmc_set_clock(struct mmc_host *host, unsigned int hz); void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode); void mmc_set_bus_width(struct mmc_host *host, unsigned int width); u32 mmc_select_voltage(struct mmc_host *host, u32 ocr); -int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage, u32 ocr); +int mmc_set_uhs_voltage(struct mmc_host *host, u32 ocr); int __mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage); void mmc_set_timing(struct mmc_host *host, unsigned int timing); void mmc_set_driver_type(struct mmc_host *host, unsigned int drv_type); diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index 8b4f13943712..89531b48ae84 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -788,8 +788,7 @@ try_again: */ if (!mmc_host_is_spi(host) && rocr && ((*rocr & 0x41000000) == 0x41000000)) { - err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180, - pocr); + err = mmc_set_uhs_voltage(host, pocr); if (err == -EAGAIN) { retries--; goto try_again; diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index 261c88632c43..a64a8709ec72 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -642,8 +642,7 @@ try_again: * to make sure which speed mode should work. */ if (!powered_resume && (rocr & ocr & R4_18V_PRESENT)) { - err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180, - ocr_card); + err = mmc_set_uhs_voltage(host, ocr_card); if (err == -EAGAIN) { mmc_sdio_resend_if_cond(host, card); retries--; From 4e74b6b3c6e9adfe6a8fdebfc56a6416a996d905 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Wed, 25 Jan 2017 11:12:34 +0100 Subject: [PATCH 098/145] mmc: core: Rename __mmc_set_signal_voltage() to mmc_set_signal_voltage() Earlier the mmc_set_signal_voltage() existed, but since it has been renamed to mmc_set_uhs_voltage(), we can now use that name instead. Signed-off-by: Ulf Hansson Reviewed-by: Shawn Lin Tested-by: Jan Glauber Tested-by: Stefan Wahren --- drivers/mmc/core/core.c | 10 +++++----- drivers/mmc/core/core.h | 2 +- drivers/mmc/core/mmc.c | 16 ++++++++-------- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 82c1a02b9c2a..b20b70fbd50d 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -1631,7 +1631,7 @@ u32 mmc_select_voltage(struct mmc_host *host, u32 ocr) return ocr; } -int __mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage) +int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage) { int err = 0; int old_signal_voltage = host->ios.signal_voltage; @@ -1691,7 +1691,7 @@ int mmc_set_uhs_voltage(struct mmc_host *host, u32 ocr) host->ios.clock = 0; mmc_set_ios(host); - if (__mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180)) { + if (mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180)) { /* * Voltages may not have been switched, but we've already * sent CMD11, so a power cycle is required anyway @@ -1800,11 +1800,11 @@ void mmc_power_up(struct mmc_host *host, u32 ocr) mmc_set_initial_state(host); /* Try to set signal voltage to 3.3V but fall back to 1.8v or 1.2v */ - if (__mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330) == 0) + if (!mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330)) dev_dbg(mmc_dev(host), "Initial signal voltage of 3.3v\n"); - else if (__mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180) == 0) + else if (!mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180)) dev_dbg(mmc_dev(host), "Initial signal voltage of 1.8v\n"); - else if (__mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120) == 0) + else if (!mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120)) dev_dbg(mmc_dev(host), "Initial signal voltage of 1.2v\n"); /* diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h index aee23f54a7ed..55f543fd37c4 100644 --- a/drivers/mmc/core/core.h +++ b/drivers/mmc/core/core.h @@ -49,7 +49,7 @@ void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode); void mmc_set_bus_width(struct mmc_host *host, unsigned int width); u32 mmc_select_voltage(struct mmc_host *host, u32 ocr); int mmc_set_uhs_voltage(struct mmc_host *host, u32 ocr); -int __mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage); +int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage); void mmc_set_timing(struct mmc_host *host, unsigned int timing); void mmc_set_driver_type(struct mmc_host *host, unsigned int drv_type); int mmc_select_drive_strength(struct mmc_card *card, unsigned int max_dtr, diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index b91abe01aacc..5844f29d3bed 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -1122,14 +1122,14 @@ static int mmc_select_hs_ddr(struct mmc_card *card) */ err = -EINVAL; if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_DDR_1_2V) - err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120); + err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120); if (err && (card->mmc_avail_type & EXT_CSD_CARD_TYPE_DDR_1_8V)) - err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180); + err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180); /* make sure vccq is 3.3v after switching disaster */ if (err) - err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330); + err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330); return err; } @@ -1296,10 +1296,10 @@ static int mmc_select_hs400es(struct mmc_card *card) } if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400_1_2V) - err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120); + err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120); if (err && card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400_1_8V) - err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180); + err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180); /* If fails try again during next card power cycle */ if (err) @@ -1405,10 +1405,10 @@ static int mmc_select_hs200(struct mmc_card *card) old_signal_voltage = host->ios.signal_voltage; if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_2V) - err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120); + err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120); if (err && card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_8V) - err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180); + err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180); /* If fails try again during next card power cycle */ if (err) @@ -1450,7 +1450,7 @@ static int mmc_select_hs200(struct mmc_card *card) err: if (err) { /* fall back to the old signal voltage, if fails report error */ - if (__mmc_set_signal_voltage(host, old_signal_voltage)) + if (mmc_set_signal_voltage(host, old_signal_voltage)) err = -EIO; pr_err("%s: %s failed, error %d\n", mmc_hostname(card->host), From 20f921bb01140207983e9fc3af4bb60f1f9fc0d5 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Wed, 25 Jan 2017 12:04:17 +0100 Subject: [PATCH 099/145] mmc: core: Invent MMC_CAP_3_3V_DDR According the JEDEC specification an eMMC card supporting 1.8V vccq in DDR mode should also be capable of 3.3V. However, it's been reported that some mmc hosts supports 3.3V, but not 1.8V. Currently the mmc core implements an error handling when the host fails to set 1.8V for vccq, by falling back to 3.3V. Unfortunate, this seems to be insufficient for some mmc hosts. To enable these to use eMMC DDR mode let's invent a new mmc cap, MMC_CAP_3_3V_DDR, which tells whether they support the eMMC 3.3V DDR mode. In case MMC_CAP_3_3V_DDR is set, but not MMC_CAP_1_8V_DDR, let's change to remain on the 3.3V, as it's the default voltage level for vccq, set by the earlier power up sequence. As this change introduces MMC_CAP_3_3V_DDR, let's take the opportunity to do some re-formatting of the related defines in the header file. Signed-off-by: Ulf Hansson Reviewed-by: Shawn Lin Tested-by: Jan Glauber Tested-by: Stefan Wahren --- drivers/mmc/core/mmc.c | 11 +++++++---- include/linux/mmc/host.h | 21 ++++++++++----------- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 5844f29d3bed..f1a451e48538 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -213,7 +213,7 @@ static void mmc_select_card_type(struct mmc_card *card) avail_type |= EXT_CSD_CARD_TYPE_HS_52; } - if (caps & MMC_CAP_1_8V_DDR && + if (caps & (MMC_CAP_1_8V_DDR | MMC_CAP_3_3V_DDR) && card_type & EXT_CSD_CARD_TYPE_DDR_1_8V) { hs_max_dtr = MMC_HIGH_DDR_MAX_DTR; avail_type |= EXT_CSD_CARD_TYPE_DDR_1_8V; @@ -1120,11 +1120,14 @@ static int mmc_select_hs_ddr(struct mmc_card *card) * * WARNING: eMMC rules are NOT the same as SD DDR */ - err = -EINVAL; - if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_DDR_1_2V) + if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_DDR_1_2V) { err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120); + if (!err) + return 0; + } - if (err && (card->mmc_avail_type & EXT_CSD_CARD_TYPE_DDR_1_8V)) + if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_DDR_1_8V && + host->caps & MMC_CAP_1_8V_DDR) err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180); /* make sure vccq is 3.3v after switching disaster */ diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index 97699d55b2ae..83f1c4a9f03b 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -259,17 +259,16 @@ struct mmc_host { #define MMC_CAP_NONREMOVABLE (1 << 8) /* Nonremovable e.g. eMMC */ #define MMC_CAP_WAIT_WHILE_BUSY (1 << 9) /* Waits while card is busy */ #define MMC_CAP_ERASE (1 << 10) /* Allow erase/trim commands */ -#define MMC_CAP_1_8V_DDR (1 << 11) /* can support */ - /* DDR mode at 1.8V */ -#define MMC_CAP_1_2V_DDR (1 << 12) /* can support */ - /* DDR mode at 1.2V */ -#define MMC_CAP_POWER_OFF_CARD (1 << 13) /* Can power off after boot */ -#define MMC_CAP_BUS_WIDTH_TEST (1 << 14) /* CMD14/CMD19 bus width ok */ -#define MMC_CAP_UHS_SDR12 (1 << 15) /* Host supports UHS SDR12 mode */ -#define MMC_CAP_UHS_SDR25 (1 << 16) /* Host supports UHS SDR25 mode */ -#define MMC_CAP_UHS_SDR50 (1 << 17) /* Host supports UHS SDR50 mode */ -#define MMC_CAP_UHS_SDR104 (1 << 18) /* Host supports UHS SDR104 mode */ -#define MMC_CAP_UHS_DDR50 (1 << 19) /* Host supports UHS DDR50 mode */ +#define MMC_CAP_3_3V_DDR (1 << 11) /* Host supports eMMC DDR 3.3V */ +#define MMC_CAP_1_8V_DDR (1 << 12) /* Host supports eMMC DDR 1.8V */ +#define MMC_CAP_1_2V_DDR (1 << 13) /* Host supports eMMC DDR 1.2V */ +#define MMC_CAP_POWER_OFF_CARD (1 << 14) /* Can power off after boot */ +#define MMC_CAP_BUS_WIDTH_TEST (1 << 15) /* CMD14/CMD19 bus width ok */ +#define MMC_CAP_UHS_SDR12 (1 << 16) /* Host supports UHS SDR12 mode */ +#define MMC_CAP_UHS_SDR25 (1 << 17) /* Host supports UHS SDR25 mode */ +#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_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 */ From 41efc76e0c0414d1e38a9d974a544aa80a653956 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Wed, 25 Jan 2017 12:44:13 +0100 Subject: [PATCH 100/145] mmc: dt: Document binding for eMMC DDR 3.3V I/O voltage support Cc: Cc: Rob Herring Signed-off-by: Ulf Hansson Reviewed-by: Shawn Lin Tested-by: Jan Glauber Tested-by: Stefan Wahren Acked-by: Rob Herring --- Documentation/devicetree/bindings/mmc/mmc.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/mmc/mmc.txt b/Documentation/devicetree/bindings/mmc/mmc.txt index 8a377827695b..c7f4a0ec48ed 100644 --- a/Documentation/devicetree/bindings/mmc/mmc.txt +++ b/Documentation/devicetree/bindings/mmc/mmc.txt @@ -40,6 +40,7 @@ Optional properties: - cap-mmc-hw-reset: eMMC hardware reset is supported - cap-sdio-irq: enable SDIO IRQ signalling on this interface - full-pwr-cycle: full power cycle of the card is supported +- mmc-ddr-3_3v: eMMC high-speed DDR mode(3.3V I/O) is supported - mmc-ddr-1_8v: eMMC high-speed DDR mode(1.8V I/O) is supported - mmc-ddr-1_2v: eMMC high-speed DDR mode(1.2V I/O) is supported - mmc-hs200-1_8v: eMMC HS200 mode(1.8V I/O) is supported From fb00f196fcce8078e162d09a1d7725032c2dfdc8 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Wed, 25 Jan 2017 12:45:43 +0100 Subject: [PATCH 101/145] mmc: core: Extend mmc_of_parse() to check for mmc-ddr-3_3v When mmc_of_parse() finds the binding, it sets the mmc cap, MMC_CAP_3_3V_DDR, which informs the core whether eMMC DDR at 3.3V I/O is supported by the mmc host. Signed-off-by: Ulf Hansson Reviewed-by: Shawn Lin Tested-by: Jan Glauber Tested-by: Stefan Wahren --- drivers/mmc/core/host.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index 98f25ffb4258..8f75a84d861e 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -301,6 +301,8 @@ int mmc_of_parse(struct mmc_host *host) if (of_property_read_bool(np, "wakeup-source") || of_property_read_bool(np, "enable-sdio-wakeup")) /* legacy */ host->pm_caps |= MMC_PM_WAKE_SDIO_IRQ; + if (of_property_read_bool(np, "mmc-ddr-3_3v")) + host->caps |= MMC_CAP_3_3V_DDR; if (of_property_read_bool(np, "mmc-ddr-1_8v")) host->caps |= MMC_CAP_1_8V_DDR; if (of_property_read_bool(np, "mmc-ddr-1_2v")) From 4436c5359962420e66e32d1340dffa3f1643e3f0 Mon Sep 17 00:00:00 2001 From: Ritesh Harjani Date: Tue, 24 Jan 2017 14:20:26 +0530 Subject: [PATCH 102/145] mmc: sdhci-msm: Remove platform_execute_tuning from sdhci_msm_ops platform_execute_tuning should not really exist as it does not do anything useful. So remove this ops and directly plug sdhci_msm_execute_tuning with mmc_host_ops. Also in case of HS400 tuning clear SDHCI_HS400_TUNING flag once HS400 related mode selection is done. Signed-off-by: Ritesh Harjani Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-msm.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index f9586977a7fa..b3e8f44ed680 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -827,12 +827,12 @@ out: return ret; } -static int sdhci_msm_execute_tuning(struct sdhci_host *host, u32 opcode) +static int sdhci_msm_execute_tuning(struct mmc_host *mmc, u32 opcode) { + struct sdhci_host *host = mmc_priv(mmc); int tuning_seq_cnt = 3; u8 phase, tuned_phases[16], tuned_phase_cnt = 0; int rc; - struct mmc_host *mmc = host->mmc; struct mmc_ios ios = host->mmc->ios; struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); @@ -855,6 +855,7 @@ static int sdhci_msm_execute_tuning(struct sdhci_host *host, u32 opcode) if (host->flags & SDHCI_HS400_TUNING) { sdhci_msm_hc_select_mode(host); msm_set_clock_rate_for_bus_mode(host, ios.clock); + host->flags &= ~SDHCI_HS400_TUNING; } retry: @@ -1119,7 +1120,6 @@ static const struct of_device_id sdhci_msm_dt_match[] = { MODULE_DEVICE_TABLE(of, sdhci_msm_dt_match); static const struct sdhci_ops sdhci_msm_ops = { - .platform_execute_tuning = sdhci_msm_execute_tuning, .reset = sdhci_reset, .set_clock = sdhci_msm_set_clock, .get_min_clock = sdhci_msm_get_min_clock, @@ -1294,6 +1294,7 @@ static int sdhci_msm_probe(struct platform_device *pdev) MSM_MMC_AUTOSUSPEND_DELAY_MS); pm_runtime_use_autosuspend(&pdev->dev); + host->mmc_host_ops.execute_tuning = sdhci_msm_execute_tuning; ret = sdhci_add_host(host); if (ret) goto pm_runtime_disable; From 543c576d1bf215c5d3c1b0615a85cec1b68a04cb Mon Sep 17 00:00:00 2001 From: Ritesh Harjani Date: Tue, 24 Jan 2017 14:20:27 +0530 Subject: [PATCH 103/145] mmc: sdhci-msm: Remove unnecessary comments of CDC init sequence This removes CDC init sequence comments which are not useful anyway. Signed-off-by: Ritesh Harjani Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-msm.c | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index b3e8f44ed680..10cdc84d5113 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -664,19 +664,7 @@ static int sdhci_msm_cdclp533_calibration(struct sdhci_host *host) config &= ~CORE_START_CDC_TRAFFIC; writel_relaxed(config, host->ioaddr + CORE_DDR_200_CFG); - /* - * Perform CDC Register Initialization Sequence - * - * CORE_CSR_CDC_CTLR_CFG0 0x11800EC - * CORE_CSR_CDC_CTLR_CFG1 0x3011111 - * CORE_CSR_CDC_CAL_TIMER_CFG0 0x1201000 - * CORE_CSR_CDC_CAL_TIMER_CFG1 0x4 - * CORE_CSR_CDC_REFCOUNT_CFG 0xCB732020 - * CORE_CSR_CDC_COARSE_CAL_CFG 0xB19 - * CORE_CSR_CDC_DELAY_CFG 0x3AC - * CORE_CDC_OFFSET_CFG 0x0 - * CORE_CDC_SLAVE_DDA_CFG 0x16334 - */ + /* Perform CDC Register Initialization Sequence */ writel_relaxed(0x11800EC, host->ioaddr + CORE_CSR_CDC_CTLR_CFG0); writel_relaxed(0x3011111, host->ioaddr + CORE_CSR_CDC_CTLR_CFG1); From 7413d1f509eb0ee605973c1a6da9911700c80012 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Sat, 28 Jan 2017 09:32:35 +0100 Subject: [PATCH 104/145] mmc: core: simplify ida handling ida handling can be simplified by switching to the ida_simple_ functions. Signed-off-by: Heiner Kallweit Signed-off-by: Ulf Hansson --- drivers/mmc/core/host.c | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index 8f75a84d861e..170881854975 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -34,14 +34,11 @@ #define cls_dev_to_mmc_host(d) container_of(d, struct mmc_host, class_dev) static DEFINE_IDA(mmc_host_ida); -static DEFINE_SPINLOCK(mmc_host_lock); static void mmc_host_classdev_release(struct device *dev) { struct mmc_host *host = cls_dev_to_mmc_host(dev); - spin_lock(&mmc_host_lock); - ida_remove(&mmc_host_ida, host->index); - spin_unlock(&mmc_host_lock); + ida_simple_remove(&mmc_host_ida, host->index); kfree(host); } @@ -356,22 +353,13 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev) /* scanning will be enabled when we're ready */ host->rescan_disable = 1; -again: - if (!ida_pre_get(&mmc_host_ida, GFP_KERNEL)) { + err = ida_simple_get(&mmc_host_ida, 0, 0, GFP_KERNEL); + if (err < 0) { kfree(host); return NULL; } - spin_lock(&mmc_host_lock); - err = ida_get_new(&mmc_host_ida, &host->index); - spin_unlock(&mmc_host_lock); - - if (err == -EAGAIN) { - goto again; - } else if (err) { - kfree(host); - return NULL; - } + host->index = err; dev_set_name(&host->class_dev, "mmc%d", host->index); From 1ed2171944888cf6787990a0f6387b717ba72e24 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Sat, 28 Jan 2017 09:32:50 +0100 Subject: [PATCH 105/145] mmc: core: fix error path in mmc_host_alloc Properly reverse everything if mmc_gpio_alloc(host) fails. Signed-off-by: Heiner Kallweit Signed-off-by: Ulf Hansson --- drivers/mmc/core/host.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index 170881854975..3f8c85d5aa09 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -371,6 +371,8 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev) if (mmc_gpio_alloc(host)) { put_device(&host->class_dev); + ida_simple_remove(&mmc_host_ida, host->index); + kfree(host); return NULL; } From 39cc281fb79e3d40e945577363a55f5c922353ad Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Fri, 27 Jan 2017 22:38:33 +0100 Subject: [PATCH 106/145] mmc: sunxi: Fix clock frequency change sequence The SD specification documents that the clock frequency should only be changed once gated (Section 3.2.3 - SD Clock Frequency Change Sequence). The current code first modifies the parent clock, gates it and then modifies the internal divider. This means that since the parent clock rate might be changed, the bus clock might be changed as well before it is gated, which breaks the specification. Move the gating before the parent rate modification. Signed-off-by: Maxime Ripard Tested-by: Florian Vaussard Acked-by: Chen-Yu Tsai Signed-off-by: Ulf Hansson --- drivers/mmc/host/sunxi-mmc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/mmc/host/sunxi-mmc.c b/drivers/mmc/host/sunxi-mmc.c index b1d1303389a7..ab4324e6eb74 100644 --- a/drivers/mmc/host/sunxi-mmc.c +++ b/drivers/mmc/host/sunxi-mmc.c @@ -761,6 +761,10 @@ static int sunxi_mmc_clk_set_rate(struct sunxi_mmc_host *host, u32 rval, clock = ios->clock; int ret; + ret = sunxi_mmc_oclk_onoff(host, 0); + if (ret) + return ret; + /* 8 bit DDR requires a higher module clock */ if (ios->timing == MMC_TIMING_MMC_DDR52 && ios->bus_width == MMC_BUS_WIDTH_8) @@ -783,10 +787,6 @@ static int sunxi_mmc_clk_set_rate(struct sunxi_mmc_host *host, return ret; } - ret = sunxi_mmc_oclk_onoff(host, 0); - if (ret) - return ret; - /* clear internal divider */ rval = mmc_readl(host, REG_CLKCR); rval &= ~0xff; From 9479074e93765a65ee352e74bb66ff3f5ec03413 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Fri, 27 Jan 2017 22:38:34 +0100 Subject: [PATCH 107/145] mmc: sunxi: Gate the clock when rate is 0 The MMC core assumes that the code will gate the clock when the bus frequency is set to 0, which we've been ignoring so far. Handle that. Signed-off-by: Maxime Ripard Tested-by: Florian Vaussard Acked-by: Chen-Yu Tsai Signed-off-by: Ulf Hansson --- drivers/mmc/host/sunxi-mmc.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/host/sunxi-mmc.c b/drivers/mmc/host/sunxi-mmc.c index ab4324e6eb74..019f95e8e7c5 100644 --- a/drivers/mmc/host/sunxi-mmc.c +++ b/drivers/mmc/host/sunxi-mmc.c @@ -765,6 +765,9 @@ static int sunxi_mmc_clk_set_rate(struct sunxi_mmc_host *host, if (ret) return ret; + if (!ios->clock) + return 0; + /* 8 bit DDR requires a higher module clock */ if (ios->timing == MMC_TIMING_MMC_DDR52 && ios->bus_width == MMC_BUS_WIDTH_8) @@ -882,7 +885,7 @@ static void sunxi_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) mmc_writel(host, REG_GCTRL, rval); /* set up clock */ - if (ios->clock && ios->power_mode) { + if (ios->power_mode) { host->ferror = sunxi_mmc_clk_set_rate(host, ios); /* Android code had a usleep_range(50000, 55000); here */ } From 860fdf89b92e740b19d1160406df98e5302a9300 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Fri, 27 Jan 2017 22:38:35 +0100 Subject: [PATCH 108/145] mmc: sunxi: Always set signal delay to 0 for A64 Experience have shown that the using the autocalibration could severely degrade the performances of the MMC bus. Allwinner is using in its BSP a delay set to 0 for all the modes but HS400. Remove the calibration code for now, and add comments to document our findings. Reviewed-by: Andre Przywara Signed-off-by: Maxime Ripard Tested-by: Florian Vaussard Acked-by: Chen-Yu Tsai Signed-off-by: Ulf Hansson --- drivers/mmc/host/sunxi-mmc.c | 50 ++++++++++++------------------------ 1 file changed, 17 insertions(+), 33 deletions(-) diff --git a/drivers/mmc/host/sunxi-mmc.c b/drivers/mmc/host/sunxi-mmc.c index 019f95e8e7c5..b9c8a62bc212 100644 --- a/drivers/mmc/host/sunxi-mmc.c +++ b/drivers/mmc/host/sunxi-mmc.c @@ -683,41 +683,19 @@ static int sunxi_mmc_oclk_onoff(struct sunxi_mmc_host *host, u32 oclk_en) static int sunxi_mmc_calibrate(struct sunxi_mmc_host *host, int reg_off) { - u32 reg = readl(host->reg_base + reg_off); - u32 delay; - unsigned long timeout; - if (!host->cfg->can_calibrate) return 0; - reg &= ~(SDXC_CAL_DL_MASK << SDXC_CAL_DL_SW_SHIFT); - reg &= ~SDXC_CAL_DL_SW_EN; - - writel(reg | SDXC_CAL_START, host->reg_base + reg_off); - - dev_dbg(mmc_dev(host->mmc), "calibration started\n"); - - timeout = jiffies + HZ * SDXC_CAL_TIMEOUT; - - while (!((reg = readl(host->reg_base + reg_off)) & SDXC_CAL_DONE)) { - if (time_before(jiffies, timeout)) - cpu_relax(); - else { - reg &= ~SDXC_CAL_START; - writel(reg, host->reg_base + reg_off); - - return -ETIMEDOUT; - } - } - - delay = (reg >> SDXC_CAL_DL_SHIFT) & SDXC_CAL_DL_MASK; - - reg &= ~SDXC_CAL_START; - reg |= (delay << SDXC_CAL_DL_SW_SHIFT) | SDXC_CAL_DL_SW_EN; - - writel(reg, host->reg_base + reg_off); - - dev_dbg(mmc_dev(host->mmc), "calibration ended, reg is 0x%x\n", reg); + /* + * FIXME: + * This is not clear how the calibration is supposed to work + * yet. The best rate have been obtained by simply setting the + * delay to 0, as Allwinner does in its BSP. + * + * The only mode that doesn't have such a delay is HS400, that + * is in itself a TODO. + */ + writel(SDXC_CAL_DL_SW_EN, host->reg_base + reg_off); return 0; } @@ -809,7 +787,13 @@ static int sunxi_mmc_clk_set_rate(struct sunxi_mmc_host *host, if (ret) return ret; - /* TODO: enable calibrate on sdc2 SDXC_REG_DS_DL_REG of A64 */ + /* + * FIXME: + * + * In HS400 we'll also need to calibrate the data strobe + * signal. This should only happen on the MMC2 controller (at + * least on the A64). + */ return sunxi_mmc_oclk_onoff(host, 1); } From 9a37e53e451eff5790ae15341031e39777105127 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Fri, 27 Jan 2017 22:38:36 +0100 Subject: [PATCH 109/145] mmc: sunxi: Enable the new timings for the A64 MMC controllers The A64 MMC controllers need to set a "new timings" bit when a new rate is set. The actual meaning of that bit is not clear yet, but not setting it leads to some corner-case issues, like the CMD53 failing, which is used to implement SDIO packet aggregation. Signed-off-by: Maxime Ripard Tested-by: Florian Vaussard Acked-by: Chen-Yu Tsai Signed-off-by: Ulf Hansson --- drivers/mmc/host/sunxi-mmc.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/mmc/host/sunxi-mmc.c b/drivers/mmc/host/sunxi-mmc.c index b9c8a62bc212..51d6388a194e 100644 --- a/drivers/mmc/host/sunxi-mmc.c +++ b/drivers/mmc/host/sunxi-mmc.c @@ -253,6 +253,8 @@ struct sunxi_mmc_cfg { /* does the IP block support autocalibration? */ bool can_calibrate; + + bool needs_new_timings; }; struct sunxi_mmc_host { @@ -779,6 +781,9 @@ static int sunxi_mmc_clk_set_rate(struct sunxi_mmc_host *host, } mmc_writel(host, REG_CLKCR, rval); + if (host->cfg->needs_new_timings) + mmc_writel(host, REG_SD_NTSR, SDXC_2X_TIMING_MODE); + ret = sunxi_mmc_clk_set_phase(host, ios, rate); if (ret) return ret; @@ -1076,6 +1081,7 @@ static const struct sunxi_mmc_cfg sun50i_a64_cfg = { .idma_des_size_bits = 16, .clk_delays = NULL, .can_calibrate = true, + .needs_new_timings = true, }; static const struct of_device_id sunxi_mmc_of_match[] = { From 16e821e3ba47096eb23abedd5a5e377d77f5f0d5 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Fri, 27 Jan 2017 22:38:37 +0100 Subject: [PATCH 110/145] mmc: sunxi: Mask DATA0 when updating the clock The A64 MMC controllers need DATA0 to be masked while updating the clock, otherwise any subsequent command will result in a timeout. It's not really clear at this point what DATA0 is exactly, but this behaviour is present in Allwinner's tree, and has been suggested by Allwinner engineers as fixes for the timeout. Signed-off-by: Maxime Ripard Tested-by: Florian Vaussard Acked-by: Chen-Yu Tsai Signed-off-by: Ulf Hansson --- drivers/mmc/host/sunxi-mmc.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/host/sunxi-mmc.c b/drivers/mmc/host/sunxi-mmc.c index 51d6388a194e..6bbe61397b7c 100644 --- a/drivers/mmc/host/sunxi-mmc.c +++ b/drivers/mmc/host/sunxi-mmc.c @@ -101,6 +101,7 @@ (SDXC_SOFT_RESET | SDXC_FIFO_RESET | SDXC_DMA_RESET) /* clock control bits */ +#define SDXC_MASK_DATA0 BIT(31) #define SDXC_CARD_CLOCK_ON BIT(16) #define SDXC_LOW_POWER_ON BIT(17) @@ -254,6 +255,9 @@ struct sunxi_mmc_cfg { /* does the IP block support autocalibration? */ bool can_calibrate; + /* Does DATA0 needs to be masked while the clock is updated */ + bool mask_data0; + bool needs_new_timings; }; @@ -657,10 +661,12 @@ static int sunxi_mmc_oclk_onoff(struct sunxi_mmc_host *host, u32 oclk_en) u32 rval; rval = mmc_readl(host, REG_CLKCR); - rval &= ~(SDXC_CARD_CLOCK_ON | SDXC_LOW_POWER_ON); + rval &= ~(SDXC_CARD_CLOCK_ON | SDXC_LOW_POWER_ON | SDXC_MASK_DATA0); if (oclk_en) rval |= SDXC_CARD_CLOCK_ON; + if (host->cfg->mask_data0) + rval |= SDXC_MASK_DATA0; mmc_writel(host, REG_CLKCR, rval); @@ -680,6 +686,11 @@ static int sunxi_mmc_oclk_onoff(struct sunxi_mmc_host *host, u32 oclk_en) return -EIO; } + if (host->cfg->mask_data0) { + rval = mmc_readl(host, REG_CLKCR); + mmc_writel(host, REG_CLKCR, rval & ~SDXC_MASK_DATA0); + } + return 0; } @@ -1081,6 +1092,7 @@ static const struct sunxi_mmc_cfg sun50i_a64_cfg = { .idma_des_size_bits = 16, .clk_delays = NULL, .can_calibrate = true, + .mask_data0 = true, .needs_new_timings = true, }; From 4fb3ce07eafa9d5945a1f36708557821a513b1b1 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Fri, 27 Jan 2017 22:38:38 +0100 Subject: [PATCH 111/145] mmc: sunxi: Add EMMC (MMC2) controller compatible The MMC2 controller on the A64 is kind of a special beast. While the general controller design is the same than the other MMC controllers in the SoC, it also has a bunch of features and changes that prevent it to be driven in the same way. It has for example a different bus width limit, a different maximum frequency, and, for some reason, the maximum buffer size of a DMA descriptor. Add a new compatible specifically for this controller. Acked-by: Rob Herring Signed-off-by: Maxime Ripard Tested-by: Florian Vaussard Acked-by: Chen-Yu Tsai Signed-off-by: Ulf Hansson --- drivers/mmc/host/sunxi-mmc.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/mmc/host/sunxi-mmc.c b/drivers/mmc/host/sunxi-mmc.c index 6bbe61397b7c..f0f6922bca8a 100644 --- a/drivers/mmc/host/sunxi-mmc.c +++ b/drivers/mmc/host/sunxi-mmc.c @@ -5,6 +5,7 @@ * (C) Copyright 2013-2014 O2S GmbH * (C) Copyright 2013-2014 David Lanzend�rfer * (C) Copyright 2013-2014 Hans de Goede + * (C) Copyright 2017 Sootech SA * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -1096,12 +1097,19 @@ static const struct sunxi_mmc_cfg sun50i_a64_cfg = { .needs_new_timings = true, }; +static const struct sunxi_mmc_cfg sun50i_a64_emmc_cfg = { + .idma_des_size_bits = 13, + .clk_delays = NULL, + .can_calibrate = true, +}; + static const struct of_device_id sunxi_mmc_of_match[] = { { .compatible = "allwinner,sun4i-a10-mmc", .data = &sun4i_a10_cfg }, { .compatible = "allwinner,sun5i-a13-mmc", .data = &sun5i_a13_cfg }, { .compatible = "allwinner,sun7i-a20-mmc", .data = &sun7i_a20_cfg }, { .compatible = "allwinner,sun9i-a80-mmc", .data = &sun9i_a80_cfg }, { .compatible = "allwinner,sun50i-a64-mmc", .data = &sun50i_a64_cfg }, + { .compatible = "allwinner,sun50i-a64-emmc", .data = &sun50i_a64_emmc_cfg }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, sunxi_mmc_of_match); From 43c15e962c1240356a7e1aeca450d783dd903c55 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Fri, 27 Jan 2017 22:38:39 +0100 Subject: [PATCH 112/145] mmc: sunxi: Add more debug informations Add a bit more debug messages that can be helpful when debugging the clock setup. Also fill the actual_clock field in struct mmc_host to report properly the current frequency in debugfs. Signed-off-by: Maxime Ripard Tested-by: Florian Vaussard Acked-by: Chen-Yu Tsai Signed-off-by: Ulf Hansson --- drivers/mmc/host/sunxi-mmc.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/drivers/mmc/host/sunxi-mmc.c b/drivers/mmc/host/sunxi-mmc.c index f0f6922bca8a..6ffcd2838272 100644 --- a/drivers/mmc/host/sunxi-mmc.c +++ b/drivers/mmc/host/sunxi-mmc.c @@ -661,6 +661,9 @@ static int sunxi_mmc_oclk_onoff(struct sunxi_mmc_host *host, u32 oclk_en) unsigned long expire = jiffies + msecs_to_jiffies(750); u32 rval; + dev_dbg(mmc_dev(host->mmc), "%sabling the clock\n", + oclk_en ? "en" : "dis"); + rval = mmc_readl(host, REG_CLKCR); rval &= ~(SDXC_CARD_CLOCK_ON | SDXC_LOW_POWER_ON | SDXC_MASK_DATA0); @@ -737,6 +740,7 @@ static int sunxi_mmc_clk_set_phase(struct sunxi_mmc_host *host, index = SDXC_CLK_50M_DDR; } } else { + dev_dbg(mmc_dev(host->mmc), "Invalid clock... returning\n"); return -EINVAL; } @@ -749,6 +753,7 @@ static int sunxi_mmc_clk_set_phase(struct sunxi_mmc_host *host, static int sunxi_mmc_clk_set_rate(struct sunxi_mmc_host *host, struct mmc_ios *ios) { + struct mmc_host *mmc = host->mmc; long rate; u32 rval, clock = ios->clock; int ret; @@ -757,6 +762,9 @@ static int sunxi_mmc_clk_set_rate(struct sunxi_mmc_host *host, if (ret) return ret; + /* Our clock is gated now */ + mmc->actual_clock = 0; + if (!ios->clock) return 0; @@ -767,17 +775,17 @@ static int sunxi_mmc_clk_set_rate(struct sunxi_mmc_host *host, rate = clk_round_rate(host->clk_mmc, clock); if (rate < 0) { - dev_err(mmc_dev(host->mmc), "error rounding clk to %d: %ld\n", + dev_err(mmc_dev(mmc), "error rounding clk to %d: %ld\n", clock, rate); return rate; } - dev_dbg(mmc_dev(host->mmc), "setting clk to %d, rounded %ld\n", + dev_dbg(mmc_dev(mmc), "setting clk to %d, rounded %ld\n", clock, rate); /* setting clock rate */ ret = clk_set_rate(host->clk_mmc, rate); if (ret) { - dev_err(mmc_dev(host->mmc), "error setting clk to %ld: %d\n", + dev_err(mmc_dev(mmc), "error setting clk to %ld: %d\n", rate, ret); return ret; } @@ -812,7 +820,14 @@ static int sunxi_mmc_clk_set_rate(struct sunxi_mmc_host *host, * least on the A64). */ - return sunxi_mmc_oclk_onoff(host, 1); + ret = sunxi_mmc_oclk_onoff(host, 1); + if (ret) + return ret; + + /* And we just enabled our clock back */ + mmc->actual_clock = rate; + + return 0; } static void sunxi_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) From e13934bdf45935f51243515c275629922dc43839 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Fri, 27 Jan 2017 15:04:54 +0100 Subject: [PATCH 113/145] mmc: core/mmci: restore pre/post_req behaviour commit 64b12a68a9f74bb32d8efd7af1ad8a2ba02fc884 "mmc: core: fix prepared requests while doing bkops" is fixing a bug in the wrong way. A bug in the MMCI device driver is fixed by amending the MMC core. Thinking about it: what the pre- and post-callbacks are doing is to essentially map and unmap SG lists for DMA transfers. Why would we not be able to do that just because a BKOPS command is sent inbetween? Having to unprepare/prepare the next asynchronous request for DMA seems wrong. Looking the backtrace in that commit we can see what the real problem actually is: mmci_data_irq() is calling mmci_dma_unmap() twice which is goung to call arm_dma_unmap_sg() twice and v7_dma_inv_range() twice for the same sglist and that will crash. This happens because a request is prepared, then a BKOPS is sent. The IRQ completing the BKOPS command goes through mmci_data_irq() and thinks that a DMA operation has just been completed because dma_inprogress() reports true. It then proceeds to unmap the sglist. But that was wrong! dma_inprogress() should NOT be true because no DMA was actually in progress! We had just prepared the sglist, and the DMA channel dma_current has been configured, but NOT started! Because of this, the sglist is already unmapped when we get our actual data completion IRQ, and we are unmapping the sglist once more, and we get this crash. Therefore, we need to revert this solution pushing the problem to the core and causing problems, and instead augment the implementation such that dma_inprogress() only reports true if some DMA has actually been started. After this we can keep the request prepared during the BKOPS and we need not unprepare/reprepare it. Fixes: 64b12a68a9f7 ("mmc: core: fix prepared requests while doing bkops") Cc: Srinivas Kandagatla Signed-off-by: Linus Walleij Tested-by: Srinivas Kandagatla Signed-off-by: Ulf Hansson --- drivers/mmc/core/core.c | 9 --------- drivers/mmc/host/mmci.c | 7 ++++++- drivers/mmc/host/mmci.h | 3 ++- 3 files changed, 8 insertions(+), 11 deletions(-) diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index b20b70fbd50d..3b12981e7627 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -676,16 +676,7 @@ struct mmc_async_req *mmc_start_req(struct mmc_host *host, ((mmc_resp_type(host->areq->mrq->cmd) == MMC_RSP_R1) || (mmc_resp_type(host->areq->mrq->cmd) == MMC_RSP_R1B)) && (host->areq->mrq->cmd->resp[0] & R1_EXCEPTION_EVENT)) { - - /* Cancel the prepared request */ - if (areq) - mmc_post_req(host, areq->mrq, -EINVAL); - mmc_start_bkops(host->card, true); - - /* prepare the request again */ - if (areq) - mmc_pre_req(host, areq->mrq); } } diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index b5972440c1bf..0c6420bb2f00 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -507,6 +507,7 @@ static void mmci_dma_data_error(struct mmci_host *host) { dev_err(mmc_dev(host->mmc), "error during DMA transfer!\n"); dmaengine_terminate_all(host->dma_current); + host->dma_in_progress = false; host->dma_current = NULL; host->dma_desc_current = NULL; host->data->host_cookie = 0; @@ -565,6 +566,7 @@ static void mmci_dma_finalize(struct mmci_host *host, struct mmc_data *data) mmci_dma_release(host); } + host->dma_in_progress = false; host->dma_current = NULL; host->dma_desc_current = NULL; } @@ -665,6 +667,7 @@ static int mmci_dma_start_data(struct mmci_host *host, unsigned int datactrl) dev_vdbg(mmc_dev(host->mmc), "Submit MMCI DMA job, sglen %d blksz %04x blks %04x flags %08x\n", data->sg_len, data->blksz, data->blocks, data->flags); + host->dma_in_progress = true; dmaengine_submit(host->dma_desc_current); dma_async_issue_pending(host->dma_current); @@ -740,8 +743,10 @@ static void mmci_post_request(struct mmc_host *mmc, struct mmc_request *mrq, if (host->dma_desc_current == next->dma_desc) host->dma_desc_current = NULL; - if (host->dma_current == next->dma_chan) + if (host->dma_current == next->dma_chan) { + host->dma_in_progress = false; host->dma_current = NULL; + } next->dma_desc = NULL; next->dma_chan = NULL; diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h index 56322c6afba4..4a8bef1aac8f 100644 --- a/drivers/mmc/host/mmci.h +++ b/drivers/mmc/host/mmci.h @@ -245,8 +245,9 @@ struct mmci_host { struct dma_chan *dma_tx_channel; struct dma_async_tx_descriptor *dma_desc_current; struct mmci_host_next next_data; + bool dma_in_progress; -#define dma_inprogress(host) ((host)->dma_current) +#define dma_inprogress(host) ((host)->dma_in_progress) #else #define dma_inprogress(host) (0) #endif From ce69e2fea093b7fa3991c87849c4955cd47796c9 Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Tue, 17 Jan 2017 09:22:55 +0800 Subject: [PATCH 114/145] mmc: dw_mmc: silent verbose log when calling from PM context When deploying runtime PM, it's quite verbose to print the log of ios setting. Also it's useless to print it from system PM as it should be the same with booting time. We also have sysfs to get all these information from ios attribute, so let's skip this print from PM context. Signed-off-by: Shawn Lin Signed-off-by: Jaehoon Chung Signed-off-by: Ulf Hansson --- drivers/mmc/host/dw_mmc.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index c04a5769e2ea..a9ac0b457313 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -1182,11 +1182,13 @@ static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool 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); + /* Silent the verbose log if calling from PM context */ + if (!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 From 3d33cb5ad582cef7d0c4f0397cf6a3307ce8802c Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Mon, 30 Jan 2017 14:27:13 +0100 Subject: [PATCH 115/145] dt-bindings: mmc: sunxi: Document A64 eMMC compatible We introduced recently a new compatible to deal with the A64 eMMC controller, let's document its binding. Signed-off-by: Maxime Ripard Acked-by: Chen-Yu Tsai Acked-by: Rob Herring Signed-off-by: Ulf Hansson --- Documentation/devicetree/bindings/mmc/sunxi-mmc.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/mmc/sunxi-mmc.txt b/Documentation/devicetree/bindings/mmc/sunxi-mmc.txt index 55cdd804cdba..7d53a799f140 100644 --- a/Documentation/devicetree/bindings/mmc/sunxi-mmc.txt +++ b/Documentation/devicetree/bindings/mmc/sunxi-mmc.txt @@ -13,6 +13,7 @@ Required properties: * "allwinner,sun5i-a13-mmc" * "allwinner,sun7i-a20-mmc" * "allwinner,sun9i-a80-mmc" + * "allwinner,sun50i-a64-emmc" * "allwinner,sun50i-a64-mmc" - reg : mmc controller base registers - clocks : a list with 4 phandle + clock specifier pairs From 24380dd4f8da47951ebaab26f9bfd398e83b186d Mon Sep 17 00:00:00 2001 From: Ravikumar Kattekola Date: Mon, 30 Jan 2017 15:41:56 +0530 Subject: [PATCH 116/145] mmc: host: omap_hsmmc: reset cmd line on ceb error When CEB (command end bit error) occurs reset CMD line to avoid system ending up in erroneous state. While command line is reset for CTO and CCRC errors, it's not done for CEB error. Fix it here. Reviewed-by: Kishon Vijay Abraham I Signed-off-by: Ravikumar Kattekola Signed-off-by: Sekhar Nori Signed-off-by: Ulf Hansson --- drivers/mmc/host/omap_hsmmc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index ad11c4cc12ed..0ee56505494e 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -1162,7 +1162,7 @@ static void omap_hsmmc_do_irq(struct omap_hsmmc_host *host, int status) if (status & ERR_EN) { omap_hsmmc_dbg_report_irq(host, status); - if (status & (CTO_EN | CCRC_EN)) + if (status & (CTO_EN | CCRC_EN | CEB_EN)) end_cmd = 1; if (host->data || host->response_busy) { end_trans = !end_cmd; From 8cc9a3e73de1264cb61d8eca4e15310f3b2b9746 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Mon, 30 Jan 2017 15:41:57 +0530 Subject: [PATCH 117/145] mmc: host: omap_hsmmc: use generic_cmd6_time to program timeout value for CMD6 commit e2bf08d643a244ccb ("omap_hsmmc: set a large data timeout for commands with busy signal") sets an arbitrary timeout value (100ms) for commands like CMD6 (MMC SWITCH). However extended CSD register defined in the eMMC standard has a field for GENERIC_CMD6_TIME which indicates the default maximum timeout for a SWITCH command. Use busy_timeout of cmd structure (populated with GENERIC_CMD6_TIME in the case of SWITCH command) to program the data timeout value in omap_hsmmc driver. SWITCH command to turn the cache on took more than 100ms to complete with MICRON eMMC card present in AM572x IDK REV 1.3A resulting in timeout and failed enumeration. It is fixed here by programming the timeout with the value advertised in GENERIC_CMD6_TIME. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Sekhar Nori Signed-off-by: Ravikumar Kattekola Signed-off-by: Ulf Hansson --- drivers/mmc/host/omap_hsmmc.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 0ee56505494e..51ca3d7c19ca 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -1527,16 +1527,24 @@ static int omap_hsmmc_prepare_data(struct omap_hsmmc_host *host, struct mmc_request *req) { int ret; + unsigned int timeout; + host->data = req->data; if (req->data == NULL) { OMAP_HSMMC_WRITE(host->base, BLK, 0); - /* - * Set an arbitrary 100ms data timeout for commands with - * busy signal. - */ - if (req->cmd->flags & MMC_RSP_BUSY) - set_data_timeout(host, 100000000U, 0); + if (req->cmd->flags & MMC_RSP_BUSY) { + timeout = req->cmd->busy_timeout * NSEC_PER_MSEC; + + /* + * Set an arbitrary 100ms data timeout for commands with + * busy signal and no indication of busy_timeout. + */ + if (!timeout) + timeout = 100000000U; + + set_data_timeout(host, timeout, 0); + } return 0; } From a53210f56d7f3f75d1edc1b3a069ddb87b72a919 Mon Sep 17 00:00:00 2001 From: Ravikumar Kattekola Date: Mon, 30 Jan 2017 15:41:58 +0530 Subject: [PATCH 118/145] mmc: host: omap_hsmmc: avoid possible overflow of timeout value Fixes: a45c6cb81647 ("[ARM] 5369/1: omap mmc: Add new omap hsmmc controller for 2430 and 34xx, v3") when using really large timeout (up to 4*60*1000 ms for bkops) there is a possibility of data overflow using unsigned int so use 64 bit unsigned long long. Signed-off-by: Ravikumar Kattekola Signed-off-by: Sekhar Nori Signed-off-by: Ulf Hansson --- drivers/mmc/host/omap_hsmmc.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 51ca3d7c19ca..a58bd653ed8b 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -1469,10 +1469,11 @@ static int omap_hsmmc_setup_dma_transfer(struct omap_hsmmc_host *host, } static void set_data_timeout(struct omap_hsmmc_host *host, - unsigned int timeout_ns, + unsigned long long timeout_ns, unsigned int timeout_clks) { - unsigned int timeout, cycle_ns; + unsigned long long timeout = timeout_ns; + unsigned int cycle_ns; uint32_t reg, clkd, dto = 0; reg = OMAP_HSMMC_READ(host->base, SYSCTL); @@ -1481,7 +1482,7 @@ static void set_data_timeout(struct omap_hsmmc_host *host, clkd = 1; cycle_ns = 1000000000 / (host->clk_rate / clkd); - timeout = timeout_ns / cycle_ns; + do_div(timeout, cycle_ns); timeout += timeout_clks; if (timeout) { while ((timeout & 0x80000000) == 0) { @@ -1527,7 +1528,7 @@ static int omap_hsmmc_prepare_data(struct omap_hsmmc_host *host, struct mmc_request *req) { int ret; - unsigned int timeout; + unsigned long long timeout; host->data = req->data; From a04848c75bc02858ba98a7af63637728d033d3e8 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Wed, 1 Feb 2017 19:44:22 +0100 Subject: [PATCH 119/145] mmc: core: switch to ida_simple_ functions in block.c ida code in block.c can be significantly simplified by switching to the ida_simple_ functions. Signed-off-by: Heiner Kallweit Signed-off-by: Ulf Hansson --- drivers/mmc/core/block.c | 31 +++++-------------------------- 1 file changed, 5 insertions(+), 26 deletions(-) diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index 6c8be1a80551..00c55841a7c4 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -90,7 +90,6 @@ static int max_devices; #define MAX_DEVICES 256 static DEFINE_IDA(mmc_blk_ida); -static DEFINE_SPINLOCK(mmc_blk_lock); /* * There is one mmc_blk_data per slot. @@ -163,11 +162,7 @@ static void mmc_blk_put(struct mmc_blk_data *md) if (md->usage == 0) { int devidx = mmc_get_devidx(md->disk); blk_cleanup_queue(md->queue.queue); - - spin_lock(&mmc_blk_lock); - ida_remove(&mmc_blk_ida, devidx); - spin_unlock(&mmc_blk_lock); - + ida_simple_remove(&mmc_blk_ida, devidx); put_disk(md->disk); kfree(md); } @@ -1839,23 +1834,9 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card, struct mmc_blk_data *md; int devidx, ret; -again: - if (!ida_pre_get(&mmc_blk_ida, GFP_KERNEL)) - return ERR_PTR(-ENOMEM); - - spin_lock(&mmc_blk_lock); - ret = ida_get_new(&mmc_blk_ida, &devidx); - spin_unlock(&mmc_blk_lock); - - if (ret == -EAGAIN) - goto again; - else if (ret) - return ERR_PTR(ret); - - if (devidx >= max_devices) { - ret = -ENOSPC; - goto out; - } + devidx = ida_simple_get(&mmc_blk_ida, 0, max_devices, GFP_KERNEL); + if (devidx < 0) + return ERR_PTR(devidx); md = kzalloc(sizeof(struct mmc_blk_data), GFP_KERNEL); if (!md) { @@ -1944,9 +1925,7 @@ again: err_kfree: kfree(md); out: - spin_lock(&mmc_blk_lock); - ida_remove(&mmc_blk_ida, devidx); - spin_unlock(&mmc_blk_lock); + ida_simple_remove(&mmc_blk_ida, devidx); return ERR_PTR(ret); } From db435505b561c1ca7b72c646dbc060f0c674360c Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 1 Feb 2017 13:47:51 +0100 Subject: [PATCH 120/145] mmc: block: inline the command abort and start new goto:s The goto statements sprinkled over the mmc_blk_issue_rw_rq() function has grown over the years and makes the code pretty hard to read. Inline the calls such that: goto cmd_abort; -> mmc_blk_rw_cmd_abort(card, req); mmc_blk_rw_start_new(mq, card, rqc); return; goto start_new_req; -> mmc_blk_rw_start_new(mq, card, rqc); return; After this it is more clear how we exit the do {} while loop in this function, and it gets possible to split the code apart. Signed-off-by: Linus Walleij Signed-off-by: Ulf Hansson --- drivers/mmc/core/block.c | 46 +++++++++++++++++++++++----------------- 1 file changed, 27 insertions(+), 19 deletions(-) diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index 00c55841a7c4..43f1f1b24b83 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -1696,10 +1696,15 @@ static void mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc) break; case MMC_BLK_CMD_ERR: ret = mmc_blk_cmd_err(md, card, brq, req, ret); - if (mmc_blk_reset(md, card->host, type)) - goto cmd_abort; - if (!ret) - goto start_new_req; + if (mmc_blk_reset(md, card->host, type)) { + mmc_blk_rw_cmd_abort(card, req); + mmc_blk_rw_start_new(mq, card, rqc); + return; + } + if (!ret) { + mmc_blk_rw_start_new(mq, card, rqc); + return; + } break; case MMC_BLK_RETRY: retune_retry_done = brq->retune_retry_done; @@ -1709,15 +1714,20 @@ static void mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc) case MMC_BLK_ABORT: if (!mmc_blk_reset(md, card->host, type)) break; - goto cmd_abort; + mmc_blk_rw_cmd_abort(card, req); + mmc_blk_rw_start_new(mq, card, rqc); + return; case MMC_BLK_DATA_ERR: { int err; err = mmc_blk_reset(md, card->host, type); if (!err) break; - if (err == -ENODEV) - goto cmd_abort; + if (err == -ENODEV) { + mmc_blk_rw_cmd_abort(card, req); + mmc_blk_rw_start_new(mq, card, rqc); + return; + } /* Fall through */ } case MMC_BLK_ECC_ERR: @@ -1735,15 +1745,21 @@ static void mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc) */ ret = blk_end_request(req, -EIO, brq->data.blksz); - if (!ret) - goto start_new_req; + if (!ret) { + mmc_blk_rw_start_new(mq, card, rqc); + return; + } break; case MMC_BLK_NOMEDIUM: - goto cmd_abort; + mmc_blk_rw_cmd_abort(card, req); + mmc_blk_rw_start_new(mq, card, rqc); + return; default: pr_err("%s: Unhandled return value (%d)", req->rq_disk->disk_name, status); - goto cmd_abort; + mmc_blk_rw_cmd_abort(card, req); + mmc_blk_rw_start_new(mq, card, rqc); + return; } if (ret) { @@ -1758,14 +1774,6 @@ static void mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc) mq_rq->brq.retune_retry_done = retune_retry_done; } } while (ret); - - return; - - cmd_abort: - mmc_blk_rw_cmd_abort(card, req); - - start_new_req: - mmc_blk_rw_start_new(mq, card, rqc); } void mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) From acd8dbd64a2adcd950c31261247cda6f847f57eb Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 1 Feb 2017 13:47:52 +0100 Subject: [PATCH 121/145] mmc: block: rename rqc and req In the function mmc_blk_issue_rw_rq() the new request coming in from the block layer is called "rqc" and the old request that was potentially just returned back from the asynchronous mechanism is called "req". This is really confusing when trying to analyze and understand the code, it becomes a perceptual nightmare to me. Maybe others have better parserheads but it is not working for me. Rename "rqc" to "new_req" and "req" to "old_req" to reflect what is semantically going on into the syntax. Signed-off-by: Linus Walleij Signed-off-by: Ulf Hansson --- drivers/mmc/core/block.c | 56 ++++++++++++++++++++-------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index 43f1f1b24b83..2b9ae44f72f9 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -1614,7 +1614,7 @@ static void mmc_blk_rw_start_new(struct mmc_queue *mq, struct mmc_card *card, } } -static void mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc) +static void mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *new_req) { struct mmc_blk_data *md = mq->blkdata; struct mmc_card *card = md->queue.card; @@ -1622,24 +1622,24 @@ static void mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc) int ret = 1, disable_multi = 0, retry = 0, type, retune_retry_done = 0; enum mmc_blk_status status; struct mmc_queue_req *mq_rq; - struct request *req; + struct request *old_req; struct mmc_async_req *new_areq; struct mmc_async_req *old_areq; - if (!rqc && !mq->mqrq_prev->req) + if (!new_req && !mq->mqrq_prev->req) return; do { - if (rqc) { + if (new_req) { /* * When 4KB native sector is enabled, only 8 blocks * multiple read or write is allowed */ if (mmc_large_sector(card) && - !IS_ALIGNED(blk_rq_sectors(rqc), 8)) { + !IS_ALIGNED(blk_rq_sectors(new_req), 8)) { pr_err("%s: Transfer size is not 4KB sector size aligned\n", - rqc->rq_disk->disk_name); - mmc_blk_rw_cmd_abort(card, rqc); + new_req->rq_disk->disk_name); + mmc_blk_rw_cmd_abort(card, new_req); return; } @@ -1666,8 +1666,8 @@ static void mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc) */ mq_rq = container_of(old_areq, struct mmc_queue_req, mmc_active); brq = &mq_rq->brq; - req = mq_rq->req; - type = rq_data_dir(req) == READ ? MMC_BLK_READ : MMC_BLK_WRITE; + old_req = mq_rq->req; + type = rq_data_dir(old_req) == READ ? MMC_BLK_READ : MMC_BLK_WRITE; mmc_queue_bounce_post(mq_rq); switch (status) { @@ -1678,7 +1678,7 @@ static void mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc) */ mmc_blk_reset_success(md, type); - ret = blk_end_request(req, 0, + ret = blk_end_request(old_req, 0, brq->data.bytes_xfered); /* @@ -1688,21 +1688,21 @@ static void mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc) */ if (status == MMC_BLK_SUCCESS && ret) { pr_err("%s BUG rq_tot %d d_xfer %d\n", - __func__, blk_rq_bytes(req), + __func__, blk_rq_bytes(old_req), brq->data.bytes_xfered); - mmc_blk_rw_cmd_abort(card, req); + mmc_blk_rw_cmd_abort(card, old_req); return; } break; case MMC_BLK_CMD_ERR: - ret = mmc_blk_cmd_err(md, card, brq, req, ret); + ret = mmc_blk_cmd_err(md, card, brq, old_req, ret); if (mmc_blk_reset(md, card->host, type)) { - mmc_blk_rw_cmd_abort(card, req); - mmc_blk_rw_start_new(mq, card, rqc); + mmc_blk_rw_cmd_abort(card, old_req); + mmc_blk_rw_start_new(mq, card, new_req); return; } if (!ret) { - mmc_blk_rw_start_new(mq, card, rqc); + mmc_blk_rw_start_new(mq, card, new_req); return; } break; @@ -1714,8 +1714,8 @@ static void mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc) case MMC_BLK_ABORT: if (!mmc_blk_reset(md, card->host, type)) break; - mmc_blk_rw_cmd_abort(card, req); - mmc_blk_rw_start_new(mq, card, rqc); + mmc_blk_rw_cmd_abort(card, old_req); + mmc_blk_rw_start_new(mq, card, new_req); return; case MMC_BLK_DATA_ERR: { int err; @@ -1724,8 +1724,8 @@ static void mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc) if (!err) break; if (err == -ENODEV) { - mmc_blk_rw_cmd_abort(card, req); - mmc_blk_rw_start_new(mq, card, rqc); + mmc_blk_rw_cmd_abort(card, old_req); + mmc_blk_rw_start_new(mq, card, new_req); return; } /* Fall through */ @@ -1734,7 +1734,7 @@ static void mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc) if (brq->data.blocks > 1) { /* Redo read one sector at a time */ pr_warn("%s: retrying using single block read\n", - req->rq_disk->disk_name); + old_req->rq_disk->disk_name); disable_multi = 1; break; } @@ -1743,22 +1743,22 @@ static void mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc) * time, so we only reach here after trying to * read a single sector. */ - ret = blk_end_request(req, -EIO, + ret = blk_end_request(old_req, -EIO, brq->data.blksz); if (!ret) { - mmc_blk_rw_start_new(mq, card, rqc); + mmc_blk_rw_start_new(mq, card, new_req); return; } break; case MMC_BLK_NOMEDIUM: - mmc_blk_rw_cmd_abort(card, req); - mmc_blk_rw_start_new(mq, card, rqc); + mmc_blk_rw_cmd_abort(card, old_req); + mmc_blk_rw_start_new(mq, card, new_req); return; default: pr_err("%s: Unhandled return value (%d)", - req->rq_disk->disk_name, status); - mmc_blk_rw_cmd_abort(card, req); - mmc_blk_rw_start_new(mq, card, rqc); + old_req->rq_disk->disk_name, status); + mmc_blk_rw_cmd_abort(card, old_req); + mmc_blk_rw_start_new(mq, card, new_req); return; } From c3399ef55d8e8295293808eba32e3f7056526324 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 1 Feb 2017 13:47:53 +0100 Subject: [PATCH 122/145] mmc: core: rename mmc_start_req() to *areq() With the coexisting __mmc_start_request(), mmc_start_request() and __mmc_start_req() it is a bit confusing that mmc_start_req() actually does not start a normal request, but an asynchronous request. Rename it to mmc_start_areq() to make it explicit what the function is doing, also fix the kerneldoc for this function while we're at it. Signed-off-by: Linus Walleij Signed-off-by: Ulf Hansson --- drivers/mmc/core/block.c | 8 ++++---- drivers/mmc/core/core.c | 14 +++++++------- drivers/mmc/core/mmc_test.c | 8 ++++---- include/linux/mmc/core.h | 2 +- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index 2b9ae44f72f9..8e1aa8d80e76 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -1609,8 +1609,8 @@ static void mmc_blk_rw_start_new(struct mmc_queue *mq, struct mmc_card *card, blk_end_request_all(req, -EIO); } else { mmc_blk_rw_rq_prep(mq->mqrq_cur, card, 0, mq); - mmc_start_req(card->host, - &mq->mqrq_cur->mmc_active, NULL); + mmc_start_areq(card->host, + &mq->mqrq_cur->mmc_active, NULL); } } @@ -1648,7 +1648,7 @@ static void mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *new_req) } else new_areq = NULL; - old_areq = mmc_start_req(card->host, new_areq, &status); + old_areq = mmc_start_areq(card->host, new_areq, &status); if (!old_areq) { /* * We have just put the first request into the pipeline @@ -1769,7 +1769,7 @@ static void mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *new_req) */ mmc_blk_rw_rq_prep(mq_rq, card, disable_multi, mq); - mmc_start_req(card->host, + mmc_start_areq(card->host, &mq_rq->mmc_active, NULL); mq_rq->brq.retune_retry_done = retune_retry_done; } diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 3b12981e7627..1985841ff1f1 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -631,10 +631,10 @@ static void mmc_post_req(struct mmc_host *host, struct mmc_request *mrq, } /** - * mmc_start_req - start a non-blocking request + * mmc_start_areq - start an asynchronous request * @host: MMC host to start command - * @areq: async request to start - * @error: out parameter returns 0 for success, otherwise non zero + * @areq: asynchronous request to start + * @ret_stat: out parameter for status * * Start a new MMC custom command request for a host. * If there is on ongoing async request wait for completion @@ -646,9 +646,9 @@ static void mmc_post_req(struct mmc_host *host, struct mmc_request *mrq, * return the completed request. If there is no ongoing request, NULL * is returned without waiting. NULL is not an error condition. */ -struct mmc_async_req *mmc_start_req(struct mmc_host *host, - struct mmc_async_req *areq, - enum mmc_blk_status *ret_stat) +struct mmc_async_req *mmc_start_areq(struct mmc_host *host, + struct mmc_async_req *areq, + enum mmc_blk_status *ret_stat) { enum mmc_blk_status status = MMC_BLK_SUCCESS; int start_err = 0; @@ -699,7 +699,7 @@ struct mmc_async_req *mmc_start_req(struct mmc_host *host, *ret_stat = status; return data; } -EXPORT_SYMBOL(mmc_start_req); +EXPORT_SYMBOL(mmc_start_areq); /** * mmc_wait_for_req - start a request and wait for completion diff --git a/drivers/mmc/core/mmc_test.c b/drivers/mmc/core/mmc_test.c index 83d193c09d98..f99ac3123fd2 100644 --- a/drivers/mmc/core/mmc_test.c +++ b/drivers/mmc/core/mmc_test.c @@ -853,7 +853,7 @@ static int mmc_test_nonblock_transfer(struct mmc_test_card *test, for (i = 0; i < count; i++) { mmc_test_prepare_mrq(test, cur_areq->mrq, sg, sg_len, dev_addr, blocks, blksz, write); - done_areq = mmc_start_req(test->card->host, cur_areq, &status); + done_areq = mmc_start_areq(test->card->host, cur_areq, &status); if (status != MMC_BLK_SUCCESS || (!done_areq && i > 0)) { ret = RESULT_FAIL; @@ -872,7 +872,7 @@ static int mmc_test_nonblock_transfer(struct mmc_test_card *test, dev_addr += blocks; } - done_areq = mmc_start_req(test->card->host, NULL, &status); + done_areq = mmc_start_areq(test->card->host, NULL, &status); if (status != MMC_BLK_SUCCESS) ret = RESULT_FAIL; @@ -2402,7 +2402,7 @@ static int mmc_test_ongoing_transfer(struct mmc_test_card *test, /* Start ongoing data request */ if (use_areq) { - mmc_start_req(host, &test_areq.areq, &blkstat); + mmc_start_areq(host, &test_areq.areq, &blkstat); if (blkstat != MMC_BLK_SUCCESS) { ret = RESULT_FAIL; goto out_free; @@ -2440,7 +2440,7 @@ static int mmc_test_ongoing_transfer(struct mmc_test_card *test, /* Wait for data request to complete */ if (use_areq) { - mmc_start_req(host, NULL, &blkstat); + mmc_start_areq(host, NULL, &blkstat); if (blkstat != MMC_BLK_SUCCESS) ret = RESULT_FAIL; } else { diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h index 6dcb339fcd45..a0c63ea28796 100644 --- a/include/linux/mmc/core.h +++ b/include/linux/mmc/core.h @@ -158,7 +158,7 @@ struct mmc_request { struct mmc_card; struct mmc_async_req; -struct mmc_async_req *mmc_start_req(struct mmc_host *host, +struct mmc_async_req *mmc_start_areq(struct mmc_host *host, struct mmc_async_req *areq, enum mmc_blk_status *ret_stat); void mmc_wait_for_req(struct mmc_host *host, struct mmc_request *mrq); From b2928e1049e1d96ac794293d18168c721dbfdb24 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 1 Feb 2017 13:47:54 +0100 Subject: [PATCH 123/145] mmc: block: refactor mmc_blk_rw_try_restart() The mmc_blk_rw_start_new() was named after the label inside mmc_blk_issue_rw_rq() but is really a confusing name for this function: what it does is to try to restart the latest issued command on the host and card of the current MMC queue. So rename it mmc_blk_rw_try_restart() that reflects what it is doing and at this point also refactore the function to treat the removed card as an exception and just exit if this happens and run on in the function if that is not happening. Signed-off-by: Linus Walleij Signed-off-by: Ulf Hansson --- drivers/mmc/core/block.c | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index 8e1aa8d80e76..1761ab238483 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -1598,20 +1598,27 @@ static void mmc_blk_rw_cmd_abort(struct mmc_card *card, struct request *req) blk_rq_cur_bytes(req)); } -static void mmc_blk_rw_start_new(struct mmc_queue *mq, struct mmc_card *card, - struct request *req) +/** + * mmc_blk_rw_try_restart() - tries to restart the current async request + * @mq: the queue with the card and host to restart + * @req: a new request that want to be started after the current one + */ +static void mmc_blk_rw_try_restart(struct mmc_queue *mq, struct request *req) { if (!req) return; - if (mmc_card_removed(card)) { + /* + * If the card was removed, just cancel everything and return. + */ + if (mmc_card_removed(mq->card)) { req->rq_flags |= RQF_QUIET; blk_end_request_all(req, -EIO); - } else { - mmc_blk_rw_rq_prep(mq->mqrq_cur, card, 0, mq); - mmc_start_areq(card->host, - &mq->mqrq_cur->mmc_active, NULL); + return; } + /* Else proceed and try to restart the current async request */ + mmc_blk_rw_rq_prep(mq->mqrq_cur, mq->card, 0, mq); + mmc_start_areq(mq->card->host, &mq->mqrq_cur->mmc_active, NULL); } static void mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *new_req) @@ -1698,11 +1705,11 @@ static void mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *new_req) ret = mmc_blk_cmd_err(md, card, brq, old_req, ret); if (mmc_blk_reset(md, card->host, type)) { mmc_blk_rw_cmd_abort(card, old_req); - mmc_blk_rw_start_new(mq, card, new_req); + mmc_blk_rw_try_restart(mq, new_req); return; } if (!ret) { - mmc_blk_rw_start_new(mq, card, new_req); + mmc_blk_rw_try_restart(mq, new_req); return; } break; @@ -1715,7 +1722,7 @@ static void mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *new_req) if (!mmc_blk_reset(md, card->host, type)) break; mmc_blk_rw_cmd_abort(card, old_req); - mmc_blk_rw_start_new(mq, card, new_req); + mmc_blk_rw_try_restart(mq, new_req); return; case MMC_BLK_DATA_ERR: { int err; @@ -1725,7 +1732,7 @@ static void mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *new_req) break; if (err == -ENODEV) { mmc_blk_rw_cmd_abort(card, old_req); - mmc_blk_rw_start_new(mq, card, new_req); + mmc_blk_rw_try_restart(mq, new_req); return; } /* Fall through */ @@ -1746,19 +1753,19 @@ static void mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *new_req) ret = blk_end_request(old_req, -EIO, brq->data.blksz); if (!ret) { - mmc_blk_rw_start_new(mq, card, new_req); + mmc_blk_rw_try_restart(mq, new_req); return; } break; case MMC_BLK_NOMEDIUM: mmc_blk_rw_cmd_abort(card, old_req); - mmc_blk_rw_start_new(mq, card, new_req); + mmc_blk_rw_try_restart(mq, new_req); return; default: pr_err("%s: Unhandled return value (%d)", old_req->rq_disk->disk_name, status); mmc_blk_rw_cmd_abort(card, old_req); - mmc_blk_rw_start_new(mq, card, new_req); + mmc_blk_rw_try_restart(mq, new_req); return; } From 74f5ba357c7cd63c664e65fb7a116dbc0538a2ec Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 1 Feb 2017 13:47:55 +0100 Subject: [PATCH 124/145] mmc: block: rename mmc_active to areq The mmc_active member of struct mmc_queue_req has a very confusing name: this is certainly not always "active", it is the asynchronous request associated by the mmc_queue_req but it is not guaranteed to be "active" in any sense, such as being running on the host. Simply rename this member to "areq". Signed-off-by: Linus Walleij Signed-off-by: Ulf Hansson --- drivers/mmc/core/block.c | 14 +++++++------- drivers/mmc/core/queue.h | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index 1761ab238483..2a3e9e678a23 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -1297,7 +1297,7 @@ static enum mmc_blk_status mmc_blk_err_check(struct mmc_card *card, struct mmc_async_req *areq) { struct mmc_queue_req *mq_mrq = container_of(areq, struct mmc_queue_req, - mmc_active); + areq); struct mmc_blk_request *brq = &mq_mrq->brq; struct request *req = mq_mrq->req; int need_retune = card->host->need_retune; @@ -1553,8 +1553,8 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq, brq->data.sg_len = i; } - mqrq->mmc_active.mrq = &brq->mrq; - mqrq->mmc_active.err_check = mmc_blk_err_check; + mqrq->areq.mrq = &brq->mrq; + mqrq->areq.err_check = mmc_blk_err_check; mmc_queue_bounce_pre(mqrq); } @@ -1618,7 +1618,7 @@ static void mmc_blk_rw_try_restart(struct mmc_queue *mq, struct request *req) } /* Else proceed and try to restart the current async request */ mmc_blk_rw_rq_prep(mq->mqrq_cur, mq->card, 0, mq); - mmc_start_areq(mq->card->host, &mq->mqrq_cur->mmc_active, NULL); + mmc_start_areq(mq->card->host, &mq->mqrq_cur->areq, NULL); } static void mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *new_req) @@ -1651,7 +1651,7 @@ static void mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *new_req) } mmc_blk_rw_rq_prep(mq->mqrq_cur, card, 0, mq); - new_areq = &mq->mqrq_cur->mmc_active; + new_areq = &mq->mqrq_cur->areq; } else new_areq = NULL; @@ -1671,7 +1671,7 @@ static void mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *new_req) * An asynchronous request has been completed and we proceed * to handle the result of it. */ - mq_rq = container_of(old_areq, struct mmc_queue_req, mmc_active); + mq_rq = container_of(old_areq, struct mmc_queue_req, areq); brq = &mq_rq->brq; old_req = mq_rq->req; type = rq_data_dir(old_req) == READ ? MMC_BLK_READ : MMC_BLK_WRITE; @@ -1777,7 +1777,7 @@ static void mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *new_req) mmc_blk_rw_rq_prep(mq_rq, card, disable_multi, mq); mmc_start_areq(card->host, - &mq_rq->mmc_active, NULL); + &mq_rq->areq, NULL); mq_rq->brq.retune_retry_done = retune_retry_done; } } while (ret); diff --git a/drivers/mmc/core/queue.h b/drivers/mmc/core/queue.h index 0cea02af79d1..e0cd5b1f40ee 100644 --- a/drivers/mmc/core/queue.h +++ b/drivers/mmc/core/queue.h @@ -33,7 +33,7 @@ struct mmc_queue_req { char *bounce_buf; struct scatterlist *bounce_sg; unsigned int bounce_sg_len; - struct mmc_async_req mmc_active; + struct mmc_async_req areq; }; struct mmc_queue { From 9491be5ff06ff08d61e6a8d767382ea0037a6f38 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 1 Feb 2017 13:47:56 +0100 Subject: [PATCH 125/145] mmc: queue: turn queue flags into bools Instead of masking and setting two bits in the "flags" field for the mmc_queue, just use two bools named "suspended" and "new_request". The masking and setting would likely have race conditions anyways, it is better to use a simple member like this. Signed-off-by: Linus Walleij Signed-off-by: Ulf Hansson --- drivers/mmc/core/block.c | 6 +++--- drivers/mmc/core/queue.c | 12 ++++++------ drivers/mmc/core/queue.h | 5 ++--- 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index 2a3e9e678a23..7f0b9af8229c 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -1663,7 +1663,7 @@ static void mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *new_req) * complete. */ if (status == MMC_BLK_NEW_REQUEST) - mq->flags |= MMC_QUEUE_NEW_REQUEST; + mq->new_request = true; return; } @@ -1802,7 +1802,7 @@ void mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) goto out; } - mq->flags &= ~MMC_QUEUE_NEW_REQUEST; + mq->new_request = false; if (req && req_op(req) == REQ_OP_DISCARD) { /* complete ongoing async transfer before issuing discard */ if (card->host->areq) @@ -1823,7 +1823,7 @@ void mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) } out: - if ((!req && !(mq->flags & MMC_QUEUE_NEW_REQUEST)) || req_is_special) + if ((!req && !mq->new_request) || req_is_special) /* * Release host when there are no more requests * and after special request(discard, flush) is done. diff --git a/drivers/mmc/core/queue.c b/drivers/mmc/core/queue.c index 611f5c6d1950..5cb369c2664b 100644 --- a/drivers/mmc/core/queue.c +++ b/drivers/mmc/core/queue.c @@ -86,8 +86,8 @@ static int mmc_queue_thread(void *d) set_current_state(TASK_RUNNING); mmc_blk_issue_rq(mq, req); cond_resched(); - if (mq->flags & MMC_QUEUE_NEW_REQUEST) { - mq->flags &= ~MMC_QUEUE_NEW_REQUEST; + if (mq->new_request) { + mq->new_request = false; continue; /* fetch again */ } @@ -401,8 +401,8 @@ void mmc_queue_suspend(struct mmc_queue *mq) struct request_queue *q = mq->queue; unsigned long flags; - if (!(mq->flags & MMC_QUEUE_SUSPENDED)) { - mq->flags |= MMC_QUEUE_SUSPENDED; + if (!mq->suspended) { + mq->suspended |= true; spin_lock_irqsave(q->queue_lock, flags); blk_stop_queue(q); @@ -421,8 +421,8 @@ void mmc_queue_resume(struct mmc_queue *mq) struct request_queue *q = mq->queue; unsigned long flags; - if (mq->flags & MMC_QUEUE_SUSPENDED) { - mq->flags &= ~MMC_QUEUE_SUSPENDED; + if (mq->suspended) { + mq->suspended = false; up(&mq->thread_sem); diff --git a/drivers/mmc/core/queue.h b/drivers/mmc/core/queue.h index e0cd5b1f40ee..e298f100101b 100644 --- a/drivers/mmc/core/queue.h +++ b/drivers/mmc/core/queue.h @@ -40,9 +40,8 @@ struct mmc_queue { struct mmc_card *card; struct task_struct *thread; struct semaphore thread_sem; - unsigned int flags; -#define MMC_QUEUE_SUSPENDED (1 << 0) -#define MMC_QUEUE_NEW_REQUEST (1 << 1) + bool new_request; + bool suspended; bool asleep; struct mmc_blk_data *blkdata; struct request_queue *queue; From 169f03a064c230de6d715bdd62112eb12256fce3 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 1 Feb 2017 13:47:57 +0100 Subject: [PATCH 126/145] mmc: block: return errorcode from mmc_sd_num_wr_blocks() mmc_sd_num_wr_blocks() has an interesting construction that saves one return argument by casting (u32)-1 as error code if something goes wrong. This is however a bit confusing when the normal kernel pattern is to return an int error code on success. So instead pass a variable "blocks" that the function can fill in with the number of successfully transferred blocks and return an integer as error code. Signed-off-by: Linus Walleij Signed-off-by: Ulf Hansson [Ulf: Changed a return code to -EIO, reported by Dan Carpenter and fixed by Linus Walleij] --- drivers/mmc/core/block.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index 7f0b9af8229c..26191b8bea72 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -763,7 +763,7 @@ static inline int mmc_blk_part_switch(struct mmc_card *card, return 0; } -static u32 mmc_sd_num_wr_blocks(struct mmc_card *card) +static int mmc_sd_num_wr_blocks(struct mmc_card *card, u32 *written_blocks) { int err; u32 result; @@ -781,9 +781,9 @@ static u32 mmc_sd_num_wr_blocks(struct mmc_card *card) err = mmc_wait_for_cmd(card->host, &cmd, 0); if (err) - return (u32)-1; + return err; if (!mmc_host_is_spi(card->host) && !(cmd.resp[0] & R1_APP_CMD)) - return (u32)-1; + return -EIO; memset(&cmd, 0, sizeof(struct mmc_command)); @@ -803,7 +803,7 @@ static u32 mmc_sd_num_wr_blocks(struct mmc_card *card) blocks = kmalloc(4, GFP_KERNEL); if (!blocks) - return (u32)-1; + return -ENOMEM; sg_init_one(&sg, blocks, 4); @@ -813,9 +813,11 @@ static u32 mmc_sd_num_wr_blocks(struct mmc_card *card) kfree(blocks); if (cmd.error || data.error) - result = (u32)-1; + return -EIO; - return result; + *written_blocks = result; + + return 0; } static int get_card_status(struct mmc_card *card, u32 *status, int retries) @@ -1576,9 +1578,10 @@ static int mmc_blk_cmd_err(struct mmc_blk_data *md, struct mmc_card *card, */ if (mmc_card_sd(card)) { u32 blocks; + int err; - blocks = mmc_sd_num_wr_blocks(card); - if (blocks != (u32)-1) { + err = mmc_sd_num_wr_blocks(card, &blocks); + if (!err) { ret = blk_end_request(req, 0, blocks << 9); } } else { From 0e65f10cf1774a27acf9e933e006f1e55a4ef642 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 1 Feb 2017 13:47:58 +0100 Subject: [PATCH 127/145] mmc: block: respect bool returned from blk_end_request() The return value from blk_end_request() is a bool but is treated like an int. This is generally safe, but the variable also has the opaque name "ret" and gets returned from the helper function mmc_blk_cmd_err(). - Switch the variable to a bool, applies everywhere. - Return a bool from mmc_blk_cmd_err() and rename the function mmc_blk_rw_cmd_err() to indicate through the namespace that this is a helper for mmc_blk_issue_rw_rq(). - Rename the variable from "ret" to "req_pending" inside the while() loop inside mmc_blk_issue_rq_rq(), which finally makes it very clear what this while loop is waiting for. - Augment the argument "ret" to mmc_blk_rq_cmd_err() to old_req_pending so it becomes evident that this is an older state, and it is returned only if we fail to get the number of written blocks from an SD card in the function mmc_sd_num_wr_blocks(). - Augment the while() loop in mmc_blk_rq_cmd_abort(): it is evident now that we know this is a bool variable, that the function is just spinning waiting for blk_end_request() to return false. Signed-off-by: Linus Walleij Signed-off-by: Ulf Hansson --- drivers/mmc/core/block.c | 49 ++++++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 25 deletions(-) diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index 26191b8bea72..cd909aecfded 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -1561,11 +1561,13 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq, mmc_queue_bounce_pre(mqrq); } -static int mmc_blk_cmd_err(struct mmc_blk_data *md, struct mmc_card *card, - struct mmc_blk_request *brq, struct request *req, - int ret) +static bool mmc_blk_rw_cmd_err(struct mmc_blk_data *md, struct mmc_card *card, + struct mmc_blk_request *brq, struct request *req, + bool old_req_pending) { struct mmc_queue_req *mq_rq; + bool req_pending; + mq_rq = container_of(brq, struct mmc_queue_req, brq); /* @@ -1581,24 +1583,21 @@ static int mmc_blk_cmd_err(struct mmc_blk_data *md, struct mmc_card *card, int err; err = mmc_sd_num_wr_blocks(card, &blocks); - if (!err) { - ret = blk_end_request(req, 0, blocks << 9); - } + if (err) + req_pending = old_req_pending; + else + req_pending = blk_end_request(req, 0, blocks << 9); } else { - ret = blk_end_request(req, 0, brq->data.bytes_xfered); + req_pending = blk_end_request(req, 0, brq->data.bytes_xfered); } - return ret; + return req_pending; } static void mmc_blk_rw_cmd_abort(struct mmc_card *card, struct request *req) { - int ret = 1; - if (mmc_card_removed(card)) req->rq_flags |= RQF_QUIET; - while (ret) - ret = blk_end_request(req, -EIO, - blk_rq_cur_bytes(req)); + while (blk_end_request(req, -EIO, blk_rq_cur_bytes(req))); } /** @@ -1629,12 +1628,13 @@ static void mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *new_req) struct mmc_blk_data *md = mq->blkdata; struct mmc_card *card = md->queue.card; struct mmc_blk_request *brq; - int ret = 1, disable_multi = 0, retry = 0, type, retune_retry_done = 0; + int disable_multi = 0, retry = 0, type, retune_retry_done = 0; enum mmc_blk_status status; struct mmc_queue_req *mq_rq; struct request *old_req; struct mmc_async_req *new_areq; struct mmc_async_req *old_areq; + bool req_pending = true; if (!new_req && !mq->mqrq_prev->req) return; @@ -1688,15 +1688,14 @@ static void mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *new_req) */ mmc_blk_reset_success(md, type); - ret = blk_end_request(old_req, 0, - brq->data.bytes_xfered); - + req_pending = blk_end_request(old_req, 0, + brq->data.bytes_xfered); /* * If the blk_end_request function returns non-zero even * though all data has been transferred and no errors * were returned by the host controller, it's a bug. */ - if (status == MMC_BLK_SUCCESS && ret) { + if (status == MMC_BLK_SUCCESS && req_pending) { pr_err("%s BUG rq_tot %d d_xfer %d\n", __func__, blk_rq_bytes(old_req), brq->data.bytes_xfered); @@ -1705,13 +1704,13 @@ static void mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *new_req) } break; case MMC_BLK_CMD_ERR: - ret = mmc_blk_cmd_err(md, card, brq, old_req, ret); + req_pending = mmc_blk_rw_cmd_err(md, card, brq, old_req, req_pending); if (mmc_blk_reset(md, card->host, type)) { mmc_blk_rw_cmd_abort(card, old_req); mmc_blk_rw_try_restart(mq, new_req); return; } - if (!ret) { + if (!req_pending) { mmc_blk_rw_try_restart(mq, new_req); return; } @@ -1753,9 +1752,9 @@ static void mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *new_req) * time, so we only reach here after trying to * read a single sector. */ - ret = blk_end_request(old_req, -EIO, - brq->data.blksz); - if (!ret) { + req_pending = blk_end_request(old_req, -EIO, + brq->data.blksz); + if (!req_pending) { mmc_blk_rw_try_restart(mq, new_req); return; } @@ -1772,7 +1771,7 @@ static void mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *new_req) return; } - if (ret) { + if (req_pending) { /* * In case of a incomplete request * prepare it again and resend. @@ -1783,7 +1782,7 @@ static void mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *new_req) &mq_rq->areq, NULL); mq_rq->brq.retune_retry_done = retune_retry_done; } - } while (ret); + } while (req_pending); } void mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) From 37dac0681e2be4f3c32b090a8c0591d4ce57e6f0 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 1 Feb 2017 13:48:00 +0100 Subject: [PATCH 128/145] mmc: core: start to break apart mmc_start_areq() This function is doing to many clever things at the same time under too many various conditions. Start to make things clearer by refactoring: break out the finalization of the previous asynchronous request to its own function mmc_finalize_areq(). We can get rid of the default assignment of status and let the call deal with this. Signed-off-by: Linus Walleij Signed-off-by: Ulf Hansson --- drivers/mmc/core/core.c | 65 +++++++++++++++++++++++++++-------------- 1 file changed, 43 insertions(+), 22 deletions(-) diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 1985841ff1f1..926e0fde07d7 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -630,6 +630,37 @@ static void mmc_post_req(struct mmc_host *host, struct mmc_request *mrq, host->ops->post_req(host, mrq, err); } +/** + * mmc_finalize_areq() - finalize an asynchronous request + * @host: MMC host to finalize any ongoing request on + * + * Returns the status of the ongoing asynchronous request, but + * MMC_BLK_SUCCESS if no request was going on. + */ +static enum mmc_blk_status mmc_finalize_areq(struct mmc_host *host) +{ + enum mmc_blk_status status; + + if (!host->areq) + return MMC_BLK_SUCCESS; + + status = mmc_wait_for_data_req_done(host, host->areq->mrq); + if (status == MMC_BLK_NEW_REQUEST) + return status; + + /* + * Check BKOPS urgency for each R1 response + */ + if (host->card && mmc_card_mmc(host->card) && + ((mmc_resp_type(host->areq->mrq->cmd) == MMC_RSP_R1) || + (mmc_resp_type(host->areq->mrq->cmd) == MMC_RSP_R1B)) && + (host->areq->mrq->cmd->resp[0] & R1_EXCEPTION_EVENT)) { + mmc_start_bkops(host->card, true); + } + + return status; +} + /** * mmc_start_areq - start an asynchronous request * @host: MMC host to start command @@ -650,7 +681,7 @@ struct mmc_async_req *mmc_start_areq(struct mmc_host *host, struct mmc_async_req *areq, enum mmc_blk_status *ret_stat) { - enum mmc_blk_status status = MMC_BLK_SUCCESS; + enum mmc_blk_status status; int start_err = 0; struct mmc_async_req *data = host->areq; @@ -658,35 +689,25 @@ struct mmc_async_req *mmc_start_areq(struct mmc_host *host, if (areq) mmc_pre_req(host, areq->mrq); - if (host->areq) { - status = mmc_wait_for_data_req_done(host, host->areq->mrq); - if (status == MMC_BLK_NEW_REQUEST) { - if (ret_stat) - *ret_stat = status; - /* - * The previous request was not completed, - * nothing to return - */ - return NULL; - } - /* - * Check BKOPS urgency for each R1 response - */ - if (host->card && mmc_card_mmc(host->card) && - ((mmc_resp_type(host->areq->mrq->cmd) == MMC_RSP_R1) || - (mmc_resp_type(host->areq->mrq->cmd) == MMC_RSP_R1B)) && - (host->areq->mrq->cmd->resp[0] & R1_EXCEPTION_EVENT)) { - mmc_start_bkops(host->card, true); - } + /* Finalize previous request */ + status = mmc_finalize_areq(host); + + /* The previous request is still going on... */ + if (status == MMC_BLK_NEW_REQUEST) { + if (ret_stat) + *ret_stat = status; + return NULL; } + /* Fine so far, start the new request! */ if (status == MMC_BLK_SUCCESS && areq) start_err = __mmc_start_data_req(host, areq->mrq); + /* Postprocess the old request at this point */ if (host->areq) mmc_post_req(host, host->areq->mrq, 0); - /* Cancel a prepared request if it was not started. */ + /* Cancel a prepared request if it was not started. */ if ((status != MMC_BLK_SUCCESS || start_err) && areq) mmc_post_req(host, areq->mrq, -EINVAL); From a4c38c8dba98643602ae08c0867425b20a3c204b Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Wed, 8 Feb 2017 12:36:20 +0100 Subject: [PATCH 129/145] mmc: meson: Assign the minimum clk rate as close to 400KHz as possible The current code dealing with calculating mmc->f_min is a bit complicated. Additionally, the attempt to set an initial clock rate should explicitly use a rate between 100KHz to 400 KHz, according the (e)MMC/SD specs, which it doesn't. Fix the problem and clean up the code by using clk_round_rate() to pick the nearest minimum rate to 400KHz (rounded down from 400kHz). Signed-off-by: Ulf Hansson [Heiner: Changed from 100KHz to 400KHz to get a proper rounded rate] Signed-off-by: Heiner Kallweit --- drivers/mmc/host/meson-gx-mmc.c | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/drivers/mmc/host/meson-gx-mmc.c b/drivers/mmc/host/meson-gx-mmc.c index 5eca88bcd562..ef2ce725c31d 100644 --- a/drivers/mmc/host/meson-gx-mmc.c +++ b/drivers/mmc/host/meson-gx-mmc.c @@ -132,7 +132,6 @@ struct meson_host { struct clk_mux mux; struct clk *mux_clk; struct clk *mux_parent[MUX_CLK_NUM_PARENTS]; - unsigned long mux_parent_rate[MUX_CLK_NUM_PARENTS]; struct clk_divider cfg_div; struct clk *cfg_div_clk; @@ -240,7 +239,6 @@ static int meson_mmc_clk_init(struct meson_host *host) const char *mux_parent_names[MUX_CLK_NUM_PARENTS]; unsigned int mux_parent_count = 0; const char *clk_div_parents[1]; - unsigned int f_min = UINT_MAX; u32 clk_reg, cfg; /* get the mux parents */ @@ -257,20 +255,10 @@ static int meson_mmc_clk_init(struct meson_host *host) return ret; } - host->mux_parent_rate[i] = clk_get_rate(host->mux_parent[i]); mux_parent_names[i] = __clk_get_name(host->mux_parent[i]); mux_parent_count++; - if (host->mux_parent_rate[i] < f_min) - f_min = host->mux_parent_rate[i]; } - /* cacluate f_min based on input clocks, and max divider value */ - if (f_min != UINT_MAX) - f_min = DIV_ROUND_UP(CLK_SRC_XTAL_RATE, CLK_DIV_MAX); - else - f_min = 4000000; /* default min: 400 MHz */ - host->mmc->f_min = f_min; - /* create the mux */ snprintf(clk_name, sizeof(clk_name), "%s#mux", dev_name(host->dev)); init.name = clk_name; @@ -325,9 +313,13 @@ static int meson_mmc_clk_init(struct meson_host *host) writel(cfg, host->regs + SD_EMMC_CFG); ret = clk_prepare_enable(host->cfg_div_clk); - if (!ret) - ret = meson_mmc_clk_set(host, f_min); + if (ret) + return ret; + /* Get the nearest minimum clock to 400KHz */ + host->mmc->f_min = clk_round_rate(host->cfg_div_clk, 400000); + + ret = meson_mmc_clk_set(host, host->mmc->f_min); if (!ret) clk_disable_unprepare(host->cfg_div_clk); From 3d45c86f92be4cd22b4d2332a5cc280e20efedc6 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Tue, 7 Feb 2017 22:34:06 +0100 Subject: [PATCH 130/145] mmc: meson-gx: minor improvements in meson_mmc_set_ios val isn't used in the switch clause and afterwards there's an identical statement. So remove it. In case of an unexpected bus width the error message indicates the intention to set the bus width to 4 and to go on. So remove the return statement. This return statement also conflicts with "setting to 4" because nothing would be set actually before returning. 4bit bus width are chosen as default as the vendor driver does it too. Signed-off-by: Heiner Kallweit Acked-by: Kevin Hilman Signed-off-by: Ulf Hansson --- drivers/mmc/host/meson-gx-mmc.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/mmc/host/meson-gx-mmc.c b/drivers/mmc/host/meson-gx-mmc.c index ef2ce725c31d..9d79df7ca214 100644 --- a/drivers/mmc/host/meson-gx-mmc.c +++ b/drivers/mmc/host/meson-gx-mmc.c @@ -371,7 +371,6 @@ static void meson_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) meson_mmc_clk_set(host, ios->clock); /* Bus width */ - val = readl(host->regs + SD_EMMC_CFG); switch (ios->bus_width) { case MMC_BUS_WIDTH_1: bus_width = CFG_BUS_WIDTH_1; @@ -386,7 +385,6 @@ static void meson_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) dev_err(host->dev, "Invalid ios->bus_width: %u. Setting to 4.\n", ios->bus_width); bus_width = CFG_BUS_WIDTH_4; - return; } val = readl(host->regs + SD_EMMC_CFG); From 5da86887638d7a833c75880b7fd8ba738aa102a7 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Tue, 7 Feb 2017 22:34:32 +0100 Subject: [PATCH 131/145] mmc: meson-gx: improve meson_mmc_clk_set The following changes are quite small, therefore I combined them in one patch. - ret doesn't need to be initialized with 0 - use standard !clk_rate notation to check for a zero value - If clk_rate is zero we return here. Therefore all further checks in this function for clk_rate != 0 are not needed. - switch from dev_warn to dev_err if the clock can't be set - If due to clock source and available divider values the requested frequency isn't matched exactly (always the case if requested frequency is 52 MHz), then just print the differing values as debug message and not as warning. - Also remove ret from the message as it is always 0. - Set member current_clock to the current requested rate and mmc->actual_clock to the current actual rate Signed-off-by: Heiner Kallweit Signed-off-by: Ulf Hansson --- drivers/mmc/host/meson-gx-mmc.c | 42 +++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/drivers/mmc/host/meson-gx-mmc.c b/drivers/mmc/host/meson-gx-mmc.c index 9d79df7ca214..d6a4dfae5ed7 100644 --- a/drivers/mmc/host/meson-gx-mmc.c +++ b/drivers/mmc/host/meson-gx-mmc.c @@ -132,6 +132,7 @@ struct meson_host { struct clk_mux mux; struct clk *mux_clk; struct clk *mux_parent[MUX_CLK_NUM_PARENTS]; + unsigned long current_clock; struct clk_divider cfg_div; struct clk *cfg_div_clk; @@ -178,7 +179,7 @@ struct sd_emmc_desc { static int meson_mmc_clk_set(struct meson_host *host, unsigned long clk_rate) { struct mmc_host *mmc = host->mmc; - int ret = 0; + int ret; u32 cfg; if (clk_rate) { @@ -188,7 +189,7 @@ static int meson_mmc_clk_set(struct meson_host *host, unsigned long clk_rate) clk_rate = mmc->f_min; } - if (clk_rate == mmc->actual_clock) + if (clk_rate == host->current_clock) return 0; /* stop clock */ @@ -201,29 +202,34 @@ static int meson_mmc_clk_set(struct meson_host *host, unsigned long clk_rate) dev_dbg(host->dev, "change clock rate %u -> %lu\n", mmc->actual_clock, clk_rate); - if (clk_rate == 0) { + if (!clk_rate) { mmc->actual_clock = 0; + host->current_clock = 0; + /* return with clock being stopped */ return 0; } ret = clk_set_rate(host->cfg_div_clk, clk_rate); - if (ret) - dev_warn(host->dev, "Unable to set cfg_div_clk to %lu. ret=%d\n", - clk_rate, ret); - else if (clk_rate && clk_rate != clk_get_rate(host->cfg_div_clk)) - dev_warn(host->dev, "divider requested rate %lu != actual rate %lu: ret=%d\n", - clk_rate, clk_get_rate(host->cfg_div_clk), ret); - else - mmc->actual_clock = clk_rate; - - /* (re)start clock, if non-zero */ - if (!ret && clk_rate) { - cfg = readl(host->regs + SD_EMMC_CFG); - cfg &= ~CFG_STOP_CLOCK; - writel(cfg, host->regs + SD_EMMC_CFG); + if (ret) { + dev_err(host->dev, "Unable to set cfg_div_clk to %lu. ret=%d\n", + clk_rate, ret); + return ret; } - return ret; + mmc->actual_clock = clk_get_rate(host->cfg_div_clk); + host->current_clock = clk_rate; + + if (clk_rate != mmc->actual_clock) + dev_dbg(host->dev, + "divider requested rate %lu != actual rate %u\n", + clk_rate, mmc->actual_clock); + + /* (re)start clock */ + cfg = readl(host->regs + SD_EMMC_CFG); + cfg &= ~CFG_STOP_CLOCK; + writel(cfg, host->regs + SD_EMMC_CFG); + + return 0; } /* From 690f90b628aaa5800244d0c6d06f2c0fa2d57e22 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Tue, 7 Feb 2017 22:34:41 +0100 Subject: [PATCH 132/145] mmc: meson-gx: improve meson_mmc_irq_thread Remove unneeded variable ret and simplify the if block. Signed-off-by: Heiner Kallweit Acked-by: Kevin Hilman Signed-off-by: Ulf Hansson --- drivers/mmc/host/meson-gx-mmc.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/drivers/mmc/host/meson-gx-mmc.c b/drivers/mmc/host/meson-gx-mmc.c index d6a4dfae5ed7..dd7f936c974e 100644 --- a/drivers/mmc/host/meson-gx-mmc.c +++ b/drivers/mmc/host/meson-gx-mmc.c @@ -666,7 +666,6 @@ static irqreturn_t meson_mmc_irq_thread(int irq, void *dev_id) struct mmc_command *cmd = host->cmd; struct mmc_data *data; unsigned int xfer_bytes; - int ret = IRQ_HANDLED; if (WARN_ON(!mrq)) return IRQ_NONE; @@ -675,14 +674,12 @@ static irqreturn_t meson_mmc_irq_thread(int irq, void *dev_id) return IRQ_NONE; data = cmd->data; - if (data) { + if (data && data->flags & MMC_DATA_READ) { xfer_bytes = data->blksz * data->blocks; - if (data->flags & MMC_DATA_READ) { - WARN_ON(xfer_bytes > host->bounce_buf_size); - sg_copy_from_buffer(data->sg, data->sg_len, - host->bounce_buf, xfer_bytes); - data->bytes_xfered = xfer_bytes; - } + WARN_ON(xfer_bytes > host->bounce_buf_size); + sg_copy_from_buffer(data->sg, data->sg_len, + host->bounce_buf, xfer_bytes); + data->bytes_xfered = xfer_bytes; } meson_mmc_read_resp(host->mmc, cmd); @@ -691,7 +688,7 @@ static irqreturn_t meson_mmc_irq_thread(int irq, void *dev_id) else meson_mmc_start_cmd(host->mmc, data->stop); - return ret; + return IRQ_HANDLED; } /* From 92763b997e468700b26a8fdddc5bee3e3c2a39fa Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Tue, 7 Feb 2017 22:34:51 +0100 Subject: [PATCH 133/145] mmc: meson-gx: improve interrupt handling Disabling and immediately re-enabling interrupts in meson_mmc_request doesn't provide a benefit. Instead enable interrupts in probe already. And disable interrupts in remove, this was missing so far. Signed-off-by: Heiner Kallweit Reviewed-by: Kevin Hilman Signed-off-by: Ulf Hansson --- drivers/mmc/host/meson-gx-mmc.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/mmc/host/meson-gx-mmc.c b/drivers/mmc/host/meson-gx-mmc.c index dd7f936c974e..4c622ad26a70 100644 --- a/drivers/mmc/host/meson-gx-mmc.c +++ b/drivers/mmc/host/meson-gx-mmc.c @@ -542,11 +542,6 @@ static void meson_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq) /* Stop execution */ writel(0, host->regs + SD_EMMC_START); - /* clear, ack, enable all interrupts */ - writel(0, host->regs + SD_EMMC_IRQ_EN); - writel(IRQ_EN_MASK, host->regs + SD_EMMC_STATUS); - writel(IRQ_EN_MASK, host->regs + SD_EMMC_IRQ_EN); - host->mrq = mrq; if (mrq->sbc) @@ -775,6 +770,7 @@ static int meson_mmc_probe(struct platform_device *pdev) /* clear, ack, enable all interrupts */ writel(0, host->regs + SD_EMMC_IRQ_EN); writel(IRQ_EN_MASK, host->regs + SD_EMMC_STATUS); + writel(IRQ_EN_MASK, host->regs + SD_EMMC_IRQ_EN); ret = devm_request_threaded_irq(&pdev->dev, host->irq, meson_mmc_irq, meson_mmc_irq_thread, @@ -812,6 +808,9 @@ static int meson_mmc_remove(struct platform_device *pdev) if (WARN_ON(!host)) return 0; + /* disable interrupts */ + writel(0, host->regs + SD_EMMC_IRQ_EN); + if (host->bounce_buf) dma_free_coherent(host->dev, host->bounce_buf_size, host->bounce_buf, host->bounce_dma_addr); From efe0b669716314072f0467368c2be2f501f04afc Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Tue, 7 Feb 2017 22:34:58 +0100 Subject: [PATCH 134/145] mmc: meson-gx: set max block count and request size So far max_blk_count isn't set what results in a default of value 8 to be used (PAGE_SIZE / block size). Block length field has 9 bits, so set max_blk_count to 2^9-1 = 511. In addition set max_req_size because max_blk_count is also limited by max_req_size / block_size. Signed-off-by: Heiner Kallweit Reviewed-by: Kevin Hilman Tested-by: Kevin Hilman Acked-by: Kevin Hilman Signed-off-by: Ulf Hansson --- drivers/mmc/host/meson-gx-mmc.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/mmc/host/meson-gx-mmc.c b/drivers/mmc/host/meson-gx-mmc.c index 4c622ad26a70..c9f251713611 100644 --- a/drivers/mmc/host/meson-gx-mmc.c +++ b/drivers/mmc/host/meson-gx-mmc.c @@ -778,6 +778,9 @@ static int meson_mmc_probe(struct platform_device *pdev) if (ret) goto free_host; + mmc->max_blk_count = CMD_CFG_LENGTH_MASK; + mmc->max_req_size = mmc->max_blk_count * mmc->max_blk_size; + /* data bounce buffer */ host->bounce_buf_size = SZ_512K; host->bounce_buf = From 4136fcb547d2baec31179aa0ce3466f4040b193c Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Tue, 7 Feb 2017 22:35:02 +0100 Subject: [PATCH 135/145] mmc: meson-gx: reduce bounce buffer size A bounce buffer of 512K isn't needed as the max request size is 511 * 512 byte. Signed-off-by: Heiner Kallweit Reviewed-by: Kevin Hilman Tested-by: Kevin Hilman Signed-off-by: Ulf Hansson --- drivers/mmc/host/meson-gx-mmc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mmc/host/meson-gx-mmc.c b/drivers/mmc/host/meson-gx-mmc.c index c9f251713611..4feb8971003e 100644 --- a/drivers/mmc/host/meson-gx-mmc.c +++ b/drivers/mmc/host/meson-gx-mmc.c @@ -782,7 +782,7 @@ static int meson_mmc_probe(struct platform_device *pdev) mmc->max_req_size = mmc->max_blk_count * mmc->max_blk_size; /* data bounce buffer */ - host->bounce_buf_size = SZ_512K; + host->bounce_buf_size = mmc->max_req_size; host->bounce_buf = dma_alloc_coherent(host->dev, host->bounce_buf_size, &host->bounce_dma_addr, GFP_KERNEL); From 62d721a646a9d515bd7b13bede78a1c02890b956 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Tue, 7 Feb 2017 22:35:40 +0100 Subject: [PATCH 136/145] mmc: meson-gx: remove unneeded checks in remove The remove callback is called only if probe finished successfully. Therefore these checks are not needed. Signed-off-by: Heiner Kallweit Reviewed-by: Kevin Hilman Tested-by: Kevin Hilman Signed-off-by: Ulf Hansson --- drivers/mmc/host/meson-gx-mmc.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/mmc/host/meson-gx-mmc.c b/drivers/mmc/host/meson-gx-mmc.c index 4feb8971003e..3cc6334acdb1 100644 --- a/drivers/mmc/host/meson-gx-mmc.c +++ b/drivers/mmc/host/meson-gx-mmc.c @@ -808,15 +808,11 @@ static int meson_mmc_remove(struct platform_device *pdev) { struct meson_host *host = dev_get_drvdata(&pdev->dev); - if (WARN_ON(!host)) - return 0; - /* disable interrupts */ writel(0, host->regs + SD_EMMC_IRQ_EN); - if (host->bounce_buf) - dma_free_coherent(host->dev, host->bounce_buf_size, - host->bounce_buf, host->bounce_dma_addr); + dma_free_coherent(host->dev, host->bounce_buf_size, + host->bounce_buf, host->bounce_dma_addr); clk_disable_unprepare(host->cfg_div_clk); clk_disable_unprepare(host->core_clk); From e21e6fdd2935e147f845de7ddf39d6204a075a46 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Tue, 7 Feb 2017 22:35:59 +0100 Subject: [PATCH 137/145] mmc: meson-gx: add support for HS400 mode Add support for HS400 mode. The driver still misses support for tuning, therefore highspeed modes like HS400 might not work under all circumstances yet. Successfully tested on a Odroid C2 (S905 GXBB). Signed-off-by: Heiner Kallweit Reviewed-by: Kevin Hilman Tested-by: Kevin Hilman Signed-off-by: Ulf Hansson --- drivers/mmc/host/meson-gx-mmc.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/mmc/host/meson-gx-mmc.c b/drivers/mmc/host/meson-gx-mmc.c index 3cc6334acdb1..5a959783304b 100644 --- a/drivers/mmc/host/meson-gx-mmc.c +++ b/drivers/mmc/host/meson-gx-mmc.c @@ -83,6 +83,7 @@ #define CFG_RC_CC_MASK 0xf #define CFG_STOP_CLOCK BIT(22) #define CFG_CLK_ALWAYS_ON BIT(18) +#define CFG_CHK_DS BIT(20) #define CFG_AUTO_CLK BIT(23) #define SD_EMMC_STATUS 0x48 @@ -408,6 +409,16 @@ static void meson_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) val &= ~(CFG_RC_CC_MASK << CFG_RC_CC_SHIFT); val |= ilog2(SD_EMMC_CFG_CMD_GAP) << CFG_RC_CC_SHIFT; + val &= ~CFG_DDR; + if (ios->timing == MMC_TIMING_UHS_DDR50 || + ios->timing == MMC_TIMING_MMC_DDR52 || + ios->timing == MMC_TIMING_MMC_HS400) + val |= CFG_DDR; + + val &= ~CFG_CHK_DS; + if (ios->timing == MMC_TIMING_MMC_HS400) + val |= CFG_CHK_DS; + writel(val, host->regs + SD_EMMC_CFG); if (val != orig) From 6962c2fb201878722ef78b513dae7c22dfa4919c Mon Sep 17 00:00:00 2001 From: Uri Yanai Date: Tue, 7 Feb 2017 18:00:00 +0200 Subject: [PATCH 138/145] mmc: MAN_BKOPS_EN inverse debug message logic Inverse the logic for printing the debug message. In mmc_decode_ext_csd() print message when MAN_BKOPS_EN is set Signed-off-by: Uri Yanai Signed-off-by: Alex Lemberg Signed-off-by: Ulf Hansson --- drivers/mmc/core/mmc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index f1a451e48538..1b67e3085353 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -543,8 +543,8 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd) EXT_CSD_MANUAL_BKOPS_MASK); card->ext_csd.raw_bkops_status = ext_csd[EXT_CSD_BKOPS_STATUS]; - if (!card->ext_csd.man_bkops_en) - pr_debug("%s: MAN_BKOPS_EN bit is not set\n", + if (card->ext_csd.man_bkops_en) + pr_debug("%s: MAN_BKOPS_EN bit is set\n", mmc_hostname(card->host)); } From efff8e7879b8b7f8a077f495262f0bb9cfaa0b06 Mon Sep 17 00:00:00 2001 From: Uri Yanai Date: Tue, 7 Feb 2017 18:00:01 +0200 Subject: [PATCH 139/145] mmc: Adding AUTO_BKOPS_EN bit set for Auto BKOPS support Adding dedicated flag for AUTO_BKOPS in card->ext_csd structure. Read AUTO_BKOPS bit value from the device EXT_CSD and set to the card->ext_csd structure. In mmc_decode_ext_csd() add a print message in case the AUTO_BKOPS is enabled Signed-off-by: Uri Yanai Signed-off-by: Alex Lemberg Signed-off-by: Ulf Hansson --- drivers/mmc/core/mmc.c | 6 ++++++ include/linux/mmc/card.h | 1 + include/linux/mmc/mmc.h | 1 + 3 files changed, 8 insertions(+) diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 1b67e3085353..e01e70c24ca2 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -546,6 +546,12 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd) if (card->ext_csd.man_bkops_en) pr_debug("%s: MAN_BKOPS_EN bit is set\n", mmc_hostname(card->host)); + card->ext_csd.auto_bkops_en = + (ext_csd[EXT_CSD_BKOPS_EN] & + EXT_CSD_AUTO_BKOPS_MASK); + if (card->ext_csd.auto_bkops_en) + pr_debug("%s: AUTO_BKOPS_EN bit is set\n", + mmc_hostname(card->host)); } /* check whether the eMMC card supports HPI */ diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h index 29d00c91c25c..77e61e0a216a 100644 --- a/include/linux/mmc/card.h +++ b/include/linux/mmc/card.h @@ -83,6 +83,7 @@ struct mmc_ext_csd { unsigned int hpi_cmd; /* cmd used as HPI */ bool bkops; /* background support bit */ bool man_bkops_en; /* manual bkops enable bit */ + bool auto_bkops_en; /* auto bkops enable bit */ unsigned int data_sector_size; /* 512 bytes or 4KB */ unsigned int data_tag_unit_size; /* DATA TAG UNIT size */ unsigned int boot_ro_lock; /* ro lock support */ diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h index 7406d9badda0..3ffc27aaeeaf 100644 --- a/include/linux/mmc/mmc.h +++ b/include/linux/mmc/mmc.h @@ -407,6 +407,7 @@ static inline bool mmc_op_multi(u32 opcode) * BKOPS modes */ #define EXT_CSD_MANUAL_BKOPS_MASK 0x01 +#define EXT_CSD_AUTO_BKOPS_MASK 0x02 /* * Command Queue From 4e03f628b464e0580abadf5161eaa38c61d20943 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 14 Feb 2017 20:05:40 +0900 Subject: [PATCH 140/145] mmc: sdhci-cadence: fix bit shift of read data from PHY port This macro is currently unused, but it may be useful for debug use. Fix it just in case. Fixes: ff6af28faff5 ("mmc: sdhci-cadence: add Cadence SD4HC support") Signed-off-by: Masahiro Yamada Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-cadence.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mmc/host/sdhci-cadence.c b/drivers/mmc/host/sdhci-cadence.c index 31e786d1b71a..316cfec3f005 100644 --- a/drivers/mmc/host/sdhci-cadence.c +++ b/drivers/mmc/host/sdhci-cadence.c @@ -26,7 +26,7 @@ #define SDHCI_CDNS_HRS04_ACK BIT(26) #define SDHCI_CDNS_HRS04_RD BIT(25) #define SDHCI_CDNS_HRS04_WR BIT(24) -#define SDHCI_CDNS_HRS04_RDATA_SHIFT 12 +#define SDHCI_CDNS_HRS04_RDATA_SHIFT 16 #define SDHCI_CDNS_HRS04_WDATA_SHIFT 8 #define SDHCI_CDNS_HRS04_ADDR_SHIFT 0 From 28fc64af63488d701184977481b263f31d856984 Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Wed, 15 Feb 2017 16:35:28 +0800 Subject: [PATCH 141/145] mmc: core: change quirks.c to be a header file Rename quirks.c to quirks.h, and include it for individual C files which need it. Signed-off-by: Shawn Lin Signed-off-by: Ulf Hansson --- drivers/mmc/core/Makefile | 2 +- drivers/mmc/core/block.c | 1 + drivers/mmc/core/card.h | 2 -- drivers/mmc/core/mmc.c | 1 + drivers/mmc/core/{quirks.c => quirks.h} | 8 ++------ drivers/mmc/core/sdio.c | 1 + 6 files changed, 6 insertions(+), 9 deletions(-) rename drivers/mmc/core/{quirks.c => quirks.h} (90%) diff --git a/drivers/mmc/core/Makefile b/drivers/mmc/core/Makefile index 0f81464fa824..7e3ed1aeada2 100644 --- a/drivers/mmc/core/Makefile +++ b/drivers/mmc/core/Makefile @@ -7,7 +7,7 @@ mmc_core-y := core.o bus.o host.o \ mmc.o mmc_ops.o sd.o sd_ops.o \ sdio.o sdio_ops.o sdio_bus.o \ sdio_cis.o sdio_io.o sdio_irq.o \ - quirks.o slot-gpio.o + slot-gpio.o mmc_core-$(CONFIG_OF) += pwrseq.o obj-$(CONFIG_PWRSEQ_SIMPLE) += pwrseq_simple.o obj-$(CONFIG_PWRSEQ_SD8787) += pwrseq_sd8787.o diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index cd909aecfded..6f3a5ff85590 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -52,6 +52,7 @@ #include "host.h" #include "bus.h" #include "mmc_ops.h" +#include "quirks.h" #include "sd_ops.h" MODULE_ALIAS("mmc:block"); diff --git a/drivers/mmc/core/card.h b/drivers/mmc/core/card.h index 95e8fc54eb21..f06cd91964ce 100644 --- a/drivers/mmc/core/card.h +++ b/drivers/mmc/core/card.h @@ -218,6 +218,4 @@ static inline int mmc_card_broken_hpi(const struct mmc_card *c) return c->quirks & MMC_QUIRK_BROKEN_HPI; } -void mmc_fixup_device(struct mmc_card *card, const struct mmc_fixup *table); - #endif diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index ad1089c713e5..f830970958e6 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -25,6 +25,7 @@ #include "host.h" #include "bus.h" #include "mmc_ops.h" +#include "quirks.h" #include "sd_ops.h" #define DEFAULT_CMD6_TIMEOUT_MS 500 diff --git a/drivers/mmc/core/quirks.c b/drivers/mmc/core/quirks.h similarity index 90% rename from drivers/mmc/core/quirks.c rename to drivers/mmc/core/quirks.h index bf25a9c88863..1e56ec4d4085 100644 --- a/drivers/mmc/core/quirks.c +++ b/drivers/mmc/core/quirks.h @@ -9,10 +9,6 @@ * */ -#include -#include -#include -#include #include #include "card.h" @@ -53,7 +49,8 @@ static const struct mmc_fixup mmc_fixup_methods[] = { END_FIXUP }; -void mmc_fixup_device(struct mmc_card *card, const struct mmc_fixup *table) +static inline void mmc_fixup_device(struct mmc_card *card, + const struct mmc_fixup *table) { const struct mmc_fixup *f; u64 rev = cid_rev_card(card); @@ -82,4 +79,3 @@ void mmc_fixup_device(struct mmc_card *card, const struct mmc_fixup *table) } } } -EXPORT_SYMBOL(mmc_fixup_device); diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index a64a8709ec72..f092a55c5064 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -23,6 +23,7 @@ #include "card.h" #include "host.h" #include "bus.h" +#include "quirks.h" #include "sd.h" #include "sdio_bus.h" #include "mmc_ops.h" From 884f38607897cb4a963ea8a65296f0973a2828d0 Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Wed, 15 Feb 2017 16:35:29 +0800 Subject: [PATCH 142/145] mmc: core: move some sdio IDs out of quirks file Consolidate all the sdio devices' IDs into sdio_ids. Signed-off-by: Shawn Lin Signed-off-by: Ulf Hansson --- drivers/mmc/core/quirks.h | 20 -------------------- include/linux/mmc/sdio_ids.h | 7 +++++++ 2 files changed, 7 insertions(+), 20 deletions(-) diff --git a/drivers/mmc/core/quirks.h b/drivers/mmc/core/quirks.h index 1e56ec4d4085..074940497686 100644 --- a/drivers/mmc/core/quirks.h +++ b/drivers/mmc/core/quirks.h @@ -13,26 +13,6 @@ #include "card.h" -#ifndef SDIO_VENDOR_ID_TI -#define SDIO_VENDOR_ID_TI 0x0097 -#endif - -#ifndef SDIO_DEVICE_ID_TI_WL1271 -#define SDIO_DEVICE_ID_TI_WL1271 0x4076 -#endif - -#ifndef SDIO_VENDOR_ID_STE -#define SDIO_VENDOR_ID_STE 0x0020 -#endif - -#ifndef SDIO_DEVICE_ID_STE_CW1200 -#define SDIO_DEVICE_ID_STE_CW1200 0x2280 -#endif - -#ifndef SDIO_DEVICE_ID_MARVELL_8797_F0 -#define SDIO_DEVICE_ID_MARVELL_8797_F0 0x9128 -#endif - static const struct mmc_fixup mmc_fixup_methods[] = { SDIO_FIXUP(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271, add_quirk, MMC_QUIRK_NONSTD_FUNC_IF), diff --git a/include/linux/mmc/sdio_ids.h b/include/linux/mmc/sdio_ids.h index d43ef96bf075..46794a7a531c 100644 --- a/include/linux/mmc/sdio_ids.h +++ b/include/linux/mmc/sdio_ids.h @@ -51,6 +51,7 @@ #define SDIO_DEVICE_ID_MARVELL_LIBERTAS 0x9103 #define SDIO_DEVICE_ID_MARVELL_8688WLAN 0x9104 #define SDIO_DEVICE_ID_MARVELL_8688BT 0x9105 +#define SDIO_DEVICE_ID_MARVELL_8797_F0 0x9128 #define SDIO_VENDOR_ID_SIANO 0x039a #define SDIO_DEVICE_ID_SIANO_NOVA_B0 0x0201 @@ -60,4 +61,10 @@ #define SDIO_DEVICE_ID_SIANO_NOVA_A0 0x1100 #define SDIO_DEVICE_ID_SIANO_STELLAR 0x5347 +#define SDIO_VENDOR_ID_TI 0x0097 +#define SDIO_DEVICE_ID_TI_WL1271 0x4076 + +#define SDIO_VENDOR_ID_STE 0x0020 +#define SDIO_DEVICE_ID_STE_CW1200 0x2280 + #endif /* LINUX_MMC_SDIO_IDS_H */ From 1144c1e4ddab9339e262e2702744e8f5c6220824 Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Wed, 15 Feb 2017 16:35:30 +0800 Subject: [PATCH 143/145] mmc: core: improve the quirks for sdio devices Rename mmc_fixup_methods to sdio_fixup_methods to better reflect that it's for sdio devices. So we could also pass on it from sdio card's probe sequence just like what we do for eMMC and block there. Signed-off-by: Shawn Lin Signed-off-by: Ulf Hansson --- drivers/mmc/core/quirks.h | 6 +----- drivers/mmc/core/sdio.c | 2 +- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/mmc/core/quirks.h b/drivers/mmc/core/quirks.h index 074940497686..f6d72173168a 100644 --- a/drivers/mmc/core/quirks.h +++ b/drivers/mmc/core/quirks.h @@ -13,7 +13,7 @@ #include "card.h" -static const struct mmc_fixup mmc_fixup_methods[] = { +static const struct mmc_fixup sdio_fixup_methods[] = { SDIO_FIXUP(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271, add_quirk, MMC_QUIRK_NONSTD_FUNC_IF), @@ -35,10 +35,6 @@ static inline void mmc_fixup_device(struct mmc_card *card, const struct mmc_fixup *f; u64 rev = cid_rev_card(card); - /* Non-core specific workarounds. */ - if (!table) - table = mmc_fixup_methods; - for (f = table; f->vendor_fixup; f++) { if ((f->manfid == CID_MANFID_ANY || f->manfid == card->cid.manfid) && diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index f092a55c5064..fae732c870a9 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -739,7 +739,7 @@ try_again: card = oldcard; } card->ocr = ocr_card; - mmc_fixup_device(card, NULL); + mmc_fixup_device(card, sdio_fixup_methods); if (card->type == MMC_TYPE_SD_COMBO) { err = mmc_sd_setup_card(host, card, oldcard != NULL); From 0e9cfcf44e4aced8d45f409dcb48a0994fa77979 Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Wed, 15 Feb 2017 16:35:31 +0800 Subject: [PATCH 144/145] mmc: core: move all quirks together into quirks.h It's not appreciated to place quirks everywhere, let's put them together just like what we do for USB, PCI etc. Signed-off-by: Shawn Lin Signed-off-by: Ulf Hansson --- drivers/mmc/core/block.c | 80 ---------------------------------- drivers/mmc/core/mmc.c | 11 ----- drivers/mmc/core/quirks.h | 91 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 91 insertions(+), 91 deletions(-) diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index 6f3a5ff85590..5bf1fba39349 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -61,12 +61,6 @@ MODULE_ALIAS("mmc:block"); #endif #define MODULE_PARAM_PREFIX "mmcblk." -#define INAND_CMD38_ARG_EXT_CSD 113 -#define INAND_CMD38_ARG_ERASE 0x00 -#define INAND_CMD38_ARG_TRIM 0x01 -#define INAND_CMD38_ARG_SECERASE 0x80 -#define INAND_CMD38_ARG_SECTRIM1 0x81 -#define INAND_CMD38_ARG_SECTRIM2 0x88 #define MMC_BLK_TIMEOUT_MS (10 * 60 * 1000) /* 10 minute timeout */ #define MMC_SANITIZE_REQ_TIMEOUT 240000 #define MMC_EXTRACT_INDEX_FROM_ARG(x) ((x & 0x00FF0000) >> 16) @@ -2108,80 +2102,6 @@ force_ro_fail: return ret; } -static const struct mmc_fixup blk_fixups[] = -{ - MMC_FIXUP("SEM02G", CID_MANFID_SANDISK, 0x100, add_quirk, - MMC_QUIRK_INAND_CMD38), - MMC_FIXUP("SEM04G", CID_MANFID_SANDISK, 0x100, add_quirk, - MMC_QUIRK_INAND_CMD38), - MMC_FIXUP("SEM08G", CID_MANFID_SANDISK, 0x100, add_quirk, - MMC_QUIRK_INAND_CMD38), - MMC_FIXUP("SEM16G", CID_MANFID_SANDISK, 0x100, add_quirk, - MMC_QUIRK_INAND_CMD38), - MMC_FIXUP("SEM32G", CID_MANFID_SANDISK, 0x100, add_quirk, - MMC_QUIRK_INAND_CMD38), - - /* - * Some MMC cards experience performance degradation with CMD23 - * instead of CMD12-bounded multiblock transfers. For now we'll - * black list what's bad... - * - Certain Toshiba cards. - * - * N.B. This doesn't affect SD cards. - */ - MMC_FIXUP("SDMB-32", CID_MANFID_SANDISK, CID_OEMID_ANY, add_quirk_mmc, - MMC_QUIRK_BLK_NO_CMD23), - MMC_FIXUP("SDM032", CID_MANFID_SANDISK, CID_OEMID_ANY, add_quirk_mmc, - MMC_QUIRK_BLK_NO_CMD23), - MMC_FIXUP("MMC08G", CID_MANFID_TOSHIBA, CID_OEMID_ANY, add_quirk_mmc, - MMC_QUIRK_BLK_NO_CMD23), - MMC_FIXUP("MMC16G", CID_MANFID_TOSHIBA, CID_OEMID_ANY, add_quirk_mmc, - MMC_QUIRK_BLK_NO_CMD23), - MMC_FIXUP("MMC32G", CID_MANFID_TOSHIBA, CID_OEMID_ANY, add_quirk_mmc, - MMC_QUIRK_BLK_NO_CMD23), - - /* - * Some MMC cards need longer data read timeout than indicated in CSD. - */ - MMC_FIXUP(CID_NAME_ANY, CID_MANFID_MICRON, 0x200, add_quirk_mmc, - MMC_QUIRK_LONG_READ_TIME), - MMC_FIXUP("008GE0", CID_MANFID_TOSHIBA, CID_OEMID_ANY, add_quirk_mmc, - MMC_QUIRK_LONG_READ_TIME), - - /* - * On these Samsung MoviNAND parts, performing secure erase or - * secure trim can result in unrecoverable corruption due to a - * firmware bug. - */ - MMC_FIXUP("M8G2FA", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc, - MMC_QUIRK_SEC_ERASE_TRIM_BROKEN), - MMC_FIXUP("MAG4FA", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc, - MMC_QUIRK_SEC_ERASE_TRIM_BROKEN), - MMC_FIXUP("MBG8FA", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc, - MMC_QUIRK_SEC_ERASE_TRIM_BROKEN), - MMC_FIXUP("MCGAFA", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc, - MMC_QUIRK_SEC_ERASE_TRIM_BROKEN), - MMC_FIXUP("VAL00M", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc, - MMC_QUIRK_SEC_ERASE_TRIM_BROKEN), - MMC_FIXUP("VYL00M", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc, - MMC_QUIRK_SEC_ERASE_TRIM_BROKEN), - MMC_FIXUP("KYL00M", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc, - MMC_QUIRK_SEC_ERASE_TRIM_BROKEN), - MMC_FIXUP("VZL00M", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc, - MMC_QUIRK_SEC_ERASE_TRIM_BROKEN), - - /* - * On Some Kingston eMMCs, performing trim can result in - * unrecoverable data conrruption occasionally due to a firmware bug. - */ - MMC_FIXUP("V10008", CID_MANFID_KINGSTON, CID_OEMID_ANY, add_quirk_mmc, - MMC_QUIRK_TRIM_BROKEN), - MMC_FIXUP("V10016", CID_MANFID_KINGSTON, CID_OEMID_ANY, add_quirk_mmc, - MMC_QUIRK_TRIM_BROKEN), - - END_FIXUP -}; - static int mmc_blk_probe(struct mmc_card *card) { struct mmc_blk_data *md, *part_md; diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index f830970958e6..7fd722868875 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -49,17 +49,6 @@ static const unsigned int tacc_mant[] = { 35, 40, 45, 50, 55, 60, 70, 80, }; -static const struct mmc_fixup mmc_ext_csd_fixups[] = { - /* - * Certain Hynix eMMC 4.41 cards might get broken when HPI feature - * is used so disable the HPI feature for such buggy cards. - */ - MMC_FIXUP_EXT_CSD_REV(CID_NAME_ANY, CID_MANFID_HYNIX, - 0x014a, add_quirk, MMC_QUIRK_BROKEN_HPI, 5), - - END_FIXUP -}; - #define UNSTUFF_BITS(resp,start,size) \ ({ \ const int __size = size; \ diff --git a/drivers/mmc/core/quirks.h b/drivers/mmc/core/quirks.h index f6d72173168a..7c195e744b33 100644 --- a/drivers/mmc/core/quirks.h +++ b/drivers/mmc/core/quirks.h @@ -13,6 +13,97 @@ #include "card.h" +static const struct mmc_fixup blk_fixups[] = { +#define INAND_CMD38_ARG_EXT_CSD 113 +#define INAND_CMD38_ARG_ERASE 0x00 +#define INAND_CMD38_ARG_TRIM 0x01 +#define INAND_CMD38_ARG_SECERASE 0x80 +#define INAND_CMD38_ARG_SECTRIM1 0x81 +#define INAND_CMD38_ARG_SECTRIM2 0x88 + /* CMD38 argument is passed through EXT_CSD[113] */ + MMC_FIXUP("SEM02G", CID_MANFID_SANDISK, 0x100, add_quirk, + MMC_QUIRK_INAND_CMD38), + MMC_FIXUP("SEM04G", CID_MANFID_SANDISK, 0x100, add_quirk, + MMC_QUIRK_INAND_CMD38), + MMC_FIXUP("SEM08G", CID_MANFID_SANDISK, 0x100, add_quirk, + MMC_QUIRK_INAND_CMD38), + MMC_FIXUP("SEM16G", CID_MANFID_SANDISK, 0x100, add_quirk, + MMC_QUIRK_INAND_CMD38), + MMC_FIXUP("SEM32G", CID_MANFID_SANDISK, 0x100, add_quirk, + MMC_QUIRK_INAND_CMD38), + + /* + * Some MMC cards experience performance degradation with CMD23 + * instead of CMD12-bounded multiblock transfers. For now we'll + * black list what's bad... + * - Certain Toshiba cards. + * + * N.B. This doesn't affect SD cards. + */ + MMC_FIXUP("SDMB-32", CID_MANFID_SANDISK, CID_OEMID_ANY, add_quirk_mmc, + MMC_QUIRK_BLK_NO_CMD23), + MMC_FIXUP("SDM032", CID_MANFID_SANDISK, CID_OEMID_ANY, add_quirk_mmc, + MMC_QUIRK_BLK_NO_CMD23), + MMC_FIXUP("MMC08G", CID_MANFID_TOSHIBA, CID_OEMID_ANY, add_quirk_mmc, + MMC_QUIRK_BLK_NO_CMD23), + MMC_FIXUP("MMC16G", CID_MANFID_TOSHIBA, CID_OEMID_ANY, add_quirk_mmc, + MMC_QUIRK_BLK_NO_CMD23), + MMC_FIXUP("MMC32G", CID_MANFID_TOSHIBA, CID_OEMID_ANY, add_quirk_mmc, + MMC_QUIRK_BLK_NO_CMD23), + + /* + * Some MMC cards need longer data read timeout than indicated in CSD. + */ + MMC_FIXUP(CID_NAME_ANY, CID_MANFID_MICRON, 0x200, add_quirk_mmc, + MMC_QUIRK_LONG_READ_TIME), + MMC_FIXUP("008GE0", CID_MANFID_TOSHIBA, CID_OEMID_ANY, add_quirk_mmc, + MMC_QUIRK_LONG_READ_TIME), + + /* + * On these Samsung MoviNAND parts, performing secure erase or + * secure trim can result in unrecoverable corruption due to a + * firmware bug. + */ + MMC_FIXUP("M8G2FA", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc, + MMC_QUIRK_SEC_ERASE_TRIM_BROKEN), + MMC_FIXUP("MAG4FA", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc, + MMC_QUIRK_SEC_ERASE_TRIM_BROKEN), + MMC_FIXUP("MBG8FA", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc, + MMC_QUIRK_SEC_ERASE_TRIM_BROKEN), + MMC_FIXUP("MCGAFA", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc, + MMC_QUIRK_SEC_ERASE_TRIM_BROKEN), + MMC_FIXUP("VAL00M", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc, + MMC_QUIRK_SEC_ERASE_TRIM_BROKEN), + MMC_FIXUP("VYL00M", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc, + MMC_QUIRK_SEC_ERASE_TRIM_BROKEN), + MMC_FIXUP("KYL00M", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc, + MMC_QUIRK_SEC_ERASE_TRIM_BROKEN), + MMC_FIXUP("VZL00M", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc, + MMC_QUIRK_SEC_ERASE_TRIM_BROKEN), + + /* + * On Some Kingston eMMCs, performing trim can result in + * unrecoverable data conrruption occasionally due to a firmware bug. + */ + MMC_FIXUP("V10008", CID_MANFID_KINGSTON, CID_OEMID_ANY, add_quirk_mmc, + MMC_QUIRK_TRIM_BROKEN), + MMC_FIXUP("V10016", CID_MANFID_KINGSTON, CID_OEMID_ANY, add_quirk_mmc, + MMC_QUIRK_TRIM_BROKEN), + + END_FIXUP +}; + +static const struct mmc_fixup mmc_ext_csd_fixups[] = { + /* + * Certain Hynix eMMC 4.41 cards might get broken when HPI feature + * is used so disable the HPI feature for such buggy cards. + */ + MMC_FIXUP_EXT_CSD_REV(CID_NAME_ANY, CID_MANFID_HYNIX, + 0x014a, add_quirk, MMC_QUIRK_BROKEN_HPI, 5), + + END_FIXUP +}; + static const struct mmc_fixup sdio_fixup_methods[] = { SDIO_FIXUP(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271, add_quirk, MMC_QUIRK_NONSTD_FUNC_IF), From 8c7cdbf9272c300dc093da3c62fa3b4bc6dc960e Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Wed, 15 Feb 2017 16:36:47 +0800 Subject: [PATCH 145/145] mmc: core: add mmc prefix for blk_fixups That makes all the quirks table look more consistent. Signed-off-by: Shawn Lin Signed-off-by: Ulf Hansson --- drivers/mmc/core/block.c | 2 +- drivers/mmc/core/quirks.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index 5bf1fba39349..1621fa08e206 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -2113,7 +2113,7 @@ static int mmc_blk_probe(struct mmc_card *card) if (!(card->csd.cmdclass & CCC_BLOCK_READ)) return -ENODEV; - mmc_fixup_device(card, blk_fixups); + mmc_fixup_device(card, mmc_blk_fixups); md = mmc_blk_alloc(card); if (IS_ERR(md)) diff --git a/drivers/mmc/core/quirks.h b/drivers/mmc/core/quirks.h index 7c195e744b33..fb725934fa21 100644 --- a/drivers/mmc/core/quirks.h +++ b/drivers/mmc/core/quirks.h @@ -13,7 +13,7 @@ #include "card.h" -static const struct mmc_fixup blk_fixups[] = { +static const struct mmc_fixup mmc_blk_fixups[] = { #define INAND_CMD38_ARG_EXT_CSD 113 #define INAND_CMD38_ARG_ERASE 0x00 #define INAND_CMD38_ARG_TRIM 0x01