From 0031a98a85e9fca282624bfc887f9531b2768396 Mon Sep 17 00:00:00 2001 From: Baruch Siach Date: Mon, 22 Sep 2014 10:12:51 +0300 Subject: mmc: block: add newline to sysfs display of force_ro Make force_ro consistent with other sysfs entries. Fixes: 371a689f64b0d ('mmc: MMC boot partitions support') Cc: Andrei Warkentin Signed-off-by: Baruch Siach Signed-off-by: Ulf Hansson --- drivers/mmc/card/block.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index 1fa4c80ff886..a11451f4f408 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -260,7 +260,7 @@ static ssize_t force_ro_show(struct device *dev, struct device_attribute *attr, int ret; struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev)); - ret = snprintf(buf, PAGE_SIZE, "%d", + ret = snprintf(buf, PAGE_SIZE, "%d\n", get_disk_ro(dev_to_disk(dev)) ^ md->read_only); mmc_blk_put(md); -- cgit v1.2.3-59-g8ed1b From 6380ea099cdd46d7377b6fbec0291cf2aa387bad Mon Sep 17 00:00:00 2001 From: Peter Guo Date: Wed, 24 Sep 2014 04:29:04 +0200 Subject: mmc: sdhci-pci-o2micro: Fix Dell E5440 issue Fix Dell E5440 when reboot Linux, can't find o2micro sd host chip issue. Fixes: 01acf6917aed (mmc: sdhci-pci: add support of O2Micro/BayHubTech SD hosts) Signed-off-by: Peter Guo Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-pci-o2micro.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/mmc/host/sdhci-pci-o2micro.c b/drivers/mmc/host/sdhci-pci-o2micro.c index 5670e381b0cf..e2ec108dba0e 100644 --- a/drivers/mmc/host/sdhci-pci-o2micro.c +++ b/drivers/mmc/host/sdhci-pci-o2micro.c @@ -127,8 +127,6 @@ void sdhci_pci_o2_fujin2_pci_init(struct sdhci_pci_chip *chip) return; scratch_32 &= ~((1 << 21) | (1 << 30)); - /* Set RTD3 function disabled */ - scratch_32 |= ((1 << 29) | (1 << 28)); pci_write_config_dword(chip->pdev, O2_SD_FUNC_REG3, scratch_32); /* Set L1 Entrance Timer */ -- cgit v1.2.3-59-g8ed1b From adfa57033d73dfc3449f3a9a2fe5450673b5aef3 Mon Sep 17 00:00:00 2001 From: Matteo Facchinetti Date: Tue, 30 Sep 2014 16:59:37 +0200 Subject: mmc: mxcmmc: fix race condition when dma finish a data transfer During a read of data block using dma, driver might have two ways to finish to read and free the resources: 1) checking STATUS_DATA_TRANS_DONE mask, in the mxcmci_irq() routine (pending to mmc irq) 2) mxmmc driver, registers also a mxcmci_dma_callback() and when transfer is finished, dma driver calls this callback. (pending to dma irq) Both ways are concurrent with each other. Race condition happens when following events occur: /* (1) mxcmci driver start data transfer */ 158.418970: mpc_dma_execute: mpc_dma_execute(): will_access_peripheral start cid=31 158.418976: mpc_dma_issue_pending <-mxcmci_request 158.418983: mxcmci_start_cmd <-mxcmci_request /* (2) mxcmci driver receive mmc irq */ 158.419656: mxcmci_irq <-handle_irq_event_percpu 158.419692: mxcmci_read_response <-mxcmci_irq /* (3) mxcmci driver checks that transfer is complete and call mxcmci_finish_data() */ 158.419726: mxcmci_data_done <-mxcmci_irq 158.419729: mxcmci_finish_data <-mxcmci_data_done 158.419733: dma_direct_unmap_sg <-mxcmci_finish_data 158.419736: mxcmci_swap_buffers.isra.24 <-mxcmci_finish_data 158.419762: mxcmci_read_response <-mxcmci_data_done /* (4) mxcmci driver (no dma): send stop command */ 158.419765: mxcmci_start_cmd <-mxcmci_data_done /* (5) mxcmci driver (no dma): receive the stop command irq response */ 158.419782: mxcmci_irq <-handle_irq_event_percpu 158.419812: mxcmci_read_response <-mxcmci_irq 158.419843: mxcmci_finish_request <-mxcmci_irq /* (6) dma driver: receive dma irq (finish data transfer) related by request on step 1 */ 158.419853: mpc_dma_irq <-handle_irq_event_percpu 158.420001: mpc_dma_irq_process <-mpc_dma_irq 158.420004: mpc_dma_irq_process <-mpc_dma_irq /* (7) dma driver: start dma tasklet to finish the dma irq handling */ 158.420008: mpc_dma_irq_process: mpc_dma_irq_process(): completed ch:31 /* (8) mxcmci driver: start next data transfer using dma */ 158.420174: mxcmci_request <-mmc_start_req 158.420182: dma_direct_map_sg <-mxcmci_request 158.420192: mpc_dma_prep_slave_sg <-mxcmci_request /* (9) dma driver: schedule irq tasklet and execute mxcmci dma driver callback */ 158.420250: mpc_dma_tasklet <-tasklet_action 158.420254: mpc_dma_process_completed <-tasklet_action 158.420267: mxcmci_dma_callback <-mpc_dma_process_completed /* ERROR!!! (10) mxcmci driver callback works on dma data related to the step 1 that is already finished */ 158.420271: mxcmci_data_done <-mpc_dma_process_completed 158.420273: mxcmci_finish_data <-mxcmci_data_done /* ERROR!!! (11) mxcmci driver: clear data that should be used by step 8 and send an other mmc stop command (already sended on step 4) */ 158.420276: dma_direct_unmap_sg <-mxcmci_finish_data 158.420279: mxcmci_swap_buffers.isra.24 <-mxcmci_finish_data 158.420330: mxcmci_read_response <-mxcmci_data_done 158.420333: mxcmci_start_cmd <-mxcmci_data_done 158.420338: dma_run_dependencies <-mpc_dma_process_completed ... ... ... 168.474223: mxcmci_watchdog <-call_timer_fn 168.474236: mxcmci_watchdog: mxcmci_watchdog 168.474397: mpc_dma_device_control <-mxcmci_watchdog In accordance with the other drivers that using the dma engine, fix it, leaving *only* to dma driver the complete control to ending the read operation. Removing STATUS_READ_OP_DONE event activation, has as effect to force mxcmci driver to handle the finish data transfer only by mxcmci dma callback. Signed-off-by: Matteo Facchinetti Acked-by: Sascha Hauer Signed-off-by: Ulf Hansson --- drivers/mmc/host/mxcmmc.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c index ad111422ad55..536a8983c3be 100644 --- a/drivers/mmc/host/mxcmmc.c +++ b/drivers/mmc/host/mxcmmc.c @@ -373,13 +373,9 @@ static void mxcmci_dma_callback(void *data) del_timer(&host->watchdog); stat = mxcmci_readl(host, MMC_REG_STATUS); - mxcmci_writel(host, stat & ~STATUS_DATA_TRANS_DONE, MMC_REG_STATUS); dev_dbg(mmc_dev(host->mmc), "%s: 0x%08x\n", __func__, stat); - if (stat & STATUS_READ_OP_DONE) - mxcmci_writel(host, STATUS_READ_OP_DONE, MMC_REG_STATUS); - mxcmci_data_done(host, stat); } @@ -743,10 +739,8 @@ static irqreturn_t mxcmci_irq(int irq, void *devid) sdio_irq = (stat & STATUS_SDIO_INT_ACTIVE) && host->use_sdio; spin_unlock_irqrestore(&host->lock, flags); - if (mxcmci_use_dma(host) && - (stat & (STATUS_READ_OP_DONE | STATUS_WRITE_OP_DONE))) - mxcmci_writel(host, STATUS_READ_OP_DONE | STATUS_WRITE_OP_DONE, - MMC_REG_STATUS); + if (mxcmci_use_dma(host) && (stat & (STATUS_WRITE_OP_DONE))) + mxcmci_writel(host, STATUS_WRITE_OP_DONE, MMC_REG_STATUS); if (sdio_irq) { mxcmci_writel(host, STATUS_SDIO_INT_ACTIVE, MMC_REG_STATUS); @@ -756,8 +750,7 @@ static irqreturn_t mxcmci_irq(int irq, void *devid) if (stat & STATUS_END_CMD_RESP) mxcmci_cmd_done(host, stat); - if (mxcmci_use_dma(host) && - (stat & (STATUS_DATA_TRANS_DONE | STATUS_WRITE_OP_DONE))) { + if (mxcmci_use_dma(host) && (stat & STATUS_WRITE_OP_DONE)) { del_timer(&host->watchdog); mxcmci_data_done(host, stat); } -- cgit v1.2.3-59-g8ed1b From 18a098063592e4341bfb904ae9f4e41c08c74a63 Mon Sep 17 00:00:00 2001 From: Matteo Facchinetti Date: Wed, 8 Oct 2014 16:24:33 +0200 Subject: mmc: mxcmmc: fix the default value for available voltages into mxcmci_probe If available voltages are not given, mmc_regulator_get_supply() function returns 0 and mxcmmc driver doesn't set a value for ocr_avail mask. In accordance with the comment in platform_data/mmc-mxcmmc.h, fix it, assuming MMC_VDD_32_33 | MMC_VDD_33_34 as default value. Signed-off-by: Matteo Facchinetti Reviewed-by: Sascha Hauer Signed-off-by: Ulf Hansson --- drivers/mmc/host/mxcmmc.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c index 536a8983c3be..5316d9b9e7b4 100644 --- a/drivers/mmc/host/mxcmmc.c +++ b/drivers/mmc/host/mxcmmc.c @@ -1077,12 +1077,14 @@ static int mxcmci_probe(struct platform_device *pdev) dat3_card_detect = true; ret = mmc_regulator_get_supply(mmc); - if (ret) { - if (pdata && ret != -EPROBE_DEFER) - mmc->ocr_avail = pdata->ocr_avail ? : - MMC_VDD_32_33 | MMC_VDD_33_34; + if (ret == -EPROBE_DEFER) + goto out_free; + + if (!mmc->ocr_avail) { + if (pdata && pdata->ocr_avail) + mmc->ocr_avail = pdata->ocr_avail; else - goto out_free; + mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; } if (dat3_card_detect) -- cgit v1.2.3-59-g8ed1b From cd529af7eefae90b97fa90a24f1ad8ccef6ae41a Mon Sep 17 00:00:00 2001 From: Dirk Behme Date: Wed, 1 Oct 2014 04:25:32 -0500 Subject: mmc: sdhci-esdhc-imx: don't exit in case of no pinctrl states The commit ad93220de7da ("mmc: sdhci-esdhc-imx: change pinctrl state according to uhs mode") exits the probe in case there are no valid pinctrl states found. As there are configurations doing the pin mux properly in the boot loader, don't exit. Just warn, but go on in case if there are no pinctrl states in the device tree. Signed-off-by: Dirk Behme Signed-off-by: Andrew Gabbasov Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-esdhc-imx.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c index 587ee0edeb57..0135f00f826f 100644 --- a/drivers/mmc/host/sdhci-esdhc-imx.c +++ b/drivers/mmc/host/sdhci-esdhc-imx.c @@ -1031,11 +1031,8 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev) imx_data->pins_default = pinctrl_lookup_state(imx_data->pinctrl, PINCTRL_STATE_DEFAULT); - if (IS_ERR(imx_data->pins_default)) { - err = PTR_ERR(imx_data->pins_default); - dev_err(mmc_dev(host->mmc), "could not get default state\n"); - goto disable_clk; - } + if (IS_ERR(imx_data->pins_default)) + dev_warn(mmc_dev(host->mmc), "could not get default state\n"); host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL; @@ -1123,7 +1120,8 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev) } /* sdr50 and sdr104 needs work on 1.8v signal voltage */ - if ((boarddata->support_vsel) && esdhc_is_usdhc(imx_data)) { + if ((boarddata->support_vsel) && esdhc_is_usdhc(imx_data) && + !IS_ERR(imx_data->pins_default)) { imx_data->pins_100mhz = pinctrl_lookup_state(imx_data->pinctrl, ESDHC_PINCTRL_STATE_100MHZ); imx_data->pins_200mhz = pinctrl_lookup_state(imx_data->pinctrl, -- cgit v1.2.3-59-g8ed1b From fbfaf0326b725cfbcc4169294cffefcad5ce64aa Mon Sep 17 00:00:00 2001 From: Andrew Gabbasov Date: Wed, 1 Oct 2014 07:14:07 -0500 Subject: mmc: sdhci: Balance vmmc regulator_disable() As a follow-up of commit "mmc: sdhci: Balance vmmc regulator_enable(), and always enable vqmmc" vmmc regulator disable is also not needed in sdhci_remove_host. The regulator is completely controlled by mmc_power_up and mmc_power_off functions and is already disabled by the time of removing the host. Extra regulator_disable call in sdhci_remove_host is unbalanced and causes a warning reported by regulator core, so should be removed. Signed-off-by: Andrew Gabbasov Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index ada1a3ea3a87..179ce06eec73 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -3339,9 +3339,6 @@ void sdhci_remove_host(struct sdhci_host *host, int dead) tasklet_kill(&host->finish_tasklet); - if (!IS_ERR(mmc->supply.vmmc)) - regulator_disable(mmc->supply.vmmc); - if (!IS_ERR(mmc->supply.vqmmc)) regulator_disable(mmc->supply.vqmmc); -- cgit v1.2.3-59-g8ed1b From fce9d33f51bf1d84270238885c2712d48a056e41 Mon Sep 17 00:00:00 2001 From: Andrew Gabbasov Date: Wed, 1 Oct 2014 07:14:08 -0500 Subject: mmc: sdhci: fix error conditions for controller reset Add the case of SET_BLOCK_COUNT command error to the error conditions check for making a controller reset at request handling finish. Otherwise, if the SET_BLOCK_COUNT command failed, e.g. with a timeout, the controller state was not reset, and the next command failed too. In the case of data error the controller reset is already done in finish_data() function before sending stop command (if present), so the finish tasklet should make a reset after data error only if no stop command existed in the request. Also, fix the indentation of this condition check to make it more logical. Signed-off-by: Andrew Gabbasov Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 179ce06eec73..062222abf3df 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -2144,9 +2144,10 @@ static void sdhci_tasklet_finish(unsigned long param) */ if (!(host->flags & SDHCI_DEVICE_DEAD) && ((mrq->cmd && mrq->cmd->error) || - (mrq->data && (mrq->data->error || - (mrq->data->stop && mrq->data->stop->error))) || - (host->quirks & SDHCI_QUIRK_RESET_AFTER_REQUEST))) { + (mrq->sbc && mrq->sbc->error) || + (mrq->data && ((mrq->data->error && !mrq->data->stop) || + (mrq->data->stop && mrq->data->stop->error))) || + (host->quirks & SDHCI_QUIRK_RESET_AFTER_REQUEST))) { /* Some controllers need this kick or reset won't work here */ if (host->quirks & SDHCI_QUIRK_CLOCK_BEFORE_RESET) -- cgit v1.2.3-59-g8ed1b From cce411e68515ee14c323d0d1fef638ed0aead7a6 Mon Sep 17 00:00:00 2001 From: Andrew Gabbasov Date: Wed, 1 Oct 2014 07:14:09 -0500 Subject: mmc: core: Initialize SET_BLOCK_COUNT request fields Some request fields are initialized just before request processing for sanity purposes. This is done for command, data, and stop parts of the request, but not for sbc (set block count) part. Add such initialization for that part too. Signed-off-by: Andrew Gabbasov Signed-off-by: Ulf Hansson --- drivers/mmc/core/core.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index f26a5f1d926d..9f1ecc4b8c82 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -214,6 +214,10 @@ mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) mrq->cmd->error = 0; mrq->cmd->mrq = mrq; + if (mrq->sbc) { + mrq->sbc->error = 0; + mrq->sbc->mrq = mrq; + } if (mrq->data) { BUG_ON(mrq->data->blksz > host->max_blk_size); BUG_ON(mrq->data->blocks > host->max_blk_count); -- cgit v1.2.3-59-g8ed1b From fc75b708b849fd15da162e0a806ae0dc27996400 Mon Sep 17 00:00:00 2001 From: Andrew Gabbasov Date: Wed, 1 Oct 2014 07:14:10 -0500 Subject: mmc: core: Add debug message for SET_BLOCK_COUNT result The debug messages with commands execution results, that are printed after processing the request, do not include results of sbc (set block count) part of request. Add the debug message for that part too. Signed-off-by: Andrew Gabbasov Signed-off-by: Ulf Hansson --- drivers/mmc/core/core.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 9f1ecc4b8c82..ee2e776fb8e3 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -149,6 +149,14 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq) led_trigger_event(host->led, LED_OFF); + if (mrq->sbc) { + pr_debug("%s: req done : %d: %08x %08x %08x %08x\n", + mmc_hostname(host), mrq->sbc->opcode, + mrq->sbc->error, + mrq->sbc->resp[0], mrq->sbc->resp[1], + mrq->sbc->resp[2], mrq->sbc->resp[3]); + } + pr_debug("%s: req done (CMD%u): %d: %08x %08x %08x %08x\n", mmc_hostname(host), cmd->opcode, err, cmd->resp[0], cmd->resp[1], -- cgit v1.2.3-59-g8ed1b From 4b75bffc77c40ac3c17a3ea9bbdc3a733c34591b Mon Sep 17 00:00:00 2001 From: Andrew Gabbasov Date: Wed, 1 Oct 2014 07:14:11 -0500 Subject: mmc: core: Fix error paths and messages in mmc_init_card In mmc_init_card function some of the branches in error handling paths go to "err" label, which skips removing of newly allocated card structure, that will actually not be used. Fix that by using proper "free_card" label. Also, some messages in these branches are reported as warnings, although the operation processing is not continued. Change these messages to error level. Signed-off-by: Andrew Gabbasov Signed-off-by: Ulf Hansson --- drivers/mmc/core/mmc.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index a301a78a2bd1..bcde451f6d91 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -998,7 +998,7 @@ static int mmc_select_hs_ddr(struct mmc_card *card) ext_csd_bits, card->ext_csd.generic_cmd6_time); if (err) { - pr_warn("%s: switch to bus width %d ddr failed\n", + pr_err("%s: switch to bus width %d ddr failed\n", mmc_hostname(host), 1 << bus_width); return err; } @@ -1069,7 +1069,7 @@ static int mmc_select_hs400(struct mmc_card *card) card->ext_csd.generic_cmd6_time, true, true, true); if (err) { - pr_warn("%s: switch to high-speed from hs200 failed, err:%d\n", + pr_err("%s: switch to high-speed from hs200 failed, err:%d\n", mmc_hostname(host), err); return err; } @@ -1079,7 +1079,7 @@ static int mmc_select_hs400(struct mmc_card *card) EXT_CSD_DDR_BUS_WIDTH_8, card->ext_csd.generic_cmd6_time); if (err) { - pr_warn("%s: switch to bus width for hs400 failed, err:%d\n", + pr_err("%s: switch to bus width for hs400 failed, err:%d\n", mmc_hostname(host), err); return err; } @@ -1089,7 +1089,7 @@ static int mmc_select_hs400(struct mmc_card *card) card->ext_csd.generic_cmd6_time, true, true, true); if (err) { - pr_warn("%s: switch to hs400 failed, err:%d\n", + pr_err("%s: switch to hs400 failed, err:%d\n", mmc_hostname(host), err); return err; } @@ -1232,7 +1232,7 @@ static int mmc_hs200_tuning(struct mmc_card *card) mmc_host_clk_release(host); if (err) - pr_warn("%s: tuning execution failed\n", + pr_err("%s: tuning execution failed\n", mmc_hostname(host)); } @@ -1458,18 +1458,18 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, if (mmc_card_hs200(card)) { err = mmc_hs200_tuning(card); if (err) - goto err; + goto free_card; err = mmc_select_hs400(card); if (err) - goto err; + goto free_card; } else if (mmc_card_hs(card)) { /* Select the desired bus width optionally */ err = mmc_select_bus_width(card); if (!IS_ERR_VALUE(err)) { err = mmc_select_hs_ddr(card); if (err) - goto err; + goto free_card; } } -- cgit v1.2.3-59-g8ed1b From 64b12a68a9f74bb32d8efd7af1ad8a2ba02fc884 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Wed, 8 Oct 2014 12:24:24 +0100 Subject: mmc: core: fix prepared requests while doing bkops While starting the bkops the previously prepared request should be canceled and restarted after the bkops. As the prepared resource might already setup the dma channels and ready to be started. Now with the arrival of bkops request this prepared request can be serviced ONLY after the bkops. So holding on to the prepared request in the host driver is confusing at this point in time, so it makes sense to cleanup such dangling requests and reissue this request once bkops is done. Canceling the prepared request would give opportunity to the host drivers to perform cleanup on the prepared request. Without this patch host drivers like mmci gets confused when a blocking request like send_ext_csd(CMD8) is issued while there is already a prepared request. With the help of this patch, the driver can better manage such blocking requests and cleanup the prepared requests which are not started yet. Without this patch I hit below crash on Qualcomm APQ8064 based IFC6410 board with mmci host driver. mmci-pl18x 12400000.sdcc: error during DMA transfer! Unable to handle kernel paging request at virtual address 40000000 pgd = c0204000 [40000000] *pgd=00000000 Internal error: Oops: 805 [#1] SMP ARM Modules linked in: ipv6 ath6kl_sdio ath6kl_core CPU: 0 PID: 0 Comm: swapper/0 Tainted: G W 3.17.0-rc7-linaro-multi-v7 #1 task: c0c9d7e0 ti: c0c92000 task.ti: c0c92000 PC is at v7_dma_inv_range+0x34/0x4c LR is at __dma_page_dev_to_cpu+0x80/0x100 pc : [] lr : [] psr: 400f0193 sp : c0c93e20 ip : c0c9a478 fp : c08ea538 r10: c0c9f548 r9 : 00000002 r8 : e97d9000 r7 : 00000200 r6 : c0c9d504 r5 : c0db0880 r4 : 00000000 r3 : 0000003f r2 : 00000040 r1 : 40000200 r0 : 40000000 Flags: nZcv IRQs off FIQs on Mode SVC_32 ISA ARM Segment kernel Control: 10c5787d Table: a9ef406a DAC: 00000015 Process swapper/0 (pid: 0, stack limit = 0xc0c92250) Stack: (0xc0c93e20 to 0xc0c94000) 3e20: c021f058 e9a17178 e9a171bc e99dfd6c 00000001 00000001 e995de10 00000002 3e40: 00000000 c021b574 00000000 c04bc4a4 00000000 e9b49ac0 c0ce6e6c e99dfda4 3e60: 00000088 e9810780 c0d8291c c072ea58 00000000 c072d3fc 00000000 c072f534 3e80: 00000000 e9b49ac0 00000100 c0c9a444 00000088 c072f6b4 c072f5d4 e9d40080 3ea0: e98107dc 00000000 00000000 c0280a60 00000000 7d55bf61 e9810780 e98107dc 3ec0: 00000000 f0002000 c0d460e8 c0d460e8 c0c92000 c0280b60 e9810780 c0ce7190 3ee0: 00000000 c028369c c02835f4 00000088 00000088 c0280278 c0c8ec70 c020f080 3f00: f000200c c0c9a958 c0c93f28 c02088e4 c04bd630 c04bd5bc 200f0013 ffffffff 3f20: c0c93f5c c0212800 00000001 a987c000 c0c93f3c c04bd574 00000000 0000015b 3f40: ea7a0e40 00000000 c0d460e8 c0d460e8 c0c92000 c08ea538 29b12000 c0c93f70 3f60: c04bd630 c04bd5bc 200f0013 ffffffff c04bd574 c071bd24 7d50c9b4 c0719a44 3f80: 7d50c9b4 0000015b c0c9a498 c0c92028 c0c9a498 c0c9a4fc ea7a0e40 c0c8ee38 3fa0: c0d460e8 c0276198 00000000 c0d8291a 00000000 c0c9a400 00000000 c0be0bc4 3fc0: ffffffff ffffffff c0be05f8 00000000 00000000 c0c533d8 c0d82ed4 c0c9a47c 3fe0: c0c533d4 c0c9e870 8020406a 511f06f0 00000000 80208074 00000000 00000000 [] (v7_dma_inv_range) from [] (__dma_page_dev_to_cpu+0x80/0x100) [] (__dma_page_dev_to_cpu) from [] (arm_dma_unmap_sg+0x5c/0x84) [] (arm_dma_unmap_sg) from [] (mmci_dma_unmap.isra.16+0x60/0x74) [] (mmci_dma_unmap.isra.16) from [] (mmci_data_irq+0x1fc/0x29c) [] (mmci_data_irq) from [] (mmci_irq+0xe0/0x114) [] (mmci_irq) from [] (handle_irq_event_percpu+0x78/0x134) [] (handle_irq_event_percpu) from [] (handle_irq_event+0x44/0x64) [] (handle_irq_event) from [] (handle_fasteoi_irq+0xa8/0x1a8) [] (handle_fasteoi_irq) from [] (generic_handle_irq+0x2c/0x3c) [] (generic_handle_irq) from [] (handle_IRQ+0x40/0x90) [] (handle_IRQ) from [] (gic_handle_irq+0x38/0x68) [] (gic_handle_irq) from [] (__irq_svc+0x40/0x54) Exception stack(0xc0c93f28 to 0xc0c93f70) 3f20: 00000001 a987c000 c0c93f3c c04bd574 00000000 0000015b 3f40: ea7a0e40 00000000 c0d460e8 c0d460e8 c0c92000 c08ea538 29b12000 c0c93f70 3f60: c04bd630 c04bd5bc 200f0013 ffffffff [] (__irq_svc) from [] (msm_cpu_pm_enter_sleep+0x48/0x4c) [] (msm_cpu_pm_enter_sleep) from [] (qcom_lpm_enter_spc+0x20/0x2c) [] (qcom_lpm_enter_spc) from [] (cpuidle_enter_state+0x44/0xf0) [] (cpuidle_enter_state) from [] (cpu_startup_entry+0x1f4/0x238) [] (cpu_startup_entry) from [] (start_kernel+0x384/0x390) Code: 1e070f3e e1110003 e1c11003 1e071f3e (ee070f36) ---[ end trace cf6cb3f6432c9834 ]--- Kernel panic - not syncing: Fatal exception in interrupt Reported-by: Nicolas Dechesne Signed-off-by: Srinivas Kandagatla Signed-off-by: Ulf Hansson --- drivers/mmc/core/core.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index ee2e776fb8e3..953f17c5fcde 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -550,8 +550,18 @@ struct mmc_async_req *mmc_start_req(struct mmc_host *host, 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)) + (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, !host->areq); + } } if (!err && areq) -- cgit v1.2.3-59-g8ed1b From b5c16a60e5ecd57b7b854cc7f9d875d0cc62034c Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Wed, 8 Oct 2014 12:25:17 +0100 Subject: mmc: mmci: fix mmci_post_request If the post request is cancelling the channel and descriptor and which are equal to host->dma_current and host->dma_desc_current respectively, then it makes sense to reset these pointers to NULL, so that the driver does not reference it. Also the host_cookie can be reset to 0 in cases of error, so that the core could reissue the same mmc_request. This patch was tested with 'mmc: core: fix prepared requests while doing bkops' to fix the below issue. mmci-pl18x 12400000.sdcc: error during DMA transfer! Unable to handle kernel paging request at virtual address 40000000 pgd = c0204000 [40000000] *pgd=00000000 Internal error: Oops: 805 [#1] SMP ARM Modules linked in: ipv6 ath6kl_sdio ath6kl_core CPU: 0 PID: 0 Comm: swapper/0 Tainted: G W 3.17.0-rc7-linaro-multi-v7 #1 task: c0c9d7e0 ti: c0c92000 task.ti: c0c92000 PC is at v7_dma_inv_range+0x34/0x4c LR is at __dma_page_dev_to_cpu+0x80/0x100 pc : [] lr : [] psr: 400f0193 sp : c0c93e20 ip : c0c9a478 fp : c08ea538 r10: c0c9f548 r9 : 00000002 r8 : e97d9000 r7 : 00000200 r6 : c0c9d504 r5 : c0db0880 r4 : 00000000 r3 : 0000003f r2 : 00000040 r1 : 40000200 r0 : 40000000 Flags: nZcv IRQs off FIQs on Mode SVC_32 ISA ARM Segment kernel Control: 10c5787d Table: a9ef406a DAC: 00000015 Process swapper/0 (pid: 0, stack limit = 0xc0c92250) Stack: (0xc0c93e20 to 0xc0c94000) 3e20: c021f058 e9a17178 e9a171bc e99dfd6c 00000001 00000001 e995de10 00000002 3e40: 00000000 c021b574 00000000 c04bc4a4 00000000 e9b49ac0 c0ce6e6c e99dfda4 3e60: 00000088 e9810780 c0d8291c c072ea58 00000000 c072d3fc 00000000 c072f534 3e80: 00000000 e9b49ac0 00000100 c0c9a444 00000088 c072f6b4 c072f5d4 e9d40080 3ea0: e98107dc 00000000 00000000 c0280a60 00000000 7d55bf61 e9810780 e98107dc 3ec0: 00000000 f0002000 c0d460e8 c0d460e8 c0c92000 c0280b60 e9810780 c0ce7190 3ee0: 00000000 c028369c c02835f4 00000088 00000088 c0280278 c0c8ec70 c020f080 3f00: f000200c c0c9a958 c0c93f28 c02088e4 c04bd630 c04bd5bc 200f0013 ffffffff 3f20: c0c93f5c c0212800 00000001 a987c000 c0c93f3c c04bd574 00000000 0000015b 3f40: ea7a0e40 00000000 c0d460e8 c0d460e8 c0c92000 c08ea538 29b12000 c0c93f70 3f60: c04bd630 c04bd5bc 200f0013 ffffffff c04bd574 c071bd24 7d50c9b4 c0719a44 3f80: 7d50c9b4 0000015b c0c9a498 c0c92028 c0c9a498 c0c9a4fc ea7a0e40 c0c8ee38 3fa0: c0d460e8 c0276198 00000000 c0d8291a 00000000 c0c9a400 00000000 c0be0bc4 3fc0: ffffffff ffffffff c0be05f8 00000000 00000000 c0c533d8 c0d82ed4 c0c9a47c 3fe0: c0c533d4 c0c9e870 8020406a 511f06f0 00000000 80208074 00000000 00000000 [] (v7_dma_inv_range) from [] (__dma_page_dev_to_cpu+0x80/0x100) [] (__dma_page_dev_to_cpu) from [] (arm_dma_unmap_sg+0x5c/0x84) [] (arm_dma_unmap_sg) from [] (mmci_dma_unmap.isra.16+0x60/0x74) [] (mmci_dma_unmap.isra.16) from [] (mmci_data_irq+0x1fc/0x29c) [] (mmci_data_irq) from [] (mmci_irq+0xe0/0x114) [] (mmci_irq) from [] (handle_irq_event_percpu+0x78/0x134) [] (handle_irq_event_percpu) from [] (handle_irq_event+0x44/0x64) [] (handle_irq_event) from [] (handle_fasteoi_irq+0xa8/0x1a8) [] (handle_fasteoi_irq) from [] (generic_handle_irq+0x2c/0x3c) [] (generic_handle_irq) from [] (handle_IRQ+0x40/0x90) [] (handle_IRQ) from [] (gic_handle_irq+0x38/0x68) [] (gic_handle_irq) from [] (__irq_svc+0x40/0x54) Exception stack(0xc0c93f28 to 0xc0c93f70) 3f20: 00000001 a987c000 c0c93f3c c04bd574 00000000 0000015b 3f40: ea7a0e40 00000000 c0d460e8 c0d460e8 c0c92000 c08ea538 29b12000 c0c93f70 3f60: c04bd630 c04bd5bc 200f0013 ffffffff [] (__irq_svc) from [] (msm_cpu_pm_enter_sleep+0x48/0x4c) [] (msm_cpu_pm_enter_sleep) from [] (qcom_lpm_enter_spc+0x20/0x2c) [] (qcom_lpm_enter_spc) from [] (cpuidle_enter_state+0x44/0xf0) [] (cpuidle_enter_state) from [] (cpu_startup_entry+0x1f4/0x238) [] (cpu_startup_entry) from [] (start_kernel+0x384/0x390) Code: 1e070f3e e1110003 e1c11003 1e071f3e (ee070f36) ---[ end trace cf6cb3f6432c9834 ]--- Kernel panic - not syncing: Fatal exception in interrupt Signed-off-by: Srinivas Kandagatla Signed-off-by: Ulf Hansson --- drivers/mmc/host/mmci.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 43af791e2e45..53bf7a4b5839 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -736,8 +736,15 @@ static void mmci_post_request(struct mmc_host *mmc, struct mmc_request *mrq, chan = host->dma_tx_channel; dmaengine_terminate_all(chan); + if (host->dma_desc_current == next->dma_desc) + host->dma_desc_current = NULL; + + if (host->dma_current == next->dma_chan) + host->dma_current = NULL; + next->dma_desc = NULL; next->dma_chan = NULL; + data->host_cookie = 0; } } -- cgit v1.2.3-59-g8ed1b From 05e07d8be1df994878af8a9b2560834892392c70 Mon Sep 17 00:00:00 2001 From: Tomeu Vizoso Date: Fri, 3 Oct 2014 17:53:18 +0200 Subject: mmc: sunxi: Remove unused includes of linux/clk-private.h Signed-off-by: Tomeu Vizoso Signed-off-by: Ulf Hansson --- drivers/mmc/host/sunxi-mmc.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/mmc/host/sunxi-mmc.c b/drivers/mmc/host/sunxi-mmc.c index d1663b3c4143..15cb8b7ffc34 100644 --- a/drivers/mmc/host/sunxi-mmc.c +++ b/drivers/mmc/host/sunxi-mmc.c @@ -21,7 +21,6 @@ #include #include -#include #include #include -- cgit v1.2.3-59-g8ed1b From 6a686c31324c9efd08ec1d42c5f5ecdfcd73a5f8 Mon Sep 17 00:00:00 2001 From: Sebastian Hesselbarth Date: Tue, 21 Oct 2014 11:22:33 +0200 Subject: mmc: sdhci-pxav2: Drop unused struct sdhci_pxa struct sdhci_pxa is private data of PXA SDHCI driver, but not used in sdhci-pxav2 at all. Drop unused references to struct sdhci_pxa. Signed-off-by: Sebastian Hesselbarth Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-pxav2.c | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/drivers/mmc/host/sdhci-pxav2.c b/drivers/mmc/host/sdhci-pxav2.c index b4c23e983baf..f98008b5ea77 100644 --- a/drivers/mmc/host/sdhci-pxav2.c +++ b/drivers/mmc/host/sdhci-pxav2.c @@ -167,23 +167,17 @@ static int sdhci_pxav2_probe(struct platform_device *pdev) struct sdhci_pxa_platdata *pdata = pdev->dev.platform_data; struct device *dev = &pdev->dev; struct sdhci_host *host = NULL; - struct sdhci_pxa *pxa = NULL; const struct of_device_id *match; int ret; struct clk *clk; - pxa = kzalloc(sizeof(struct sdhci_pxa), GFP_KERNEL); - if (!pxa) - return -ENOMEM; - host = sdhci_pltfm_init(pdev, NULL, 0); - if (IS_ERR(host)) { - kfree(pxa); + if (IS_ERR(host)) return PTR_ERR(host); - } + pltfm_host = sdhci_priv(host); - pltfm_host->priv = pxa; + pltfm_host->priv = NULL; clk = clk_get(dev, "PXA-SDHCLK"); if (IS_ERR(clk)) { @@ -238,7 +232,6 @@ err_add_host: clk_put(clk); err_clk_get: sdhci_pltfm_free(pdev); - kfree(pxa); return ret; } @@ -246,14 +239,12 @@ static int sdhci_pxav2_remove(struct platform_device *pdev) { struct sdhci_host *host = platform_get_drvdata(pdev); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct sdhci_pxa *pxa = pltfm_host->priv; sdhci_remove_host(host, 1); clk_disable_unprepare(pltfm_host->clk); clk_put(pltfm_host->clk); sdhci_pltfm_free(pdev); - kfree(pxa); return 0; } -- cgit v1.2.3-59-g8ed1b From 668e84b20f7a76c7aacfc907906400b844561276 Mon Sep 17 00:00:00 2001 From: Sebastian Hesselbarth Date: Tue, 21 Oct 2014 11:22:34 +0200 Subject: mmc: sdhci-pxav3: Respect MMC_DDR52 timing on uhs signaling commit bb8175a8aa42d731a840cd474e348ac3367eb5a0 ("mmc: sdhci: clarify DDR timing mode between SD-UHS and eMMC") added MMC_DDR52 as eMMC's DDR mode to be distinguished from SD-UHS. While the differentation may be useful, pxav3 SDHCI controller lacks a corresponding check in its custom .set_uhs_signaling callback for MMC_DDR52. This patch adds a new switch case for MMC_TIMING_MMC_DDR52 to MMC_TIMING_UHS_DDR50 case. Signed-off-by: Sebastian Hesselbarth Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-pxav3.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mmc/host/sdhci-pxav3.c b/drivers/mmc/host/sdhci-pxav3.c index 5036d7d39529..b55c807982fe 100644 --- a/drivers/mmc/host/sdhci-pxav3.c +++ b/drivers/mmc/host/sdhci-pxav3.c @@ -211,6 +211,7 @@ static void pxav3_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs) case MMC_TIMING_UHS_SDR104: ctrl_2 |= SDHCI_CTRL_UHS_SDR104 | SDHCI_CTRL_VDD_180; break; + case MMC_TIMING_MMC_DDR52: case MMC_TIMING_UHS_DDR50: ctrl_2 |= SDHCI_CTRL_UHS_DDR50 | SDHCI_CTRL_VDD_180; break; -- cgit v1.2.3-59-g8ed1b From cc9571e85808dfc121e4fda5c75c9a3c3c75e514 Mon Sep 17 00:00:00 2001 From: Sebastian Hesselbarth Date: Tue, 21 Oct 2014 11:22:35 +0200 Subject: mmc: sdhci-pxav3: Move private driver data to driver source struct sdhci_pxa is only used in sdhci_pxa driver itself, so move it there. Signed-off-by: Sebastian Hesselbarth Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-pxav3.c | 5 +++++ include/linux/platform_data/pxa_sdhci.h | 5 ----- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/mmc/host/sdhci-pxav3.c b/drivers/mmc/host/sdhci-pxav3.c index b55c807982fe..48bc8179c8fc 100644 --- a/drivers/mmc/host/sdhci-pxav3.c +++ b/drivers/mmc/host/sdhci-pxav3.c @@ -58,6 +58,11 @@ #define SDCE_MISC_INT (1<<2) #define SDCE_MISC_INT_EN (1<<1) +struct sdhci_pxa { + u8 clk_enable; + u8 power_mode; +}; + /* * These registers are relative to the second register region, for the * MBus bridge. diff --git a/include/linux/platform_data/pxa_sdhci.h b/include/linux/platform_data/pxa_sdhci.h index 27d3156d093a..9e20c2fb4ffd 100644 --- a/include/linux/platform_data/pxa_sdhci.h +++ b/include/linux/platform_data/pxa_sdhci.h @@ -55,9 +55,4 @@ struct sdhci_pxa_platdata { unsigned int quirks2; unsigned int pm_caps; }; - -struct sdhci_pxa { - u8 clk_enable; - u8 power_mode; -}; #endif /* _PXA_SDHCI_H_ */ -- cgit v1.2.3-59-g8ed1b From ff8878fd64c0e578d979816a675c8ecb937888bd Mon Sep 17 00:00:00 2001 From: Sebastian Hesselbarth Date: Tue, 21 Oct 2014 11:22:36 +0200 Subject: mmc: sdhci-pxav3: Remove unused clk_enable from sdhci_pxa clk_enable from struct sdhci_pxa is unused, remove it from the private driver data. Signed-off-by: Sebastian Hesselbarth Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-pxav3.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/mmc/host/sdhci-pxav3.c b/drivers/mmc/host/sdhci-pxav3.c index 48bc8179c8fc..d1f63d32b2cd 100644 --- a/drivers/mmc/host/sdhci-pxav3.c +++ b/drivers/mmc/host/sdhci-pxav3.c @@ -59,7 +59,6 @@ #define SDCE_MISC_INT_EN (1<<1) struct sdhci_pxa { - u8 clk_enable; u8 power_mode; }; -- cgit v1.2.3-59-g8ed1b From 20d5a70344e526f51efe50861be10f6d743b7706 Mon Sep 17 00:00:00 2001 From: Sebastian Hesselbarth Date: Tue, 21 Oct 2014 11:22:37 +0200 Subject: mmc: sdhci-pxav3: Remove checks for mandatory host clock NULL-checking a struct clk it not only wrong but also not required as for PXAv3 driver the corresponding clock is mandatory. Remove the checks from sdhci_pxav3_runtime_{suspend,resume}. Signed-off-by: Sebastian Hesselbarth Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-pxav3.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/drivers/mmc/host/sdhci-pxav3.c b/drivers/mmc/host/sdhci-pxav3.c index d1f63d32b2cd..e52bbbb09d88 100644 --- a/drivers/mmc/host/sdhci-pxav3.c +++ b/drivers/mmc/host/sdhci-pxav3.c @@ -448,13 +448,11 @@ static int sdhci_pxav3_runtime_suspend(struct device *dev) struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); unsigned long flags; - if (pltfm_host->clk) { - spin_lock_irqsave(&host->lock, flags); - host->runtime_suspended = true; - spin_unlock_irqrestore(&host->lock, flags); + spin_lock_irqsave(&host->lock, flags); + host->runtime_suspended = true; + spin_unlock_irqrestore(&host->lock, flags); - clk_disable_unprepare(pltfm_host->clk); - } + clk_disable_unprepare(pltfm_host->clk); return 0; } @@ -465,13 +463,11 @@ static int sdhci_pxav3_runtime_resume(struct device *dev) struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); unsigned long flags; - if (pltfm_host->clk) { - clk_prepare_enable(pltfm_host->clk); + clk_prepare_enable(pltfm_host->clk); - spin_lock_irqsave(&host->lock, flags); - host->runtime_suspended = false; - spin_unlock_irqrestore(&host->lock, flags); - } + spin_lock_irqsave(&host->lock, flags); + host->runtime_suspended = false; + spin_unlock_irqrestore(&host->lock, flags); return 0; } -- cgit v1.2.3-59-g8ed1b From d99903ca4c89c3aa325845cf87ff249d0b432261 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Mon, 6 Oct 2014 10:28:35 +0200 Subject: mmc: core: Remove superfluous ifdefs for SDIO bus' PM callbacks Signed-off-by: Ulf Hansson --- drivers/mmc/core/sdio_bus.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c index 6da97b170563..f09040bf5484 100644 --- a/drivers/mmc/core/sdio_bus.c +++ b/drivers/mmc/core/sdio_bus.c @@ -196,8 +196,6 @@ static int sdio_bus_remove(struct device *dev) return ret; } -#ifdef CONFIG_PM - static const struct dev_pm_ops sdio_bus_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(pm_generic_suspend, pm_generic_resume) SET_RUNTIME_PM_OPS( @@ -207,14 +205,6 @@ static const struct dev_pm_ops sdio_bus_pm_ops = { ) }; -#define SDIO_PM_OPS_PTR (&sdio_bus_pm_ops) - -#else /* !CONFIG_PM */ - -#define SDIO_PM_OPS_PTR NULL - -#endif /* !CONFIG_PM */ - static struct bus_type sdio_bus_type = { .name = "sdio", .dev_groups = sdio_dev_groups, @@ -222,7 +212,7 @@ static struct bus_type sdio_bus_type = { .uevent = sdio_bus_uevent, .probe = sdio_bus_probe, .remove = sdio_bus_remove, - .pm = SDIO_PM_OPS_PTR, + .pm = &sdio_bus_pm_ops, }; int sdio_register_bus(void) -- cgit v1.2.3-59-g8ed1b From 433b7b1210a4ece4f2b4f1b04f31a2f0928c8aa8 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Mon, 6 Oct 2014 11:00:15 +0200 Subject: mmc: core: Don't export the to_sdio_driver macro The macro is only used by the mmc core, so let's move it in there. Signed-off-by: Ulf Hansson --- drivers/mmc/core/sdio_bus.c | 2 ++ include/linux/mmc/sdio_func.h | 2 -- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c index f09040bf5484..51e23f502108 100644 --- a/drivers/mmc/core/sdio_bus.c +++ b/drivers/mmc/core/sdio_bus.c @@ -26,6 +26,8 @@ #include "sdio_cis.h" #include "sdio_bus.h" +#define to_sdio_driver(d) container_of(d, struct sdio_driver, drv) + /* show configuration fields */ #define sdio_config_attr(field, format_string) \ static ssize_t \ diff --git a/include/linux/mmc/sdio_func.h b/include/linux/mmc/sdio_func.h index 50f0bc952328..aab032a6ae61 100644 --- a/include/linux/mmc/sdio_func.h +++ b/include/linux/mmc/sdio_func.h @@ -84,8 +84,6 @@ struct sdio_driver { struct device_driver drv; }; -#define to_sdio_driver(d) container_of(d, struct sdio_driver, drv) - /** * SDIO_DEVICE - macro used to describe a specific SDIO device * @vend: the 16 bit manufacturer code -- cgit v1.2.3-59-g8ed1b From 0967edc6ef5c3c181cabde3178ea9f33e5130e4a Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Mon, 6 Oct 2014 11:29:42 +0200 Subject: mmc: core: Convert the mmc_driver to use the modern PM ops Instead of having specific mmc system PM callbacks for the mmc driver, let's convert to use the common ones. Signed-off-by: Ulf Hansson --- drivers/mmc/card/block.c | 16 ++++++++-------- drivers/mmc/core/bus.c | 14 ++++---------- 2 files changed, 12 insertions(+), 18 deletions(-) diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index a11451f4f408..dfbdfb995dd3 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -2516,15 +2516,17 @@ static void mmc_blk_shutdown(struct mmc_card *card) _mmc_blk_suspend(card); } -#ifdef CONFIG_PM -static int mmc_blk_suspend(struct mmc_card *card) +#ifdef CONFIG_PM_SLEEP +static int mmc_blk_suspend(struct device *dev) { + struct mmc_card *card = mmc_dev_to_card(dev); return _mmc_blk_suspend(card); } -static int mmc_blk_resume(struct mmc_card *card) +static int mmc_blk_resume(struct device *dev) { struct mmc_blk_data *part_md; + struct mmc_card *card = mmc_dev_to_card(dev); struct mmc_blk_data *md = mmc_get_drvdata(card); if (md) { @@ -2540,19 +2542,17 @@ static int mmc_blk_resume(struct mmc_card *card) } return 0; } -#else -#define mmc_blk_suspend NULL -#define mmc_blk_resume NULL #endif +static SIMPLE_DEV_PM_OPS(mmc_blk_pm_ops, mmc_blk_suspend, mmc_blk_resume); + static struct mmc_driver mmc_driver = { .drv = { .name = "mmcblk", + .pm = &mmc_blk_pm_ops, }, .probe = mmc_blk_probe, .remove = mmc_blk_remove, - .suspend = mmc_blk_suspend, - .resume = mmc_blk_resume, .shutdown = mmc_blk_shutdown, }; diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c index 8a1f1240e058..2f375283c423 100644 --- a/drivers/mmc/core/bus.c +++ b/drivers/mmc/core/bus.c @@ -145,16 +145,13 @@ static void mmc_bus_shutdown(struct device *dev) #ifdef CONFIG_PM_SLEEP static int mmc_bus_suspend(struct device *dev) { - struct mmc_driver *drv = to_mmc_driver(dev->driver); struct mmc_card *card = mmc_dev_to_card(dev); struct mmc_host *host = card->host; int ret; - if (dev->driver && drv->suspend) { - ret = drv->suspend(card); - if (ret) - return ret; - } + ret = pm_generic_suspend(dev); + if (ret) + return ret; ret = host->bus_ops->suspend(host); return ret; @@ -162,7 +159,6 @@ static int mmc_bus_suspend(struct device *dev) static int mmc_bus_resume(struct device *dev) { - struct mmc_driver *drv = to_mmc_driver(dev->driver); struct mmc_card *card = mmc_dev_to_card(dev); struct mmc_host *host = card->host; int ret; @@ -172,9 +168,7 @@ static int mmc_bus_resume(struct device *dev) pr_warn("%s: error %d during resume (card was removed?)\n", mmc_hostname(host), ret); - if (dev->driver && drv->resume) - ret = drv->resume(card); - + ret = pm_generic_resume(dev); return ret; } #endif -- cgit v1.2.3-59-g8ed1b From 6685ac62b2f08fcff77dc35c6b8bff1b74aaa408 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Mon, 6 Oct 2014 13:51:40 +0200 Subject: mmc: core: Convert mmc_driver to device_driver The struct mmc_driver adds an extra layer on top of the struct device_driver. That would be fine, if there were a good reason, but that's not the case. Let's simplify code by converting to the common struct device_driver instead and thus also removing superfluous overhead. Signed-off-by: Ulf Hansson --- drivers/mmc/card/block.c | 26 ++++++++++++++------------ drivers/mmc/card/mmc_test.c | 18 +++++++++++------- drivers/mmc/core/bus.c | 41 ++++++++--------------------------------- include/linux/mmc/card.h | 16 ++-------------- 4 files changed, 35 insertions(+), 66 deletions(-) diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index dfbdfb995dd3..70569d9b5c74 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -2425,8 +2425,9 @@ static const struct mmc_fixup blk_fixups[] = END_FIXUP }; -static int mmc_blk_probe(struct mmc_card *card) +static int mmc_blk_probe(struct device *dev) { + struct mmc_card *card = mmc_dev_to_card(dev); struct mmc_blk_data *md, *part_md; char cap_str[10]; @@ -2481,8 +2482,9 @@ static int mmc_blk_probe(struct mmc_card *card) return 0; } -static void mmc_blk_remove(struct mmc_card *card) +static int mmc_blk_remove(struct device *dev) { + struct mmc_card *card = mmc_dev_to_card(dev); struct mmc_blk_data *md = mmc_get_drvdata(card); mmc_blk_remove_parts(card, md); @@ -2495,11 +2497,14 @@ static void mmc_blk_remove(struct mmc_card *card) pm_runtime_put_noidle(&card->dev); mmc_blk_remove_req(md); mmc_set_drvdata(card, NULL); + + return 0; } -static int _mmc_blk_suspend(struct mmc_card *card) +static int _mmc_blk_suspend(struct device *dev) { struct mmc_blk_data *part_md; + struct mmc_card *card = mmc_dev_to_card(dev); struct mmc_blk_data *md = mmc_get_drvdata(card); if (md) { @@ -2511,16 +2516,15 @@ static int _mmc_blk_suspend(struct mmc_card *card) return 0; } -static void mmc_blk_shutdown(struct mmc_card *card) +static void mmc_blk_shutdown(struct device *dev) { - _mmc_blk_suspend(card); + _mmc_blk_suspend(dev); } #ifdef CONFIG_PM_SLEEP static int mmc_blk_suspend(struct device *dev) { - struct mmc_card *card = mmc_dev_to_card(dev); - return _mmc_blk_suspend(card); + return _mmc_blk_suspend(dev); } static int mmc_blk_resume(struct device *dev) @@ -2546,11 +2550,9 @@ static int mmc_blk_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(mmc_blk_pm_ops, mmc_blk_suspend, mmc_blk_resume); -static struct mmc_driver mmc_driver = { - .drv = { - .name = "mmcblk", - .pm = &mmc_blk_pm_ops, - }, +static struct device_driver mmc_driver = { + .name = "mmcblk", + .pm = &mmc_blk_pm_ops, .probe = mmc_blk_probe, .remove = mmc_blk_remove, .shutdown = mmc_blk_shutdown, diff --git a/drivers/mmc/card/mmc_test.c b/drivers/mmc/card/mmc_test.c index 0c0fc52d42c5..b0643432d6d9 100644 --- a/drivers/mmc/card/mmc_test.c +++ b/drivers/mmc/card/mmc_test.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include /* For nr_free_buffer_pages() */ @@ -2997,8 +2998,9 @@ err: return ret; } -static int mmc_test_probe(struct mmc_card *card) +static int mmc_test_probe(struct device *dev) { + struct mmc_card *card = mmc_dev_to_card(dev); int ret; if (!mmc_card_mmc(card) && !mmc_card_sd(card)) @@ -3013,20 +3015,22 @@ static int mmc_test_probe(struct mmc_card *card) return 0; } -static void mmc_test_remove(struct mmc_card *card) +static int mmc_test_remove(struct device *dev) { + struct mmc_card *card = mmc_dev_to_card(dev); + mmc_test_free_result(card); mmc_test_free_dbgfs_file(card); + + return 0; } -static void mmc_test_shutdown(struct mmc_card *card) +static void mmc_test_shutdown(struct device *dev) { } -static struct mmc_driver mmc_driver = { - .drv = { - .name = "mmc_test", - }, +static struct device_driver mmc_driver = { + .name = "mmc_test", .probe = mmc_test_probe, .remove = mmc_test_remove, .shutdown = mmc_test_shutdown, diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c index 2f375283c423..5ca562ccfcf3 100644 --- a/drivers/mmc/core/bus.c +++ b/drivers/mmc/core/bus.c @@ -25,8 +25,6 @@ #include "sdio_cis.h" #include "bus.h" -#define to_mmc_driver(d) container_of(d, struct mmc_driver, drv) - static ssize_t type_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -106,33 +104,14 @@ mmc_bus_uevent(struct device *dev, struct kobj_uevent_env *env) return retval; } -static int mmc_bus_probe(struct device *dev) -{ - struct mmc_driver *drv = to_mmc_driver(dev->driver); - struct mmc_card *card = mmc_dev_to_card(dev); - - return drv->probe(card); -} - -static int mmc_bus_remove(struct device *dev) -{ - struct mmc_driver *drv = to_mmc_driver(dev->driver); - struct mmc_card *card = mmc_dev_to_card(dev); - - drv->remove(card); - - return 0; -} - static void mmc_bus_shutdown(struct device *dev) { - struct mmc_driver *drv = to_mmc_driver(dev->driver); struct mmc_card *card = mmc_dev_to_card(dev); struct mmc_host *host = card->host; int ret; - if (dev->driver && drv->shutdown) - drv->shutdown(card); + if (dev->driver && dev->driver->shutdown) + dev->driver->shutdown(dev); if (host->bus_ops->shutdown) { ret = host->bus_ops->shutdown(host); @@ -201,8 +180,6 @@ static struct bus_type mmc_bus_type = { .dev_groups = mmc_dev_groups, .match = mmc_bus_match, .uevent = mmc_bus_uevent, - .probe = mmc_bus_probe, - .remove = mmc_bus_remove, .shutdown = mmc_bus_shutdown, .pm = &mmc_bus_pm_ops, }; @@ -221,24 +198,22 @@ void mmc_unregister_bus(void) * mmc_register_driver - register a media driver * @drv: MMC media driver */ -int mmc_register_driver(struct mmc_driver *drv) +int mmc_register_driver(struct device_driver *drv) { - drv->drv.bus = &mmc_bus_type; - return driver_register(&drv->drv); + drv->bus = &mmc_bus_type; + return driver_register(drv); } - EXPORT_SYMBOL(mmc_register_driver); /** * mmc_unregister_driver - unregister a media driver * @drv: MMC media driver */ -void mmc_unregister_driver(struct mmc_driver *drv) +void mmc_unregister_driver(struct device_driver *drv) { - drv->drv.bus = &mmc_bus_type; - driver_unregister(&drv->drv); + drv->bus = &mmc_bus_type; + driver_unregister(drv); } - EXPORT_SYMBOL(mmc_unregister_driver); static void mmc_release_card(struct device *dev) diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h index b0692d28f8e6..cf54afe5d863 100644 --- a/include/linux/mmc/card.h +++ b/include/linux/mmc/card.h @@ -513,20 +513,8 @@ static inline int mmc_card_broken_irq_polling(const struct mmc_card *c) #define mmc_get_drvdata(c) dev_get_drvdata(&(c)->dev) #define mmc_set_drvdata(c,d) dev_set_drvdata(&(c)->dev, d) -/* - * 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 *); - int (*suspend)(struct mmc_card *); - int (*resume)(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 int mmc_register_driver(struct device_driver *); +extern void mmc_unregister_driver(struct device_driver *); extern void mmc_fixup_device(struct mmc_card *card, const struct mmc_fixup *table); -- cgit v1.2.3-59-g8ed1b From eaaceb6cbf7ef6f480b3f80468beb21eafe82ac0 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Mon, 6 Oct 2014 14:08:09 +0200 Subject: mmc: msm_sdcc: Use platform_set|get_drvdata The msm_sdcc host shall not use mmc core specific macros to handle its driver data. Instead, convert to use the platform device driver macros. Signed-off-by: Ulf Hansson --- drivers/mmc/host/msm_sdcc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c index 9405ecdaf6cf..90c60fd4ff6e 100644 --- a/drivers/mmc/host/msm_sdcc.c +++ b/drivers/mmc/host/msm_sdcc.c @@ -1360,7 +1360,7 @@ msmsdcc_probe(struct platform_device *pdev) if (ret) goto cmd_irq_free; - mmc_set_drvdata(pdev, mmc); + platform_set_drvdata(pdev, mmc); mmc_add_host(mmc); pr_info("%s: Qualcomm MSM SDCC at 0x%016llx irq %d,%d dma %d\n", @@ -1419,7 +1419,7 @@ ioremap_free: static int msmsdcc_suspend(struct platform_device *dev, pm_message_t state) { - struct mmc_host *mmc = mmc_get_drvdata(dev); + struct mmc_host *mmc = platform_get_drvdata(dev); if (mmc) { struct msmsdcc_host *host = mmc_priv(mmc); @@ -1437,7 +1437,7 @@ msmsdcc_suspend(struct platform_device *dev, pm_message_t state) static int msmsdcc_resume(struct platform_device *dev) { - struct mmc_host *mmc = mmc_get_drvdata(dev); + struct mmc_host *mmc = platform_get_drvdata(dev); if (mmc) { struct msmsdcc_host *host = mmc_priv(mmc); -- cgit v1.2.3-59-g8ed1b From fc95e30ba33b9f4faa8630d0762af2548031dc00 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Mon, 6 Oct 2014 14:34:09 +0200 Subject: mmc: block: Use dev_set|get_drvdata() In most of the cases mmc_get|set_drvdata() didn't simplify code, which should be the primary reason for such macros. Let's remove them and convert to the common device_driver macros, dev_set|get_drvdata() instead. Signed-off-by: Ulf Hansson --- drivers/mmc/card/block.c | 21 ++++++++++----------- include/linux/mmc/card.h | 2 -- 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index 70569d9b5c74..f45f7e3870be 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -112,7 +112,7 @@ struct mmc_blk_data { /* * Only set in main mmc_blk_data associated - * with mmc_card with mmc_set_drvdata, and keeps + * with mmc_card with dev_set_drvdata, and keeps * track of the current selected device partition. */ unsigned int part_curr; @@ -642,7 +642,7 @@ static inline int mmc_blk_part_switch(struct mmc_card *card, struct mmc_blk_data *md) { int ret; - struct mmc_blk_data *main_md = mmc_get_drvdata(card); + struct mmc_blk_data *main_md = dev_get_drvdata(&card->dev); if (main_md->part_curr == md->part_type) return 0; @@ -1004,7 +1004,8 @@ static int mmc_blk_reset(struct mmc_blk_data *md, struct mmc_host *host, err = mmc_hw_reset(host); /* Ensure we switch back to the correct partition */ if (err != -EOPNOTSUPP) { - struct mmc_blk_data *main_md = mmc_get_drvdata(host->card); + struct mmc_blk_data *main_md = + dev_get_drvdata(&host->card->dev); int part_err; main_md->part_curr = main_md->part_type; @@ -2093,7 +2094,7 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card, /* * !subname implies we are creating main mmc_blk_data that will be - * associated with mmc_card with mmc_set_drvdata. Due to device + * associated with mmc_card with dev_set_drvdata. Due to device * partitions, devidx will not coincide with a per-physical card * index anymore so we keep track of a name index. */ @@ -2452,7 +2453,7 @@ static int mmc_blk_probe(struct device *dev) if (mmc_blk_alloc_parts(card, md)) goto out; - mmc_set_drvdata(card, md); + dev_set_drvdata(dev, md); if (mmc_add_disk(md)) goto out; @@ -2485,7 +2486,7 @@ static int mmc_blk_probe(struct device *dev) static int mmc_blk_remove(struct device *dev) { struct mmc_card *card = mmc_dev_to_card(dev); - struct mmc_blk_data *md = mmc_get_drvdata(card); + struct mmc_blk_data *md = dev_get_drvdata(dev); mmc_blk_remove_parts(card, md); pm_runtime_get_sync(&card->dev); @@ -2496,7 +2497,7 @@ static int mmc_blk_remove(struct device *dev) pm_runtime_disable(&card->dev); pm_runtime_put_noidle(&card->dev); mmc_blk_remove_req(md); - mmc_set_drvdata(card, NULL); + dev_set_drvdata(dev, NULL); return 0; } @@ -2504,8 +2505,7 @@ static int mmc_blk_remove(struct device *dev) static int _mmc_blk_suspend(struct device *dev) { struct mmc_blk_data *part_md; - struct mmc_card *card = mmc_dev_to_card(dev); - struct mmc_blk_data *md = mmc_get_drvdata(card); + struct mmc_blk_data *md = dev_get_drvdata(dev); if (md) { mmc_queue_suspend(&md->queue); @@ -2530,8 +2530,7 @@ static int mmc_blk_suspend(struct device *dev) static int mmc_blk_resume(struct device *dev) { struct mmc_blk_data *part_md; - struct mmc_card *card = mmc_dev_to_card(dev); - struct mmc_blk_data *md = mmc_get_drvdata(card); + struct mmc_blk_data *md = dev_get_drvdata(dev); if (md) { /* diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h index cf54afe5d863..64f413676410 100644 --- a/include/linux/mmc/card.h +++ b/include/linux/mmc/card.h @@ -510,8 +510,6 @@ static inline int mmc_card_broken_irq_polling(const struct mmc_card *c) #define mmc_dev_to_card(d) container_of(d, struct mmc_card, dev) #define mmc_list_to_card(l) container_of(l, struct mmc_card, node) -#define mmc_get_drvdata(c) dev_get_drvdata(&(c)->dev) -#define mmc_set_drvdata(c,d) dev_set_drvdata(&(c)->dev, d) extern int mmc_register_driver(struct device_driver *); extern void mmc_unregister_driver(struct device_driver *); -- cgit v1.2.3-59-g8ed1b From 390e316c606de2f839389698f4531004cfe1bafd Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Mon, 6 Oct 2014 14:39:03 +0200 Subject: mmc: core: Remove unused mmc_list_to_card() macro Signed-off-by: Ulf Hansson --- include/linux/mmc/card.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h index 64f413676410..0ba8f251f8ef 100644 --- a/include/linux/mmc/card.h +++ b/include/linux/mmc/card.h @@ -509,8 +509,6 @@ static inline int mmc_card_broken_irq_polling(const struct mmc_card *c) #define mmc_dev_to_card(d) container_of(d, struct mmc_card, dev) -#define mmc_list_to_card(l) container_of(l, struct mmc_card, node) - extern int mmc_register_driver(struct device_driver *); extern void mmc_unregister_driver(struct device_driver *); -- cgit v1.2.3-59-g8ed1b From 536f6b91d21b81bec6c8a675b3a00052ee05f986 Mon Sep 17 00:00:00 2001 From: Sonny Rao Date: Thu, 16 Oct 2014 09:58:05 -0700 Subject: mmc: dw_mmc: Reset DMA before enabling IDMAC We've already got a reset of DMA after it's done. Add one before we start DMA too. This fixes a data corruption on Rockchip SoCs which will get bad data when doing a DMA transfer after doing a PIO transfer. We tested this on an Exynos 5800 with HS200 and didn't notice any difference in sequential read throughput. Signed-off-by: Sonny Rao Signed-off-by: Doug Anderson Tested-by: Doug Anderson Acked-by: Jaehoon Chung Tested-by: Jaehoon Chung Reviewed-by: Alim Akhtar Signed-off-by: Ulf Hansson --- drivers/mmc/host/dw_mmc.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 69f0cc68d5b2..ca67f6923bfd 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -83,6 +83,7 @@ struct idmac_desc { #endif /* CONFIG_MMC_DW_IDMAC */ static bool dw_mci_reset(struct dw_mci *host); +static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset); #if defined(CONFIG_DEBUG_FS) static int dw_mci_req_show(struct seq_file *s, void *v) @@ -448,6 +449,10 @@ static void dw_mci_idmac_start_dma(struct dw_mci *host, unsigned int sg_len) dw_mci_translate_sglist(host, host->data, sg_len); + /* Make sure to reset DMA in case we did PIO before this */ + dw_mci_ctrl_reset(host, SDMMC_CTRL_DMA_RESET); + dw_mci_idmac_reset(host); + /* Select IDMAC interface */ temp = mci_readl(host, CTRL); temp |= SDMMC_CTRL_USE_IDMAC; -- cgit v1.2.3-59-g8ed1b From b19caf379c82e99737c29bc15d7b7fd7d24279f9 Mon Sep 17 00:00:00 2001 From: Doug Anderson Date: Fri, 10 Oct 2014 21:16:16 -0700 Subject: mmc: dw_mmc: Change signal voltage error to dev_dbg() In (28f92b5 mmc: core: Try other signal levels during power up) we can see that there are times when it's valid to try several signal voltages. Don't print an ugly error in the logs when that happens. Signed-off-by: Doug Anderson Reviewed-by: Alim Akhtar Acked-by: Jaehoon Chung Signed-off-by: Ulf Hansson --- drivers/mmc/host/dw_mmc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index ca67f6923bfd..545f62191afd 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -1080,7 +1080,7 @@ static int dw_mci_switch_voltage(struct mmc_host *mmc, struct mmc_ios *ios) ret = regulator_set_voltage(mmc->supply.vqmmc, min_uv, max_uv); if (ret) { - dev_err(&mmc->class_dev, + dev_dbg(&mmc->class_dev, "Regulator set error %d: %d - %d\n", ret, min_uv, max_uv); return ret; -- cgit v1.2.3-59-g8ed1b From e7791079ae89d91024019e11a1f430d38c491246 Mon Sep 17 00:00:00 2001 From: Doug Anderson Date: Tue, 14 Oct 2014 09:39:12 -0700 Subject: mmc: dw_mmc: rockchip: Don't recalc the clock when it goes off The "set_ios" function is called with a clock of 0 when the clock is turning off. There's no reason to go through all the extra Rockchip logic (whose goal is to make sure DIV is 0 or 1) in that case. The Rockchip logic happened to work because the CCF will pick the lowest possible rate when you ask it for a clock of 0, but it's silly to go through all the remuxing and adjusting for no reason. Signed-off-by: Doug Anderson Acked-by: Jaehoon Chung Signed-off-by: Ulf Hansson --- drivers/mmc/host/dw_mmc-rockchip.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/mmc/host/dw_mmc-rockchip.c b/drivers/mmc/host/dw_mmc-rockchip.c index f0c2cb1a210d..bbb4ec386e56 100644 --- a/drivers/mmc/host/dw_mmc-rockchip.c +++ b/drivers/mmc/host/dw_mmc-rockchip.c @@ -37,6 +37,9 @@ static void dw_mci_rk3288_set_ios(struct dw_mci *host, struct mmc_ios *ios) unsigned int cclkin; u32 bus_hz; + if (ios->clock == 0) + return; + /* * cclkin: source clock of mmc controller * bus_hz: card interface clock generated by CLKGEN -- cgit v1.2.3-59-g8ed1b From 0f762426769a517d5b278e4e5d579fcea6801734 Mon Sep 17 00:00:00 2001 From: Gwendal Grignou Date: Thu, 16 Oct 2014 11:27:16 -0700 Subject: mmc: core: Report firmware version for eMMC 5.0 devices. For eMMC 5.0 compliant device, firmware version is stored in ext_csd. Report firmware as a 64bit hexa decimal. Vendor can use hexa or ascii string to report firmware version. Also add FFU related EXT_CSD register and note if the device is FFU capable. Signed-off-by: Gwendal Grignou Signed-off-by: Ulf Hansson --- drivers/mmc/core/mmc.c | 27 ++++++++++++++++++++++++++- include/linux/mmc/card.h | 3 +++ include/linux/mmc/mmc.h | 3 +++ 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index bcde451f6d91..a5e05ceb554c 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -628,6 +628,14 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) card->ext_csd.data_sector_size = 512; } + /* eMMC v5 or later */ + if (card->ext_csd.rev >= 7) { + memcpy(card->ext_csd.fwrev, &ext_csd[EXT_CSD_FIRMWARE_VERSION], + MMC_FIRMWARE_LEN); + card->ext_csd.ffu_capable = + (ext_csd[EXT_CSD_SUPPORTED_MODE] & 0x1) && + !(ext_csd[EXT_CSD_FW_CONFIG] & 0x1); + } out: return err; } @@ -722,7 +730,7 @@ MMC_DEV_ATTR(csd, "%08x%08x%08x%08x\n", card->raw_csd[0], card->raw_csd[1], MMC_DEV_ATTR(date, "%02d/%04d\n", card->cid.month, card->cid.year); MMC_DEV_ATTR(erase_size, "%u\n", card->erase_size << 9); MMC_DEV_ATTR(preferred_erase_size, "%u\n", card->pref_erase << 9); -MMC_DEV_ATTR(fwrev, "0x%x\n", card->cid.fwrev); +MMC_DEV_ATTR(ffu_capable, "%d\n", card->ext_csd.ffu_capable); MMC_DEV_ATTR(hwrev, "0x%x\n", card->cid.hwrev); MMC_DEV_ATTR(manfid, "0x%06x\n", card->cid.manfid); MMC_DEV_ATTR(name, "%s\n", card->cid.prod_name); @@ -735,6 +743,22 @@ MMC_DEV_ATTR(enhanced_area_size, "%u\n", card->ext_csd.enhanced_area_size); MMC_DEV_ATTR(raw_rpmb_size_mult, "%#x\n", card->ext_csd.raw_rpmb_size_mult); MMC_DEV_ATTR(rel_sectors, "%#x\n", card->ext_csd.rel_sectors); +static ssize_t mmc_fwrev_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct mmc_card *card = mmc_dev_to_card(dev); + + if (card->ext_csd.rev < 7) { + return sprintf(buf, "0x%x\n", card->cid.fwrev); + } else { + return sprintf(buf, "0x%*phN\n", MMC_FIRMWARE_LEN, + card->ext_csd.fwrev); + } +} + +static DEVICE_ATTR(fwrev, S_IRUGO, mmc_fwrev_show, NULL); + static struct attribute *mmc_std_attrs[] = { &dev_attr_cid.attr, &dev_attr_csd.attr, @@ -742,6 +766,7 @@ static struct attribute *mmc_std_attrs[] = { &dev_attr_erase_size.attr, &dev_attr_preferred_erase_size.attr, &dev_attr_fwrev.attr, + &dev_attr_ffu_capable.attr, &dev_attr_hwrev.attr, &dev_attr_manfid.attr, &dev_attr_name.attr, diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h index 0ba8f251f8ef..4d69c00497bd 100644 --- a/include/linux/mmc/card.h +++ b/include/linux/mmc/card.h @@ -88,6 +88,9 @@ struct mmc_ext_csd { unsigned int data_tag_unit_size; /* DATA TAG UNIT size */ unsigned int boot_ro_lock; /* ro lock support */ bool boot_ro_lockable; + bool ffu_capable; /* Firmware upgrade support */ +#define MMC_FIRMWARE_LEN 8 + u8 fwrev[MMC_FIRMWARE_LEN]; /* FW version */ u8 raw_exception_status; /* 54 */ u8 raw_partition_support; /* 160 */ u8 raw_rpmb_size_mult; /* 168 */ diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h index 1cd00b3a75b9..49ad7a943638 100644 --- a/include/linux/mmc/mmc.h +++ b/include/linux/mmc/mmc.h @@ -296,6 +296,7 @@ struct _mmc_csd { #define EXT_CSD_SANITIZE_START 165 /* W */ #define EXT_CSD_WR_REL_PARAM 166 /* RO */ #define EXT_CSD_RPMB_MULT 168 /* RO */ +#define EXT_CSD_FW_CONFIG 169 /* R/W */ #define EXT_CSD_BOOT_WP 173 /* R/W */ #define EXT_CSD_ERASE_GROUP_DEF 175 /* R/W */ #define EXT_CSD_PART_CONFIG 179 /* R/W */ @@ -332,6 +333,8 @@ struct _mmc_csd { #define EXT_CSD_GENERIC_CMD6_TIME 248 /* RO */ #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_SUPPORTED_MODE 493 /* RO */ #define EXT_CSD_TAG_UNIT_SIZE 498 /* RO */ #define EXT_CSD_DATA_TAG_SUPPORT 499 /* RO */ #define EXT_CSD_MAX_PACKED_WRITES 500 /* RO */ -- cgit v1.2.3-59-g8ed1b From 9cbef73cb657ff795c130cccfed251f0ae923abb Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Fri, 17 Oct 2014 10:26:36 +0200 Subject: mmc: atmel-mci: move mach header to platform_data Move the mach header that can come either from arm/mach-at91 or avr32 to platform_data to be able to switch the AT91 platforms to multiplatform. Signed-off-by: Alexandre Belloni Acked-by: Arnd Bergmann Acked-by: Ludovic Desroches Signed-off-by: Ulf Hansson [Ulf: Fixed compile error] --- drivers/mmc/host/atmel-mci.c | 2 +- include/linux/platform_data/mmc-atmel-mci.h | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 include/linux/platform_data/mmc-atmel-mci.h diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c index 77250d4b1979..0b9ddf8aed04 100644 --- a/drivers/mmc/host/atmel-mci.c +++ b/drivers/mmc/host/atmel-mci.c @@ -30,11 +30,11 @@ #include #include #include +#include #include #include -#include #include #include diff --git a/include/linux/platform_data/mmc-atmel-mci.h b/include/linux/platform_data/mmc-atmel-mci.h new file mode 100644 index 000000000000..399a2d5a14bd --- /dev/null +++ b/include/linux/platform_data/mmc-atmel-mci.h @@ -0,0 +1,22 @@ +#ifndef __MMC_ATMEL_MCI_H +#define __MMC_ATMEL_MCI_H + +#include +#include + +/** + * struct mci_dma_data - DMA data for MCI interface + */ +struct mci_dma_data { +#ifdef CONFIG_ARM + struct at_dma_slave sdata; +#else + struct dw_dma_slave sdata; +#endif +}; + +/* accessor macros */ +#define slave_data_ptr(s) (&(s)->sdata) +#define find_slave_dev(s) ((s)->sdata.dma_dev) + +#endif /* __MMC_ATMEL_MCI_H */ -- cgit v1.2.3-59-g8ed1b From 19336880bf21709fa419245435e9424afdb5d3ea Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Fri, 17 Oct 2014 10:26:37 +0200 Subject: ARM: at91: remove mach/atmel-mci.h Use the generic platform_data header file instead of mach/atmel-mci.h Signed-off-by: Alexandre Belloni Acked-by: Arnd Bergmann Acked-by: Ludovic Desroches Signed-off-by: Ulf Hansson --- arch/arm/mach-at91/at91sam9g45_devices.c | 2 +- arch/arm/mach-at91/include/mach/atmel-mci.h | 17 ----------------- 2 files changed, 1 insertion(+), 18 deletions(-) delete mode 100644 arch/arm/mach-at91/include/mach/atmel-mci.h diff --git a/arch/arm/mach-at91/at91sam9g45_devices.c b/arch/arm/mach-at91/at91sam9g45_devices.c index 21ab782cc8e9..06ecbafd01ee 100644 --- a/arch/arm/mach-at91/at91sam9g45_devices.c +++ b/arch/arm/mach-at91/at91sam9g45_devices.c @@ -19,6 +19,7 @@ #include #include #include +#include #include @@ -30,7 +31,6 @@ #include #include #include -#include #include #include diff --git a/arch/arm/mach-at91/include/mach/atmel-mci.h b/arch/arm/mach-at91/include/mach/atmel-mci.h deleted file mode 100644 index 3069e4135573..000000000000 --- a/arch/arm/mach-at91/include/mach/atmel-mci.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef __MACH_ATMEL_MCI_H -#define __MACH_ATMEL_MCI_H - -#include - -/** - * struct mci_dma_data - DMA data for MCI interface - */ -struct mci_dma_data { - struct at_dma_slave sdata; -}; - -/* accessor macros */ -#define slave_data_ptr(s) (&(s)->sdata) -#define find_slave_dev(s) ((s)->sdata.dma_dev) - -#endif /* __MACH_ATMEL_MCI_H */ -- cgit v1.2.3-59-g8ed1b From 4df10e02aa92a2f898da408e9b8ef9a73e7f7264 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Fri, 17 Oct 2014 10:26:38 +0200 Subject: avr32: remove mach/atmel-mci.h Use the generic platform_data header file instead of mach/atmel-mci.h Signed-off-by: Alexandre Belloni Acked-by: Arnd Bergmann Acked-by: Ludovic Desroches Signed-off-by: Ulf Hansson --- arch/avr32/mach-at32ap/at32ap700x.c | 2 +- arch/avr32/mach-at32ap/include/mach/atmel-mci.h | 17 ----------------- 2 files changed, 1 insertion(+), 18 deletions(-) delete mode 100644 arch/avr32/mach-at32ap/include/mach/atmel-mci.h diff --git a/arch/avr32/mach-at32ap/at32ap700x.c b/arch/avr32/mach-at32ap/at32ap700x.c index 37b75602adf6..cc92cdb9994c 100644 --- a/arch/avr32/mach-at32ap/at32ap700x.c +++ b/arch/avr32/mach-at32ap/at32ap700x.c @@ -17,7 +17,7 @@ #include #include -#include +#include #include #include diff --git a/arch/avr32/mach-at32ap/include/mach/atmel-mci.h b/arch/avr32/mach-at32ap/include/mach/atmel-mci.h deleted file mode 100644 index 11d7f4b28dc8..000000000000 --- a/arch/avr32/mach-at32ap/include/mach/atmel-mci.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef __MACH_ATMEL_MCI_H -#define __MACH_ATMEL_MCI_H - -#include - -/** - * struct mci_dma_data - DMA data for MCI interface - */ -struct mci_dma_data { - struct dw_dma_slave sdata; -}; - -/* accessor macros */ -#define slave_data_ptr(s) (&(s)->sdata) -#define find_slave_dev(s) ((s)->sdata.dma_dev) - -#endif /* __MACH_ATMEL_MCI_H */ -- cgit v1.2.3-59-g8ed1b From 5d0e1194459f70c06d866531ebf19c9e2b75a77e Mon Sep 17 00:00:00 2001 From: Mike Looijmans Date: Thu, 23 Oct 2014 13:31:00 +0200 Subject: mmc: sdhci-of-arasan: Use signed formatting in error messages "ret" is a signed int, so use "%d" in format strings instead of "%u". This prevents cryptic codes in error messages like this: sdhci-arasan e0101000.sdhci: platform register failed (4294966779) Signed-off-by: Mike Looijmans Reviewed-by: Michal Simek Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-of-arasan.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/sdhci-of-arasan.c b/drivers/mmc/host/sdhci-of-arasan.c index 981d66e5c023..5f10c22ea3aa 100644 --- a/drivers/mmc/host/sdhci-of-arasan.c +++ b/drivers/mmc/host/sdhci-of-arasan.c @@ -165,7 +165,7 @@ static int sdhci_arasan_probe(struct platform_device *pdev) host = sdhci_pltfm_init(pdev, &sdhci_arasan_pdata, 0); if (IS_ERR(host)) { ret = PTR_ERR(host); - dev_err(&pdev->dev, "platform init failed (%u)\n", ret); + dev_err(&pdev->dev, "platform init failed (%d)\n", ret); goto clk_disable_all; } @@ -176,7 +176,7 @@ static int sdhci_arasan_probe(struct platform_device *pdev) ret = sdhci_add_host(host); if (ret) { - dev_err(&pdev->dev, "platform register failed (%u)\n", ret); + dev_err(&pdev->dev, "platform register failed (%d)\n", ret); goto err_pltfm_free; } -- cgit v1.2.3-59-g8ed1b From 51d346068876bf4972efc61969d02958a087f3ee Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 23 Oct 2014 14:37:00 +0300 Subject: mmc: core: silence a shift wrapping warning Presumably ->slotno is normally fairly small and the shift doesn't wrap but static checkers will complain about it. Signed-off-by: Dan Carpenter Signed-off-by: Ulf Hansson --- drivers/mmc/core/sdio_bus.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c index 51e23f502108..60885316afba 100644 --- a/drivers/mmc/core/sdio_bus.c +++ b/drivers/mmc/core/sdio_bus.c @@ -287,7 +287,7 @@ struct sdio_func *sdio_alloc_func(struct mmc_card *card) static void sdio_acpi_set_handle(struct sdio_func *func) { struct mmc_host *host = func->card->host; - u64 addr = (host->slotno << 16) | func->num; + u64 addr = ((u64)host->slotno << 16) | func->num; acpi_preset_companion(&func->dev, ACPI_COMPANION(host->parent), addr); } -- cgit v1.2.3-59-g8ed1b From 6130e7a9c34d01afbd4e7e215846d1f2d70333bb Mon Sep 17 00:00:00 2001 From: Doug Anderson Date: Tue, 14 Oct 2014 09:33:09 -0700 Subject: mmc: dw_mmc: Remove old card detect infrastructure The dw_mmc driver had a bunch of code that ran whenever a card was ejected and inserted. However, this code was old and crufty and should be removed. Some evidence that it's really not needed: 1. Is is supposed to be legal to use 'cd-gpio' on dw_mmc instead of using the built-in card detect mechanism. The 'cd-gpio' code doesn't run any of the crufty old code but yet still works. 2. While looking at this, I realized that my old change (369ac86 mmc: dw_mmc: don't queue up a card detect at slot startup) actually castrated the old code a little bit already and nobody noticed. Specifically "last_detect_state" was left as 0 at bootup. That means that on the first card removal none of the crufty code ran. 3. I can run "while true; do dd if=/dev/mmcblk1 of=/dev/null; done" while ejecting and inserting an SD Card and the world doesn't explode. If some of the crufty old code is actually needed, we should justify it and also put it in some place where it will be run even with "cd-gpio". Note that in my case I'm using the "cd-gpio" mechanism but for various reasons the hardware triggers a dw_mmc "card detect" at bootup. That was actually causing a real bug. The card detect workqueue was running while the system was trying to enumerate the card. The "present != slot->last_detect_state" triggered and we were doing all kinds of crazy stuff and messing up enumeration. The new mechanism of just asking the core to check the card is much safer and then the bogus interrupt doesn't hurt. Signed-off-by: Doug Anderson Tested-by: Jaehoon Chung Acked-by: Jaehoon Chung Tested-by: alim.akhtar Signed-off-by: Ulf Hansson --- drivers/mmc/host/dw_mmc.c | 121 ++++++++------------------------------------- drivers/mmc/host/dw_mmc.h | 2 - include/linux/mmc/dw_mmc.h | 2 - 3 files changed, 20 insertions(+), 105 deletions(-) diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 545f62191afd..bb46b1b8d16b 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -34,7 +34,6 @@ #include #include #include -#include #include #include #include @@ -1959,6 +1958,23 @@ static void dw_mci_cmd_interrupt(struct dw_mci *host, u32 status) tasklet_schedule(&host->tasklet); } +static void dw_mci_handle_cd(struct dw_mci *host) +{ + int i; + + for (i = 0; i < host->num_slots; i++) { + struct dw_mci_slot *slot = host->slot[i]; + + if (!slot) + continue; + + if (slot->mmc->ops->card_event) + slot->mmc->ops->card_event(slot->mmc); + mmc_detect_change(slot->mmc, + msecs_to_jiffies(host->pdata->detect_delay_ms)); + } +} + static irqreturn_t dw_mci_interrupt(int irq, void *dev_id) { struct dw_mci *host = dev_id; @@ -2034,7 +2050,7 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id) if (pending & SDMMC_INT_CD) { mci_writel(host, RINTSTS, SDMMC_INT_CD); - queue_work(host->card_workqueue, &host->card_work); + dw_mci_handle_cd(host); } /* Handle SDIO Interrupts */ @@ -2061,88 +2077,6 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -static void dw_mci_work_routine_card(struct work_struct *work) -{ - struct dw_mci *host = container_of(work, struct dw_mci, card_work); - int i; - - for (i = 0; i < host->num_slots; i++) { - struct dw_mci_slot *slot = host->slot[i]; - struct mmc_host *mmc = slot->mmc; - struct mmc_request *mrq; - int present; - - present = dw_mci_get_cd(mmc); - while (present != slot->last_detect_state) { - dev_dbg(&slot->mmc->class_dev, "card %s\n", - present ? "inserted" : "removed"); - - spin_lock_bh(&host->lock); - - /* Card change detected */ - slot->last_detect_state = present; - - /* Clean up queue if present */ - mrq = slot->mrq; - if (mrq) { - if (mrq == host->mrq) { - host->data = NULL; - host->cmd = NULL; - - switch (host->state) { - case STATE_IDLE: - case STATE_WAITING_CMD11_DONE: - break; - case STATE_SENDING_CMD11: - case STATE_SENDING_CMD: - mrq->cmd->error = -ENOMEDIUM; - if (!mrq->data) - break; - /* fall through */ - case STATE_SENDING_DATA: - mrq->data->error = -ENOMEDIUM; - dw_mci_stop_dma(host); - break; - case STATE_DATA_BUSY: - case STATE_DATA_ERROR: - if (mrq->data->error == -EINPROGRESS) - mrq->data->error = -ENOMEDIUM; - /* fall through */ - case STATE_SENDING_STOP: - if (mrq->stop) - mrq->stop->error = -ENOMEDIUM; - break; - } - - dw_mci_request_end(host, mrq); - } else { - list_del(&slot->queue_node); - mrq->cmd->error = -ENOMEDIUM; - if (mrq->data) - mrq->data->error = -ENOMEDIUM; - if (mrq->stop) - mrq->stop->error = -ENOMEDIUM; - - spin_unlock(&host->lock); - mmc_request_done(slot->mmc, mrq); - spin_lock(&host->lock); - } - } - - /* Power down slot */ - if (present == 0) - dw_mci_reset(host); - - spin_unlock_bh(&host->lock); - - present = dw_mci_get_cd(mmc); - } - - mmc_detect_change(slot->mmc, - msecs_to_jiffies(host->pdata->detect_delay_ms)); - } -} - #ifdef CONFIG_OF /* given a slot id, find out the device node representing that slot */ static struct device_node *dw_mci_of_find_slot_node(struct device *dev, u8 slot) @@ -2294,9 +2228,6 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id) dw_mci_init_debugfs(slot); #endif - /* Card initially undetected */ - slot->last_detect_state = 0; - return 0; err_host_allocated: @@ -2677,17 +2608,10 @@ int dw_mci_probe(struct dw_mci *host) host->data_offset = DATA_240A_OFFSET; tasklet_init(&host->tasklet, dw_mci_tasklet_func, (unsigned long)host); - host->card_workqueue = alloc_workqueue("dw-mci-card", - WQ_MEM_RECLAIM, 1); - if (!host->card_workqueue) { - ret = -ENOMEM; - goto err_dmaunmap; - } - INIT_WORK(&host->card_work, dw_mci_work_routine_card); ret = devm_request_irq(host->dev, host->irq, dw_mci_interrupt, host->irq_flags, "dw-mci", host); if (ret) - goto err_workqueue; + goto err_dmaunmap; if (host->pdata->num_slots) host->num_slots = host->pdata->num_slots; @@ -2723,7 +2647,7 @@ int dw_mci_probe(struct dw_mci *host) } else { dev_dbg(host->dev, "attempted to initialize %d slots, " "but failed on all\n", host->num_slots); - goto err_workqueue; + goto err_dmaunmap; } if (host->quirks & DW_MCI_QUIRK_IDMAC_DTO) @@ -2731,9 +2655,6 @@ int dw_mci_probe(struct dw_mci *host) return 0; -err_workqueue: - destroy_workqueue(host->card_workqueue); - err_dmaunmap: if (host->use_dma && host->dma_ops->exit) host->dma_ops->exit(host); @@ -2767,8 +2688,6 @@ void dw_mci_remove(struct dw_mci *host) mci_writel(host, CLKENA, 0); mci_writel(host, CLKSRC, 0); - destroy_workqueue(host->card_workqueue); - if (host->use_dma && host->dma_ops->exit) host->dma_ops->exit(host); diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h index 01b99e8a9190..71d499557edc 100644 --- a/drivers/mmc/host/dw_mmc.h +++ b/drivers/mmc/host/dw_mmc.h @@ -214,7 +214,6 @@ extern int dw_mci_resume(struct dw_mci *host); * with CONFIG_MMC_CLKGATE. * @flags: Random state bits associated with the slot. * @id: Number of this slot. - * @last_detect_state: Most recently observed card detect state. */ struct dw_mci_slot { struct mmc_host *mmc; @@ -234,7 +233,6 @@ struct dw_mci_slot { #define DW_MMC_CARD_PRESENT 0 #define DW_MMC_CARD_NEED_INIT 1 int id; - int last_detect_state; }; struct dw_mci_tuning_data { diff --git a/include/linux/mmc/dw_mmc.h b/include/linux/mmc/dw_mmc.h index 001366927cf4..69d08144cfad 100644 --- a/include/linux/mmc/dw_mmc.h +++ b/include/linux/mmc/dw_mmc.h @@ -135,7 +135,6 @@ struct dw_mci { struct mmc_command stop_abort; unsigned int prev_blksz; unsigned char timing; - struct workqueue_struct *card_workqueue; /* DMA interface members*/ int use_dma; @@ -154,7 +153,6 @@ struct dw_mci { u32 stop_cmdr; u32 dir_status; struct tasklet_struct tasklet; - struct work_struct card_work; unsigned long pending_events; unsigned long completed_events; enum dw_mci_state state; -- cgit v1.2.3-59-g8ed1b From 00b41b58cdb115ffc28de1adad63a59a61428db8 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Thu, 16 Oct 2014 16:18:51 +0200 Subject: mmc: core: Remove mmc_free_ext_csd() Let callers of mmc_free_ext_csd() do kfree() directly instead. Signed-off-by: Ulf Hansson --- drivers/mmc/core/mmc.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index a5e05ceb554c..d4ed62cab23d 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -640,12 +640,6 @@ out: return err; } -static inline void mmc_free_ext_csd(u8 *ext_csd) -{ - kfree(ext_csd); -} - - static int mmc_compare_ext_csds(struct mmc_card *card, unsigned bus_width) { u8 *bw_ext_csd; @@ -719,7 +713,7 @@ static int mmc_compare_ext_csds(struct mmc_card *card, unsigned bus_width) err = -EINVAL; out: - mmc_free_ext_csd(bw_ext_csd); + kfree(bw_ext_csd); return err; } @@ -1570,14 +1564,14 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, if (!oldcard) host->card = card; - mmc_free_ext_csd(ext_csd); + kfree(ext_csd); return 0; free_card: if (!oldcard) mmc_remove_card(card); err: - mmc_free_ext_csd(ext_csd); + kfree(ext_csd); return err; } -- cgit v1.2.3-59-g8ed1b From fd372f7d7f6c579379bd7d14e4924eba39a5b2dd Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Fri, 17 Oct 2014 11:16:57 +0200 Subject: mmc: core: Remove duplicated definition of mmc_send_ext_csd() mmc_send_ext_csd() is an exported function used by both the mmc core and the mmc block layer. Let's remove the local duplicated definition in the mmc core. Signed-off-by: Ulf Hansson --- drivers/mmc/core/mmc_ops.h | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/mmc/core/mmc_ops.h b/drivers/mmc/core/mmc_ops.h index 390dac665b2a..f752ec67c102 100644 --- a/drivers/mmc/core/mmc_ops.h +++ b/drivers/mmc/core/mmc_ops.h @@ -20,7 +20,6 @@ int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr); int mmc_all_send_cid(struct mmc_host *host, u32 *cid); int mmc_set_relative_addr(struct mmc_card *card); int mmc_send_csd(struct mmc_card *card, u32 *csd); -int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd); int mmc_send_status(struct mmc_card *card, u32 *status); int mmc_send_cid(struct mmc_host *host, u32 *cid); int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp); -- cgit v1.2.3-59-g8ed1b From 56d09b1da7dbe18bdb4e4a74df4a00ab95e6aecd Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Mon, 20 Oct 2014 11:18:41 +0200 Subject: mmc: core: Remove redundant check while selecting powerclass The validation of the buswidth and the MMC spec version in __mmc_select_powerclass() is redundant, let's remove it. Signed-off-by: Ulf Hansson --- drivers/mmc/core/mmc.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index d4ed62cab23d..c0f21eb56eec 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -793,14 +793,6 @@ static int __mmc_select_powerclass(struct mmc_card *card, unsigned int pwrclass_val = 0; int err = 0; - /* Power class selection is supported for versions >= 4.0 */ - if (card->csd.mmca_vsn < CSD_SPEC_VER_4) - return 0; - - /* Power class values are defined only for 4/8 bit bus */ - if (bus_width == EXT_CSD_BUS_WIDTH_1) - return 0; - switch (1 << host->ios.vdd) { case MMC_VDD_165_195: if (host->ios.clock <= MMC_HIGH_26_MAX_DTR) -- cgit v1.2.3-59-g8ed1b From 9e304d67ad4768585e4c7002341aac81272799ec Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Mon, 20 Oct 2014 11:49:21 +0200 Subject: mmc: core: Remove redundant check of max_dtr while selecting timings If the MMC spec version is < CSD_SPEC_VER_4, there aren't support for the EXT_CSD register. Since max_dtr is fetched from there, it will default to zero, which thus isn't needed to verify. Signed-off-by: Ulf Hansson --- drivers/mmc/core/mmc.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index c0f21eb56eec..cc9f4599f3e1 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -1157,8 +1157,7 @@ static int mmc_select_timing(struct mmc_card *card) { int err = 0; - if ((card->csd.mmca_vsn < CSD_SPEC_VER_4 && - card->ext_csd.hs_max_dtr == 0)) + if (card->csd.mmca_vsn < CSD_SPEC_VER_4) goto bus_speed; if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200) -- cgit v1.2.3-59-g8ed1b From a1fc444e83de05ebbb6269029c9888b8f8b11490 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Tue, 21 Oct 2014 17:16:14 +0200 Subject: mmc: core: Remove unnecessary 'out of memory' message Rely on the prints handled internally by kmalloc(). Signed-off-by: Ulf Hansson --- drivers/mmc/core/mmc.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index cc9f4599f3e1..5226ef8c0c2d 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -198,11 +198,8 @@ static int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd) * raw block in mmc_card. */ ext_csd = kmalloc(512, GFP_KERNEL); - if (!ext_csd) { - pr_err("%s: could not allocate a buffer to " - "receive the ext_csd.\n", mmc_hostname(card->host)); + if (!ext_csd) return -ENOMEM; - } err = mmc_send_ext_csd(card, ext_csd); if (err) { -- cgit v1.2.3-59-g8ed1b From 148bcab28f51c80f13e5ad678fe840e8a34af46f Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Mon, 20 Oct 2014 11:33:53 +0200 Subject: mmc: core: Add helper function for EXT_CSD support The helper function mmc_can_ext_csd() will return a positive value if the card supports the EXT_CSD register. Start using it at relavant places in the mmc core. Signed-off-by: Ulf Hansson --- drivers/mmc/core/mmc.c | 8 ++++---- drivers/mmc/core/mmc_ops.c | 5 +++++ drivers/mmc/core/mmc_ops.h | 1 + 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 5226ef8c0c2d..7c257c93ecd7 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -190,7 +190,7 @@ static int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd) *new_ext_csd = NULL; - if (card->csd.mmca_vsn < CSD_SPEC_VER_4) + if (!mmc_can_ext_csd(card)) return 0; /* @@ -852,7 +852,7 @@ static int mmc_select_powerclass(struct mmc_card *card) int err, ddr; /* Power class selection is supported for versions >= 4.0 */ - if (card->csd.mmca_vsn < CSD_SPEC_VER_4) + if (!mmc_can_ext_csd(card)) return 0; bus_width = host->ios.bus_width; @@ -913,7 +913,7 @@ static int mmc_select_bus_width(struct mmc_card *card) unsigned idx, bus_width = 0; int err = 0; - if ((card->csd.mmca_vsn < CSD_SPEC_VER_4) && + if (!mmc_can_ext_csd(card) && !(host->caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA))) return 0; @@ -1154,7 +1154,7 @@ static int mmc_select_timing(struct mmc_card *card) { int err = 0; - if (card->csd.mmca_vsn < CSD_SPEC_VER_4) + if (!mmc_can_ext_csd(card)) goto bus_speed; if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200) diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c index 7911e0510a1d..1db60be43c37 100644 --- a/drivers/mmc/core/mmc_ops.c +++ b/drivers/mmc/core/mmc_ops.c @@ -675,3 +675,8 @@ int mmc_send_hpi_cmd(struct mmc_card *card, u32 *status) return 0; } + +int mmc_can_ext_csd(struct mmc_card *card) +{ + return (card && card->csd.mmca_vsn > CSD_SPEC_VER_3); +} diff --git a/drivers/mmc/core/mmc_ops.h b/drivers/mmc/core/mmc_ops.h index f752ec67c102..6f4b00ed93de 100644 --- a/drivers/mmc/core/mmc_ops.h +++ b/drivers/mmc/core/mmc_ops.h @@ -26,6 +26,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); int mmc_bus_test(struct mmc_card *card, u8 bus_width); int mmc_send_hpi_cmd(struct mmc_card *card, u32 *status); +int mmc_can_ext_csd(struct mmc_card *card); #endif -- cgit v1.2.3-59-g8ed1b From 076ec38a58584dc85c837bd52b4ec3d9cd02b393 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Mon, 20 Oct 2014 13:37:24 +0200 Subject: mmc: core: Fetch and decode EXT_CSD from mmc_read_ext_csd() As a step in cleaning up code around reading/decoding EXT_CSD, convert the current mmc_read_ext_csd(), to handle both fetching the EXT_CSD and decoding its data. Signed-off-by: Ulf Hansson --- drivers/mmc/core/mmc.c | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 7c257c93ecd7..13f8e3672606 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -388,7 +388,7 @@ static void mmc_manage_gp_partitions(struct mmc_card *card, u8 *ext_csd) /* * Decode extended CSD. */ -static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) +static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd) { int err = 0, idx; unsigned int part_size; @@ -637,6 +637,20 @@ out: return err; } +static int mmc_read_ext_csd(struct mmc_card *card) +{ + u8 *ext_csd = NULL; + int err; + + err = mmc_get_ext_csd(card, &ext_csd); + if (err) + return err; + + err = mmc_decode_ext_csd(card, ext_csd); + kfree(ext_csd); + return err; +} + static int mmc_compare_ext_csds(struct mmc_card *card, unsigned bus_width) { u8 *bw_ext_csd; @@ -1259,7 +1273,6 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, int err; u32 cid[4]; u32 rocr; - u8 *ext_csd = NULL; BUG_ON(!host); WARN_ON(!host->claimed); @@ -1368,14 +1381,8 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, } if (!oldcard) { - /* - * Fetch and process extended CSD. - */ - - err = mmc_get_ext_csd(card, &ext_csd); - if (err) - goto free_card; - err = mmc_read_ext_csd(card, ext_csd); + /* Read extended CSD. */ + err = mmc_read_ext_csd(card); if (err) goto free_card; @@ -1552,15 +1559,12 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, if (!oldcard) host->card = card; - kfree(ext_csd); return 0; free_card: if (!oldcard) mmc_remove_card(card); err: - kfree(ext_csd); - return err; } -- cgit v1.2.3-59-g8ed1b From c197787ced5b42bde224d9ee70473d87a824119a Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Mon, 20 Oct 2014 14:08:16 +0200 Subject: mmc: core: Let's callers of from mmc_get_ext_csd() do error handling The callers of mmc_get_ext_csd() need the flexibility to handle errors themselves, because they behave differently. Let's clean up mmc_get_ext_csd() with its friends and adopt the error handling as stated above. Signed-off-by: Ulf Hansson --- drivers/mmc/core/mmc.c | 70 ++++++++++++++++++++++---------------------------- 1 file changed, 31 insertions(+), 39 deletions(-) diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 13f8e3672606..fe801e612b1f 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -188,10 +188,8 @@ static int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd) BUG_ON(!card); BUG_ON(!new_ext_csd); - *new_ext_csd = NULL; - if (!mmc_can_ext_csd(card)) - return 0; + return -EOPNOTSUPP; /* * As the ext_csd is so large and mostly unused, we don't store the @@ -202,32 +200,9 @@ static int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd) return -ENOMEM; err = mmc_send_ext_csd(card, ext_csd); - if (err) { + if (err) kfree(ext_csd); - *new_ext_csd = NULL; - - /* If the host or the card can't do the switch, - * fail more gracefully. */ - if ((err != -EINVAL) - && (err != -ENOSYS) - && (err != -EFAULT)) - return err; - - /* - * High capacity cards should have this "magic" size - * stored in their CSD. - */ - if (card->csd.capacity == (4096 * 512)) { - pr_err("%s: unable to read EXT_CSD " - "on a possible high capacity card. " - "Card will be ignored.\n", - mmc_hostname(card->host)); - } else { - pr_warn("%s: unable to read EXT_CSD, performance might suffer\n", - mmc_hostname(card->host)); - err = 0; - } - } else + else *new_ext_csd = ext_csd; return err; @@ -395,9 +370,6 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd) BUG_ON(!card); - if (!ext_csd) - return 0; - /* Version is coded in the CSD_STRUCTURE byte in the EXT_CSD register */ card->ext_csd.raw_ext_csd_structure = ext_csd[EXT_CSD_STRUCTURE]; if (card->csd.structure == 3) { @@ -639,12 +611,36 @@ out: static int mmc_read_ext_csd(struct mmc_card *card) { - u8 *ext_csd = NULL; + u8 *ext_csd; int err; + if (!mmc_can_ext_csd(card)) + return 0; + err = mmc_get_ext_csd(card, &ext_csd); - if (err) + if (err) { + /* If the host or the card can't do the switch, + * fail more gracefully. */ + if ((err != -EINVAL) + && (err != -ENOSYS) + && (err != -EFAULT)) + return err; + + /* + * High capacity cards should have this "magic" size + * stored in their CSD. + */ + if (card->csd.capacity == (4096 * 512)) { + pr_err("%s: unable to read EXT_CSD on a possible high capacity card. Card will be ignored.\n", + mmc_hostname(card->host)); + } else { + pr_warn("%s: unable to read EXT_CSD, performance might suffer\n", + mmc_hostname(card->host)); + err = 0; + } + return err; + } err = mmc_decode_ext_csd(card, ext_csd); kfree(ext_csd); @@ -660,11 +656,8 @@ static int mmc_compare_ext_csds(struct mmc_card *card, unsigned bus_width) return 0; err = mmc_get_ext_csd(card, &bw_ext_csd); - - if (err || bw_ext_csd == NULL) { - err = -EINVAL; - goto out; - } + if (err) + return err; /* only compare read only fields */ err = !((card->ext_csd.raw_partition_support == @@ -723,7 +716,6 @@ static int mmc_compare_ext_csds(struct mmc_card *card, unsigned bus_width) if (err) err = -EINVAL; -out: kfree(bw_ext_csd); return err; } -- cgit v1.2.3-59-g8ed1b From 2fd322a58ed17b9159aa369e7c9ea01eb6a5d5ae Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Thu, 16 Oct 2014 17:00:39 +0200 Subject: mmc: core: Don't panic when fetching EXT_CSD Instead of doing BUG_ON(), return an error code. Signed-off-by: Ulf Hansson --- drivers/mmc/core/mmc.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index fe801e612b1f..efaa9f8f07b0 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -185,8 +185,8 @@ static int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd) int err; u8 *ext_csd; - BUG_ON(!card); - BUG_ON(!new_ext_csd); + if (!card || !new_ext_csd) + return -EINVAL; if (!mmc_can_ext_csd(card)) return -EOPNOTSUPP; @@ -368,8 +368,6 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd) int err = 0, idx; unsigned int part_size; - BUG_ON(!card); - /* Version is coded in the CSD_STRUCTURE byte in the EXT_CSD register */ card->ext_csd.raw_ext_csd_structure = ext_csd[EXT_CSD_STRUCTURE]; if (card->csd.structure == 3) { -- cgit v1.2.3-59-g8ed1b From e21aa519ee3667d0fabda5d806cc68826e9899e0 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Fri, 17 Oct 2014 11:32:32 +0200 Subject: mmc: core: Export mmc_get_ext_csd() Callers of mmc_send_ext_csd() will be able to decrease code duplication by using mmc_get_ext_csd() instead. Let's make it available. Signed-off-by: Ulf Hansson --- drivers/mmc/core/mmc.c | 31 ------------------------------- drivers/mmc/core/mmc_ops.c | 29 +++++++++++++++++++++++++++++ include/linux/mmc/core.h | 1 + 3 files changed, 30 insertions(+), 31 deletions(-) diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index efaa9f8f07b0..02ad79229f65 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -177,37 +177,6 @@ static int mmc_decode_csd(struct mmc_card *card) return 0; } -/* - * Read extended CSD. - */ -static int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd) -{ - int err; - u8 *ext_csd; - - if (!card || !new_ext_csd) - return -EINVAL; - - if (!mmc_can_ext_csd(card)) - return -EOPNOTSUPP; - - /* - * As the ext_csd is so large and mostly unused, we don't store the - * raw block in mmc_card. - */ - ext_csd = kmalloc(512, GFP_KERNEL); - if (!ext_csd) - return -ENOMEM; - - err = mmc_send_ext_csd(card, ext_csd); - if (err) - kfree(ext_csd); - else - *new_ext_csd = ext_csd; - - return err; -} - static void mmc_select_card_type(struct mmc_card *card) { struct mmc_host *host = card->host; diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c index 1db60be43c37..72e1f9b3ed0d 100644 --- a/drivers/mmc/core/mmc_ops.c +++ b/drivers/mmc/core/mmc_ops.c @@ -385,6 +385,35 @@ int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd) } EXPORT_SYMBOL_GPL(mmc_send_ext_csd); +int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd) +{ + int err; + u8 *ext_csd; + + if (!card || !new_ext_csd) + return -EINVAL; + + if (!mmc_can_ext_csd(card)) + return -EOPNOTSUPP; + + /* + * As the ext_csd is so large and mostly unused, we don't store the + * raw block in mmc_card. + */ + ext_csd = kmalloc(512, GFP_KERNEL); + if (!ext_csd) + return -ENOMEM; + + err = mmc_send_ext_csd(card, ext_csd); + if (err) + kfree(ext_csd); + else + *new_ext_csd = ext_csd; + + return err; +} +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}; diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h index f206e29f94d7..0a77d3567c27 100644 --- a/include/linux/mmc/core.h +++ b/include/linux/mmc/core.h @@ -155,6 +155,7 @@ extern int __mmc_switch(struct mmc_card *, u8, u8, u8, unsigned int, bool, bool, bool); extern int mmc_switch(struct mmc_card *, u8, u8, u8, unsigned int); extern int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd); +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 -- cgit v1.2.3-59-g8ed1b From 86817ffb492b509b87b20be4a4f1afc74f04dccf Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Fri, 17 Oct 2014 11:39:05 +0200 Subject: mmc: block: Use mmc_get_ext_csd() instead of mmc_send_ext_csd() By using mmc_get_ext_csd() in favor of mmc_send_ext_csd, we decrease code duplication. Signed-off-by: Ulf Hansson --- drivers/mmc/card/block.c | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index f45f7e3870be..0c41ee043e36 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -1309,19 +1309,11 @@ static int mmc_blk_packed_err_check(struct mmc_card *card, } if (status & R1_EXCEPTION_EVENT) { - ext_csd = kzalloc(512, GFP_KERNEL); - if (!ext_csd) { - pr_err("%s: unable to allocate buffer for ext_csd\n", - req->rq_disk->disk_name); - return -ENOMEM; - } - - err = mmc_send_ext_csd(card, ext_csd); + err = mmc_get_ext_csd(card, &ext_csd); if (err) { pr_err("%s: error %d sending ext_csd\n", req->rq_disk->disk_name, err); - check = MMC_BLK_ABORT; - goto free; + return MMC_BLK_ABORT; } if ((ext_csd[EXT_CSD_EXP_EVENTS_STATUS] & @@ -1339,7 +1331,6 @@ static int mmc_blk_packed_err_check(struct mmc_card *card, req->rq_disk->disk_name, packed->nr_entries, packed->blocks, packed->idx_failure); } -free: kfree(ext_csd); } -- cgit v1.2.3-59-g8ed1b From b2cada73a8ff2ee9129557c724f7e53bf55e48f8 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Fri, 17 Oct 2014 11:48:23 +0200 Subject: mmc: core: Use mmc_get_ext_csd() instead of mmc_send_ext_csd() By using mmc_get_ext_csd() in favor of mmc_send_ext_csd, we decrease code duplication. Signed-off-by: Ulf Hansson --- drivers/mmc/core/core.c | 17 +++-------------- drivers/mmc/core/debugfs.c | 9 +-------- 2 files changed, 4 insertions(+), 22 deletions(-) diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 953f17c5fcde..943f9051ec6d 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -731,27 +731,16 @@ int mmc_read_bkops_status(struct mmc_card *card) int err; u8 *ext_csd; - /* - * In future work, we should consider storing the entire ext_csd. - */ - ext_csd = kmalloc(512, GFP_KERNEL); - if (!ext_csd) { - pr_err("%s: could not allocate buffer to receive the ext_csd.\n", - mmc_hostname(card->host)); - return -ENOMEM; - } - mmc_claim_host(card->host); - err = mmc_send_ext_csd(card, ext_csd); + err = mmc_get_ext_csd(card, &ext_csd); mmc_release_host(card->host); if (err) - goto out; + return err; card->ext_csd.raw_bkops_status = ext_csd[EXT_CSD_BKOPS_STATUS]; card->ext_csd.raw_exception_status = ext_csd[EXT_CSD_EXP_EVENTS_STATUS]; -out: kfree(ext_csd); - return err; + return 0; } EXPORT_SYMBOL(mmc_read_bkops_status); diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c index 91eb16223246..e9142108a6c6 100644 --- a/drivers/mmc/core/debugfs.c +++ b/drivers/mmc/core/debugfs.c @@ -291,14 +291,8 @@ static int mmc_ext_csd_open(struct inode *inode, struct file *filp) if (!buf) return -ENOMEM; - ext_csd = kmalloc(512, GFP_KERNEL); - if (!ext_csd) { - err = -ENOMEM; - goto out_free; - } - mmc_get_card(card); - err = mmc_send_ext_csd(card, ext_csd); + err = mmc_get_ext_csd(card, &ext_csd); mmc_put_card(card); if (err) goto out_free; @@ -314,7 +308,6 @@ static int mmc_ext_csd_open(struct inode *inode, struct file *filp) out_free: kfree(buf); - kfree(ext_csd); return err; } -- cgit v1.2.3-59-g8ed1b From 2fc91e8b0e1cd89094677d1c9dfba1b26979e48b Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Fri, 17 Oct 2014 11:54:22 +0200 Subject: mmc: core: Remove the redundant mmc_send_ext_csd() API Previous patches has replaced the calls to mmc_send_ext_csd() into mmc_get_ext_csd(), thus mmc_send_ext_csd() has become redundant. Let's remove it. Signed-off-by: Ulf Hansson --- drivers/mmc/core/mmc_ops.c | 10 ++-------- include/linux/mmc/core.h | 1 - 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c index 72e1f9b3ed0d..9a6181bf0c06 100644 --- a/drivers/mmc/core/mmc_ops.c +++ b/drivers/mmc/core/mmc_ops.c @@ -378,13 +378,6 @@ err: return ret; } -int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd) -{ - return mmc_send_cxd_data(card, card->host, MMC_SEND_EXT_CSD, - ext_csd, 512); -} -EXPORT_SYMBOL_GPL(mmc_send_ext_csd); - int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd) { int err; @@ -404,7 +397,8 @@ int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd) if (!ext_csd) return -ENOMEM; - err = mmc_send_ext_csd(card, ext_csd); + err = mmc_send_cxd_data(card, card->host, MMC_SEND_EXT_CSD, ext_csd, + 512); if (err) kfree(ext_csd); else diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h index 0a77d3567c27..b11e43c10631 100644 --- a/include/linux/mmc/core.h +++ b/include/linux/mmc/core.h @@ -154,7 +154,6 @@ extern void mmc_start_bkops(struct mmc_card *card, bool from_exception); extern int __mmc_switch(struct mmc_card *, u8, u8, u8, unsigned int, bool, bool, bool); extern int mmc_switch(struct mmc_card *, u8, u8, u8, unsigned int); -extern int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd); extern int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd); #define MMC_ERASE_ARG 0x00000000 -- cgit v1.2.3-59-g8ed1b From 601ed60cef722d1fcdbf46e5b63a7892585abf7b Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Fri, 17 Oct 2014 11:58:24 +0200 Subject: mmc: core: Don't handle buffers on stack while fetching CXD registers Due to previous patches, all callers of mmc_send_cxd_data() now allocates their buffers from the heap. This enables us to simplify mmc_send_cxd_data() by removing the support of handling buffers, which are allocated from the stack. Signed-off-by: Ulf Hansson --- drivers/mmc/core/mmc_ops.c | 21 +-------------------- 1 file changed, 1 insertion(+), 20 deletions(-) diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c index 9a6181bf0c06..e04008f6fc24 100644 --- a/drivers/mmc/core/mmc_ops.c +++ b/drivers/mmc/core/mmc_ops.c @@ -264,20 +264,6 @@ mmc_send_cxd_data(struct mmc_card *card, struct mmc_host *host, struct mmc_command cmd = {0}; struct mmc_data data = {0}; struct scatterlist sg; - void *data_buf; - int is_on_stack; - - is_on_stack = object_is_on_stack(buf); - if (is_on_stack) { - /* - * dma onto stack is unsafe/nonportable, but callers to this - * routine normally provide temporary on-stack buffers ... - */ - data_buf = kmalloc(len, GFP_KERNEL); - if (!data_buf) - return -ENOMEM; - } else - data_buf = buf; mrq.cmd = &cmd; mrq.data = &data; @@ -298,7 +284,7 @@ mmc_send_cxd_data(struct mmc_card *card, struct mmc_host *host, data.sg = &sg; data.sg_len = 1; - sg_init_one(&sg, data_buf, len); + sg_init_one(&sg, buf, len); if (opcode == MMC_SEND_CSD || opcode == MMC_SEND_CID) { /* @@ -312,11 +298,6 @@ mmc_send_cxd_data(struct mmc_card *card, struct mmc_host *host, mmc_wait_for_req(host, &mrq); - if (is_on_stack) { - memcpy(buf, data_buf, len); - kfree(data_buf); - } - if (cmd.error) return cmd.error; if (data.error) -- cgit v1.2.3-59-g8ed1b From 22b787007faed44456414f7ed88331e39f0df387 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Fri, 17 Oct 2014 12:00:56 +0200 Subject: mmc: core: Convert to use kzalloc() for CXD register buffers While allocating buffers for CXD data, let's use kzalloc() to make sure those are zeroed. Signed-off-by: Ulf Hansson --- drivers/mmc/core/mmc_ops.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c index e04008f6fc24..23aa3a380f27 100644 --- a/drivers/mmc/core/mmc_ops.c +++ b/drivers/mmc/core/mmc_ops.c @@ -315,7 +315,7 @@ int mmc_send_csd(struct mmc_card *card, u32 *csd) return mmc_send_cxd_native(card->host, card->rca << 16, csd, MMC_SEND_CSD); - csd_tmp = kmalloc(16, GFP_KERNEL); + csd_tmp = kzalloc(16, GFP_KERNEL); if (!csd_tmp) return -ENOMEM; @@ -343,7 +343,7 @@ int mmc_send_cid(struct mmc_host *host, u32 *cid) cid, MMC_SEND_CID); } - cid_tmp = kmalloc(16, GFP_KERNEL); + cid_tmp = kzalloc(16, GFP_KERNEL); if (!cid_tmp) return -ENOMEM; @@ -374,7 +374,7 @@ int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd) * As the ext_csd is so large and mostly unused, we don't store the * raw block in mmc_card. */ - ext_csd = kmalloc(512, GFP_KERNEL); + ext_csd = kzalloc(512, GFP_KERNEL); if (!ext_csd) return -ENOMEM; -- cgit v1.2.3-59-g8ed1b From b1df9de75cd5d53f715894bcd428da450ca0b66a Mon Sep 17 00:00:00 2001 From: Mike Looijmans Date: Tue, 28 Oct 2014 08:53:21 +0100 Subject: mmc: sdhci-of-arasan: Omit superfluous error messages sdhci_add_host and sdhci_platfm_init already report failure, so don't emit error messages when a failure occurs. This prevents occurences of "deferred" messages when required power supplies are not ready for operation yet. Signed-off-by: Mike Looijmans Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-of-arasan.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/mmc/host/sdhci-of-arasan.c b/drivers/mmc/host/sdhci-of-arasan.c index 5f10c22ea3aa..bcb51e9dfdcd 100644 --- a/drivers/mmc/host/sdhci-of-arasan.c +++ b/drivers/mmc/host/sdhci-of-arasan.c @@ -165,7 +165,6 @@ static int sdhci_arasan_probe(struct platform_device *pdev) host = sdhci_pltfm_init(pdev, &sdhci_arasan_pdata, 0); if (IS_ERR(host)) { ret = PTR_ERR(host); - dev_err(&pdev->dev, "platform init failed (%d)\n", ret); goto clk_disable_all; } @@ -175,10 +174,8 @@ static int sdhci_arasan_probe(struct platform_device *pdev) pltfm_host->clk = clk_xin; ret = sdhci_add_host(host); - if (ret) { - dev_err(&pdev->dev, "platform register failed (%d)\n", ret); + if (ret) goto err_pltfm_free; - } return 0; -- cgit v1.2.3-59-g8ed1b From 8c96a7a3310a21a4a3f827b9c42636aa04a47f9e Mon Sep 17 00:00:00 2001 From: Sebastian Hesselbarth Date: Tue, 21 Oct 2014 11:22:38 +0200 Subject: mmc: sdhci-pxav3: Move I/O clock to private data As we are using references to the I/O clock throughout the driver, move it to the private data. Also, in preparation for core clock, rename it to clk_io. Signed-off-by: Sebastian Hesselbarth Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-pxav3.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/drivers/mmc/host/sdhci-pxav3.c b/drivers/mmc/host/sdhci-pxav3.c index e52bbbb09d88..a34a589670e6 100644 --- a/drivers/mmc/host/sdhci-pxav3.c +++ b/drivers/mmc/host/sdhci-pxav3.c @@ -59,6 +59,7 @@ #define SDCE_MISC_INT_EN (1<<1) struct sdhci_pxa { + struct clk *clk_io; u8 power_mode; }; @@ -288,9 +289,7 @@ static int sdhci_pxav3_probe(struct platform_device *pdev) struct sdhci_host *host = NULL; struct sdhci_pxa *pxa = NULL; const struct of_device_id *match; - int ret; - struct clk *clk; pxa = devm_kzalloc(&pdev->dev, sizeof(struct sdhci_pxa), GFP_KERNEL); if (!pxa) @@ -310,14 +309,14 @@ static int sdhci_pxav3_probe(struct platform_device *pdev) pltfm_host = sdhci_priv(host); pltfm_host->priv = pxa; - clk = devm_clk_get(dev, NULL); - if (IS_ERR(clk)) { + pxa->clk_io = devm_clk_get(dev, NULL); + if (IS_ERR(pxa->clk_io)) { dev_err(dev, "failed to get io clock\n"); - ret = PTR_ERR(clk); + ret = PTR_ERR(pxa->clk_io); goto err_clk_get; } - pltfm_host->clk = clk; - clk_prepare_enable(clk); + pltfm_host->clk = pxa->clk_io; + clk_prepare_enable(pxa->clk_io); /* enable 1/8V DDR capable */ host->mmc->caps |= MMC_CAP_1_8V_DDR; @@ -390,7 +389,7 @@ err_add_host: pm_runtime_disable(&pdev->dev); err_of_parse: err_cd_req: - clk_disable_unprepare(clk); + clk_disable_unprepare(pxa->clk_io); err_clk_get: err_mbus_win: sdhci_pltfm_free(pdev); @@ -401,12 +400,13 @@ static int sdhci_pxav3_remove(struct platform_device *pdev) { struct sdhci_host *host = platform_get_drvdata(pdev); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_pxa *pxa = pltfm_host->priv; pm_runtime_get_sync(&pdev->dev); sdhci_remove_host(host, 1); pm_runtime_disable(&pdev->dev); - clk_disable_unprepare(pltfm_host->clk); + clk_disable_unprepare(pxa->clk_io); sdhci_pltfm_free(pdev); @@ -446,13 +446,14 @@ static int sdhci_pxav3_runtime_suspend(struct device *dev) { struct sdhci_host *host = dev_get_drvdata(dev); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_pxa *pxa = pltfm_host->priv; unsigned long flags; spin_lock_irqsave(&host->lock, flags); host->runtime_suspended = true; spin_unlock_irqrestore(&host->lock, flags); - clk_disable_unprepare(pltfm_host->clk); + clk_disable_unprepare(pxa->clk_io); return 0; } @@ -461,9 +462,10 @@ static int sdhci_pxav3_runtime_resume(struct device *dev) { struct sdhci_host *host = dev_get_drvdata(dev); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_pxa *pxa = pltfm_host->priv; unsigned long flags; - clk_prepare_enable(pltfm_host->clk); + clk_prepare_enable(pxa->clk_io); spin_lock_irqsave(&host->lock, flags); host->runtime_suspended = false; -- cgit v1.2.3-59-g8ed1b From 01ae1070cbb5fbb3bffa0df44e422521df2b4ab1 Mon Sep 17 00:00:00 2001 From: Sebastian Hesselbarth Date: Tue, 21 Oct 2014 11:22:39 +0200 Subject: mmc: sdhci-pxav3: Try to get named I/O clock first With support for more than one clock, we'll need to distinguish between the clock by name. Change clock probing to first try to get "io" clock before falling back to unnamed clock. Signed-off-by: Sebastian Hesselbarth Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-pxav3.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/host/sdhci-pxav3.c b/drivers/mmc/host/sdhci-pxav3.c index a34a589670e6..3dfd97977515 100644 --- a/drivers/mmc/host/sdhci-pxav3.c +++ b/drivers/mmc/host/sdhci-pxav3.c @@ -309,7 +309,9 @@ static int sdhci_pxav3_probe(struct platform_device *pdev) pltfm_host = sdhci_priv(host); pltfm_host->priv = pxa; - pxa->clk_io = devm_clk_get(dev, NULL); + pxa->clk_io = devm_clk_get(dev, "io"); + if (IS_ERR(pxa->clk_io)) + pxa->clk_io = devm_clk_get(dev, NULL); if (IS_ERR(pxa->clk_io)) { dev_err(dev, "failed to get io clock\n"); ret = PTR_ERR(pxa->clk_io); -- cgit v1.2.3-59-g8ed1b From 8afdc9cca27fc299ffe7b535b299adc03efab851 Mon Sep 17 00:00:00 2001 From: Sebastian Hesselbarth Date: Tue, 21 Oct 2014 11:22:40 +0200 Subject: mmc: sdhci-pxav3: Get optional core clock Besides the I/O clock, some PXAv3 SDHCI IP also requires a core clock to be enabled. Add an optional core clock to the corresponding driver. Signed-off-by: Sebastian Hesselbarth Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-pxav3.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/mmc/host/sdhci-pxav3.c b/drivers/mmc/host/sdhci-pxav3.c index 3dfd97977515..ad0badad0ebc 100644 --- a/drivers/mmc/host/sdhci-pxav3.c +++ b/drivers/mmc/host/sdhci-pxav3.c @@ -59,6 +59,7 @@ #define SDCE_MISC_INT_EN (1<<1) struct sdhci_pxa { + struct clk *clk_core; struct clk *clk_io; u8 power_mode; }; @@ -320,6 +321,10 @@ static int sdhci_pxav3_probe(struct platform_device *pdev) pltfm_host->clk = pxa->clk_io; clk_prepare_enable(pxa->clk_io); + pxa->clk_core = devm_clk_get(dev, "core"); + if (!IS_ERR(pxa->clk_core)) + clk_prepare_enable(pxa->clk_core); + /* enable 1/8V DDR capable */ host->mmc->caps |= MMC_CAP_1_8V_DDR; @@ -392,6 +397,8 @@ err_add_host: err_of_parse: err_cd_req: clk_disable_unprepare(pxa->clk_io); + if (!IS_ERR(pxa->clk_core)) + clk_disable_unprepare(pxa->clk_core); err_clk_get: err_mbus_win: sdhci_pltfm_free(pdev); @@ -409,6 +416,8 @@ static int sdhci_pxav3_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); clk_disable_unprepare(pxa->clk_io); + if (!IS_ERR(pxa->clk_core)) + clk_disable_unprepare(pxa->clk_core); sdhci_pltfm_free(pdev); @@ -456,6 +465,8 @@ static int sdhci_pxav3_runtime_suspend(struct device *dev) spin_unlock_irqrestore(&host->lock, flags); clk_disable_unprepare(pxa->clk_io); + if (!IS_ERR(pxa->clk_core)) + clk_disable_unprepare(pxa->clk_core); return 0; } @@ -468,6 +479,8 @@ static int sdhci_pxav3_runtime_resume(struct device *dev) unsigned long flags; clk_prepare_enable(pxa->clk_io); + if (!IS_ERR(pxa->clk_core)) + clk_prepare_enable(pxa->clk_core); spin_lock_irqsave(&host->lock, flags); host->runtime_suspended = false; -- cgit v1.2.3-59-g8ed1b From 0654bb3cdd5142ca8bf27a4f72bf22098394fbd5 Mon Sep 17 00:00:00 2001 From: Sebastian Hesselbarth Date: Tue, 21 Oct 2014 11:22:41 +0200 Subject: mmc: sdhci-pxav3: Document clocks and additional clock-names property Now that sdhci-pxav3 driver allows to have more than one IP clock defined, document both clocks and clock-names properties. Signed-off-by: Sebastian Hesselbarth Signed-off-by: Ulf Hansson --- Documentation/devicetree/bindings/mmc/sdhci-pxa.txt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Documentation/devicetree/bindings/mmc/sdhci-pxa.txt b/Documentation/devicetree/bindings/mmc/sdhci-pxa.txt index 86223c3eda90..4dd6deb90719 100644 --- a/Documentation/devicetree/bindings/mmc/sdhci-pxa.txt +++ b/Documentation/devicetree/bindings/mmc/sdhci-pxa.txt @@ -12,6 +12,10 @@ Required properties: * for "marvell,armada-380-sdhci", two register areas. The first one for the SDHCI registers themselves, and the second one for the AXI/Mbus bridge registers of the SDHCI unit. +- clocks: Array of clocks required for SDHCI; requires at least one for + I/O clock. +- clock-names: Array of names corresponding to clocks property; shall be + "io" for I/O clock and "core" for optional core clock. Optional properties: - mrvl,clk-delay-cycles: Specify a number of cycles to delay for tuning. @@ -23,6 +27,8 @@ sdhci@d4280800 { reg = <0xd4280800 0x800>; bus-width = <8>; interrupts = <27>; + clocks = <&chip CLKID_SDIO1XIN>, <&chip CLKID_SDIO1>; + clock-names = "io", "core"; non-removable; mrvl,clk-delay-cycles = <31>; }; @@ -32,5 +38,6 @@ sdhci@d8000 { reg = <0xd8000 0x1000>, <0xdc000 0x100>; interrupts = <0 25 0x4>; clocks = <&gateclk 17>; + clock-names = "io"; mrvl,clk-delay-cycles = <0x1F>; }; -- cgit v1.2.3-59-g8ed1b From 76d5556428fbbdf411504895b516272cad27127d Mon Sep 17 00:00:00 2001 From: Timo Kokkonen Date: Mon, 3 Nov 2014 13:12:59 +0200 Subject: mmc: host: atmel-mci: Add support for non-removable slots Add support for non-removable slots which have no card detection GPIO and which should not be polled for a card change. Signed-off-by: Timo Kokkonen Acked-by: Ludovic Desroches Signed-off-by: Ulf Hansson --- drivers/mmc/host/atmel-mci.c | 11 +++++++++-- include/linux/atmel-mci.h | 2 ++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c index 0b9ddf8aed04..d9646e5ae2c8 100644 --- a/drivers/mmc/host/atmel-mci.c +++ b/drivers/mmc/host/atmel-mci.c @@ -560,6 +560,9 @@ atmci_of_init(struct platform_device *pdev) pdata->slot[slot_id].detect_is_active_high = of_property_read_bool(cnp, "cd-inverted"); + pdata->slot[slot_id].non_removable = + of_property_read_bool(cnp, "non-removable"); + pdata->slot[slot_id].wp_pin = of_get_named_gpio(cnp, "wp-gpios", 0); } @@ -2206,8 +2209,12 @@ static int __init atmci_init_slot(struct atmel_mci *host, } } - if (!gpio_is_valid(slot->detect_pin)) - mmc->caps |= MMC_CAP_NEEDS_POLL; + if (!gpio_is_valid(slot->detect_pin)) { + if (slot_data->non_removable) + mmc->caps |= MMC_CAP_NONREMOVABLE; + else + mmc->caps |= MMC_CAP_NEEDS_POLL; + } if (gpio_is_valid(slot->wp_pin)) { if (devm_gpio_request(&host->pdev->dev, slot->wp_pin, diff --git a/include/linux/atmel-mci.h b/include/linux/atmel-mci.h index 91b77f8d495d..9177947bf032 100644 --- a/include/linux/atmel-mci.h +++ b/include/linux/atmel-mci.h @@ -11,6 +11,7 @@ * @detect_pin: GPIO pin wired to the card detect switch * @wp_pin: GPIO pin wired to the write protect sensor * @detect_is_active_high: The state of the detect pin when it is active + * @non_removable: The slot is not removable, only detect once * * If a given slot is not present on the board, @bus_width should be * set to 0. The other fields are ignored in this case. @@ -26,6 +27,7 @@ struct mci_slot_pdata { int detect_pin; int wp_pin; bool detect_is_active_high; + bool non_removable; }; /** -- cgit v1.2.3-59-g8ed1b From c09df940ebe0167dcf13d52ea122c99b9bb8365a Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Tue, 4 Nov 2014 12:42:35 +0200 Subject: mmc: sdhci: Fix incorrect ADMA2 descriptor table size The ADMA2 descriptor table size was being calculated incorrectly Fix it. Note that it has been wrong for a long time and likely has not caused any problems because of a combination of 1) not needing alignment descriptors for block operations 2) more memory being allocated than was requested 3) the use of SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC which does not use an extra descriptor for the end marker. Signed-off-by: Adrian Hunter Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 062222abf3df..41c6d3b9766c 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -44,7 +44,13 @@ #define MAX_TUNING_LOOP 40 -#define ADMA_SIZE ((128 * 2 + 1) * 4) +/* + * The ADMA2 descriptor table size is calculated as the maximum number of + * segments (128), times 2 to allow for an alignment descriptor for each + * segment, plus 1 for a nop end descriptor, all multipled by the 32-bit + * descriptor size (8). + */ +#define ADMA_SIZE ((128 * 2 + 1) * 8) static unsigned int debug_quirks = 0; static unsigned int debug_quirks2; -- cgit v1.2.3-59-g8ed1b From 8be78c6ad4d38ae555065b2778205d310300c8b0 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Tue, 4 Nov 2014 12:42:36 +0200 Subject: mmc: sdhci: Fix ADMA page boundary warnings Bytes are being copied from/to a single page. The intent of the warning is to warn if the page boundary is crossed. There are two problems. First, PAGE_MASK is mistaken for (PAGE_SIZE - 1). Secondly, instead of using the number of bytes to copy, the warning is using the maximum that that value could be. Fix both. Signed-off-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 41c6d3b9766c..e7593578d5b2 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -525,7 +525,8 @@ static int sdhci_adma_table_pre(struct sdhci_host *host, if (offset) { if (data->flags & MMC_DATA_WRITE) { buffer = sdhci_kmap_atomic(sg, &flags); - WARN_ON(((long)buffer & PAGE_MASK) > (PAGE_SIZE - 3)); + WARN_ON(((long)buffer & (PAGE_SIZE - 1)) > + (PAGE_SIZE - offset)); memcpy(align, buffer, offset); sdhci_kunmap_atomic(buffer, &flags); } @@ -630,7 +631,8 @@ static void sdhci_adma_table_post(struct sdhci_host *host, size = 4 - (sg_dma_address(sg) & 0x3); buffer = sdhci_kmap_atomic(sg, &flags); - WARN_ON(((long)buffer & PAGE_MASK) > (PAGE_SIZE - 3)); + WARN_ON(((long)buffer & (PAGE_SIZE - 1)) > + (PAGE_SIZE - size)); memcpy(buffer, align, size); sdhci_kunmap_atomic(buffer, &flags); -- cgit v1.2.3-59-g8ed1b From b521cf34bb6b4d38d66176f7cd7337846ac27342 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Tue, 4 Nov 2014 12:42:37 +0200 Subject: mmc: sdhci: Fix ADMA table size warning The intent of the warning is to warn if the ADMA table overflows. However there can be one more 'end' entry so the condition should be adjusted accordingly. Signed-off-by: Adrian Hunter Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index e7593578d5b2..4436f77f5d38 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -555,7 +555,7 @@ static int sdhci_adma_table_pre(struct sdhci_host *host, * If this triggers then we have a calculation bug * somewhere. :/ */ - WARN_ON((desc - host->adma_desc) > ADMA_SIZE); + WARN_ON((desc - host->adma_desc) >= ADMA_SIZE); } if (host->quirks & SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC) { -- cgit v1.2.3-59-g8ed1b From 08621b18a15ee21601ad8133565d283610b493d8 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Tue, 4 Nov 2014 12:42:38 +0200 Subject: mmc: sdhci: Rename two ADMA-related functions for consistency Rename sdhci_set_adma_desc to sdhci_adma_write_desc and sdhci_show_adma_error to sdhci_adma_show_error so that all ADMA functions start with sdhci_adma_. Signed-off-by: Adrian Hunter Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 4436f77f5d38..e40414ab7ef8 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -454,7 +454,7 @@ static void sdhci_kunmap_atomic(void *buffer, unsigned long *flags) local_irq_restore(*flags); } -static void sdhci_set_adma_desc(u8 *desc, u32 addr, int len, unsigned cmd) +static void sdhci_adma_write_desc(u8 *desc, u32 addr, int len, unsigned cmd) { __le32 *dataddr = (__le32 __force *)(desc + 4); __le16 *cmdlen = (__le16 __force *)desc; @@ -532,7 +532,7 @@ static int sdhci_adma_table_pre(struct sdhci_host *host, } /* tran, valid */ - sdhci_set_adma_desc(desc, align_addr, offset, 0x21); + sdhci_adma_write_desc(desc, align_addr, offset, 0x21); BUG_ON(offset > 65536); @@ -548,7 +548,7 @@ static int sdhci_adma_table_pre(struct sdhci_host *host, BUG_ON(len > 65536); /* tran, valid */ - sdhci_set_adma_desc(desc, addr, len, 0x21); + sdhci_adma_write_desc(desc, addr, len, 0x21); desc += 8; /* @@ -572,7 +572,7 @@ static int sdhci_adma_table_pre(struct sdhci_host *host, */ /* nop, end, valid */ - sdhci_set_adma_desc(desc, 0, 0, 0x3); + sdhci_adma_write_desc(desc, 0, 0, 0x3); } /* @@ -2291,7 +2291,7 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask, u32 *mask) } #ifdef CONFIG_MMC_DEBUG -static void sdhci_show_adma_error(struct sdhci_host *host) +static void sdhci_adma_show_error(struct sdhci_host *host) { const char *name = mmc_hostname(host->mmc); u8 *desc = host->adma_desc; @@ -2316,7 +2316,7 @@ static void sdhci_show_adma_error(struct sdhci_host *host) } } #else -static void sdhci_show_adma_error(struct sdhci_host *host) { } +static void sdhci_adma_show_error(struct sdhci_host *host) { } #endif static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) @@ -2379,7 +2379,7 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) host->data->error = -EILSEQ; else if (intmask & SDHCI_INT_ADMA_ERROR) { pr_err("%s: ADMA error\n", mmc_hostname(host->mmc)); - sdhci_show_adma_error(host); + sdhci_adma_show_error(host); host->data->error = -EIO; if (host->ops->adma_workaround) host->ops->adma_workaround(host, intmask); -- cgit v1.2.3-59-g8ed1b From 4efaa6fbe1fd5e86ab2fee4cdcfc6873dab60716 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Tue, 4 Nov 2014 12:42:39 +0200 Subject: mmc: sdhci: Rename adma_desc to adma_table In preparation for 64-bit ADMA, rename adma_desc to adma_table. That is because members will be added for descriptor size and table size, so using adma_desc (which is the table) is confusing. Signed-off-by: Adrian Hunter Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci.c | 31 ++++++++++++++++--------------- include/linux/mmc/sdhci.h | 2 +- 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index e40414ab7ef8..f2062b073e00 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -505,7 +505,7 @@ static int sdhci_adma_table_pre(struct sdhci_host *host, if (host->sg_count == 0) goto unmap_align; - desc = host->adma_desc; + desc = host->adma_table; align = host->align_buffer; align_addr = host->align_addr; @@ -555,14 +555,14 @@ static int sdhci_adma_table_pre(struct sdhci_host *host, * If this triggers then we have a calculation bug * somewhere. :/ */ - WARN_ON((desc - host->adma_desc) >= ADMA_SIZE); + WARN_ON((desc - host->adma_table) >= ADMA_SIZE); } if (host->quirks & SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC) { /* * Mark the last descriptor as the terminating descriptor */ - if (desc != host->adma_desc) { + if (desc != host->adma_table) { desc -= 8; desc[0] |= 0x2; /* end */ } @@ -2294,7 +2294,7 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask, u32 *mask) static void sdhci_adma_show_error(struct sdhci_host *host) { const char *name = mmc_hostname(host->mmc); - u8 *desc = host->adma_desc; + u8 *desc = host->adma_table; __le32 *dma; __le16 *len; u8 attr; @@ -2875,27 +2875,28 @@ int sdhci_add_host(struct sdhci_host *host) * (128) and potentially one alignment transfer for * each of those entries. */ - host->adma_desc = dma_alloc_coherent(mmc_dev(mmc), - ADMA_SIZE, &host->adma_addr, - GFP_KERNEL); + host->adma_table = dma_alloc_coherent(mmc_dev(mmc), + ADMA_SIZE, + &host->adma_addr, + GFP_KERNEL); host->align_buffer = kmalloc(128 * 4, GFP_KERNEL); - if (!host->adma_desc || !host->align_buffer) { + if (!host->adma_table || !host->align_buffer) { dma_free_coherent(mmc_dev(mmc), ADMA_SIZE, - host->adma_desc, host->adma_addr); + host->adma_table, host->adma_addr); kfree(host->align_buffer); pr_warn("%s: Unable to allocate ADMA buffers - falling back to standard DMA\n", mmc_hostname(mmc)); host->flags &= ~SDHCI_USE_ADMA; - host->adma_desc = NULL; + host->adma_table = NULL; host->align_buffer = NULL; } else if (host->adma_addr & 3) { pr_warn("%s: unable to allocate aligned ADMA descriptor\n", mmc_hostname(mmc)); host->flags &= ~SDHCI_USE_ADMA; dma_free_coherent(mmc_dev(mmc), ADMA_SIZE, - host->adma_desc, host->adma_addr); + host->adma_table, host->adma_addr); kfree(host->align_buffer); - host->adma_desc = NULL; + host->adma_table = NULL; host->align_buffer = NULL; } } @@ -3351,12 +3352,12 @@ void sdhci_remove_host(struct sdhci_host *host, int dead) if (!IS_ERR(mmc->supply.vqmmc)) regulator_disable(mmc->supply.vqmmc); - if (host->adma_desc) + if (host->adma_table) dma_free_coherent(mmc_dev(mmc), ADMA_SIZE, - host->adma_desc, host->adma_addr); + host->adma_table, host->adma_addr); kfree(host->align_buffer); - host->adma_desc = NULL; + host->adma_table = NULL; host->align_buffer = NULL; } diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h index dba793e3a331..76e04324cc33 100644 --- a/include/linux/mmc/sdhci.h +++ b/include/linux/mmc/sdhci.h @@ -155,7 +155,7 @@ struct sdhci_host { int sg_count; /* Mapped sg entries */ - u8 *adma_desc; /* ADMA descriptor table */ + u8 *adma_table; /* ADMA descriptor table */ u8 *align_buffer; /* Bounce buffer */ dma_addr_t adma_addr; /* Mapped ADMA descr. table */ -- cgit v1.2.3-59-g8ed1b From b5ffa6749c596234243731e458739a2d793fb944 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Tue, 4 Nov 2014 12:42:40 +0200 Subject: mmc: sdhci: Add sdhci_adma_mark_end() In preparation for 64-bit ADMA, separate out code that touches the ADMA descriptor by adding sdhci_adma_mark_end(). Signed-off-by: Adrian Hunter Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index f2062b073e00..19f31ea99738 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -468,6 +468,13 @@ static void sdhci_adma_write_desc(u8 *desc, u32 addr, int len, unsigned cmd) dataddr[0] = cpu_to_le32(addr); } +static void sdhci_adma_mark_end(void *desc) +{ + u8 *dma_desc = desc; + + dma_desc[0] |= 0x2; /* end */ +} + static int sdhci_adma_table_pre(struct sdhci_host *host, struct mmc_data *data) { @@ -564,7 +571,7 @@ static int sdhci_adma_table_pre(struct sdhci_host *host, */ if (desc != host->adma_table) { desc -= 8; - desc[0] |= 0x2; /* end */ + sdhci_adma_mark_end(desc); } } else { /* -- cgit v1.2.3-59-g8ed1b From 1c3d5f6ddcb915c0e702cf513bad4a3b1583f48f Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Tue, 4 Nov 2014 12:42:41 +0200 Subject: mmc: sdhci: Use 'void *' for not 'u8 *' for ADMA data It is kernel-style to use 'void *' for anonymous data. This is being applied to the ADMA bounce buffer which contains unaligned bytes, and to the ADMA descriptor table which will contain 32-bit ADMA descriptors or 64-bit ADMA descriptors when support is added. Signed-off-by: Adrian Hunter Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci.c | 12 ++++++------ include/linux/mmc/sdhci.h | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 19f31ea99738..20e8a2d0d51a 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -454,7 +454,7 @@ static void sdhci_kunmap_atomic(void *buffer, unsigned long *flags) local_irq_restore(*flags); } -static void sdhci_adma_write_desc(u8 *desc, u32 addr, int len, unsigned cmd) +static void sdhci_adma_write_desc(void *desc, u32 addr, int len, unsigned cmd) { __le32 *dataddr = (__le32 __force *)(desc + 4); __le16 *cmdlen = (__le16 __force *)desc; @@ -480,8 +480,8 @@ static int sdhci_adma_table_pre(struct sdhci_host *host, { int direction; - u8 *desc; - u8 *align; + void *desc; + void *align; dma_addr_t addr; dma_addr_t align_addr; int len, offset; @@ -606,7 +606,7 @@ static void sdhci_adma_table_post(struct sdhci_host *host, struct scatterlist *sg; int i, size; - u8 *align; + void *align; char *buffer; unsigned long flags; bool has_unaligned; @@ -2301,7 +2301,7 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask, u32 *mask) static void sdhci_adma_show_error(struct sdhci_host *host) { const char *name = mmc_hostname(host->mmc); - u8 *desc = host->adma_table; + void *desc = host->adma_table; __le32 *dma; __le16 *len; u8 attr; @@ -2311,7 +2311,7 @@ static void sdhci_adma_show_error(struct sdhci_host *host) while (true) { dma = (__le32 *)(desc + 4); len = (__le16 *)(desc + 2); - attr = *desc; + attr = *(u8 *)desc; DBG("%s: %p: DMA 0x%08x, LEN 0x%04x, Attr=0x%02x\n", name, desc, le32_to_cpu(*dma), le16_to_cpu(*len), attr); diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h index 76e04324cc33..933dbbb50742 100644 --- a/include/linux/mmc/sdhci.h +++ b/include/linux/mmc/sdhci.h @@ -155,8 +155,8 @@ struct sdhci_host { int sg_count; /* Mapped sg entries */ - u8 *adma_table; /* ADMA descriptor table */ - u8 *align_buffer; /* Bounce buffer */ + void *adma_table; /* ADMA descriptor table */ + void *align_buffer; /* Bounce buffer */ dma_addr_t adma_addr; /* Mapped ADMA descr. table */ dma_addr_t align_addr; /* Mapped bounce buffer */ -- cgit v1.2.3-59-g8ed1b From 76fe379acaeb857f91705f3bd5c6f69ec13872a9 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Tue, 4 Nov 2014 12:42:42 +0200 Subject: mmc: sdhci: Parameterize ADMA sizes and alignment In preparation for 64-bit ADMA, parameterize ADMA sizes and alignment. 64-bit ADMA has a larger descriptor because it contains a 64-bit address instead of a 32-bit address. Also data must be 8-byte aligned instead of 4-byte aligned. Consequently, sdhci_host members are added for descriptor, table, and buffer sizes and alignment. Signed-off-by: Adrian Hunter Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci.c | 68 +++++++++++++++++++++++------------------------ include/linux/mmc/sdhci.h | 7 +++++ 2 files changed, 41 insertions(+), 34 deletions(-) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 20e8a2d0d51a..053b55df9df1 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -44,14 +44,6 @@ #define MAX_TUNING_LOOP 40 -/* - * The ADMA2 descriptor table size is calculated as the maximum number of - * segments (128), times 2 to allow for an alignment descriptor for each - * segment, plus 1 for a nop end descriptor, all multipled by the 32-bit - * descriptor size (8). - */ -#define ADMA_SIZE ((128 * 2 + 1) * 8) - static unsigned int debug_quirks = 0; static unsigned int debug_quirks2; @@ -502,10 +494,10 @@ static int sdhci_adma_table_pre(struct sdhci_host *host, direction = DMA_TO_DEVICE; host->align_addr = dma_map_single(mmc_dev(host->mmc), - host->align_buffer, 128 * 4, direction); + host->align_buffer, host->align_buffer_sz, direction); if (dma_mapping_error(mmc_dev(host->mmc), host->align_addr)) goto fail; - BUG_ON(host->align_addr & 0x3); + BUG_ON(host->align_addr & host->align_mask); host->sg_count = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len, direction); @@ -528,7 +520,8 @@ static int sdhci_adma_table_pre(struct sdhci_host *host, * the (up to three) bytes that screw up the * alignment. */ - offset = (4 - (addr & 0x3)) & 0x3; + offset = (host->align_sz - (addr & host->align_mask)) & + host->align_mask; if (offset) { if (data->flags & MMC_DATA_WRITE) { buffer = sdhci_kmap_atomic(sg, &flags); @@ -543,10 +536,10 @@ static int sdhci_adma_table_pre(struct sdhci_host *host, BUG_ON(offset > 65536); - align += 4; - align_addr += 4; + align += host->align_sz; + align_addr += host->align_sz; - desc += 8; + desc += host->desc_sz; addr += offset; len -= offset; @@ -556,13 +549,13 @@ static int sdhci_adma_table_pre(struct sdhci_host *host, /* tran, valid */ sdhci_adma_write_desc(desc, addr, len, 0x21); - desc += 8; + desc += host->desc_sz; /* * If this triggers then we have a calculation bug * somewhere. :/ */ - WARN_ON((desc - host->adma_table) >= ADMA_SIZE); + WARN_ON((desc - host->adma_table) >= host->adma_table_sz); } if (host->quirks & SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC) { @@ -570,7 +563,7 @@ static int sdhci_adma_table_pre(struct sdhci_host *host, * Mark the last descriptor as the terminating descriptor */ if (desc != host->adma_table) { - desc -= 8; + desc -= host->desc_sz; sdhci_adma_mark_end(desc); } } else { @@ -587,14 +580,14 @@ static int sdhci_adma_table_pre(struct sdhci_host *host, */ if (data->flags & MMC_DATA_WRITE) { dma_sync_single_for_device(mmc_dev(host->mmc), - host->align_addr, 128 * 4, direction); + host->align_addr, host->align_buffer_sz, direction); } return 0; unmap_align: dma_unmap_single(mmc_dev(host->mmc), host->align_addr, - 128 * 4, direction); + host->align_buffer_sz, direction); fail: return -EINVAL; } @@ -617,12 +610,12 @@ static void sdhci_adma_table_post(struct sdhci_host *host, direction = DMA_TO_DEVICE; dma_unmap_single(mmc_dev(host->mmc), host->align_addr, - 128 * 4, direction); + host->align_buffer_sz, direction); /* Do a quick scan of the SG list for any unaligned mappings */ has_unaligned = false; for_each_sg(data->sg, sg, host->sg_count, i) - if (sg_dma_address(sg) & 3) { + if (sg_dma_address(sg) & host->align_mask) { has_unaligned = true; break; } @@ -634,8 +627,9 @@ static void sdhci_adma_table_post(struct sdhci_host *host, align = host->align_buffer; for_each_sg(data->sg, sg, host->sg_count, i) { - if (sg_dma_address(sg) & 0x3) { - size = 4 - (sg_dma_address(sg) & 0x3); + if (sg_dma_address(sg) & host->align_mask) { + size = host->align_sz - + (sg_dma_address(sg) & host->align_mask); buffer = sdhci_kmap_atomic(sg, &flags); WARN_ON(((long)buffer & (PAGE_SIZE - 1)) > @@ -643,7 +637,7 @@ static void sdhci_adma_table_post(struct sdhci_host *host, memcpy(buffer, align, size); sdhci_kunmap_atomic(buffer, &flags); - align += 4; + align += host->align_sz; } } } @@ -2316,7 +2310,7 @@ static void sdhci_adma_show_error(struct sdhci_host *host) DBG("%s: %p: DMA 0x%08x, LEN 0x%04x, Attr=0x%02x\n", name, desc, le32_to_cpu(*dma), le16_to_cpu(*len), attr); - desc += 8; + desc += host->desc_sz; if (attr & 2) break; @@ -2878,17 +2872,23 @@ int sdhci_add_host(struct sdhci_host *host) if (host->flags & SDHCI_USE_ADMA) { /* - * We need to allocate descriptors for all sg entries - * (128) and potentially one alignment transfer for - * each of those entries. + * The DMA descriptor table size is calculated as the maximum + * number of segments times 2, to allow for an alignment + * descriptor for each segment, plus 1 for a nop end descriptor, + * all multipled by the descriptor size. */ + host->adma_table_sz = (128 * 2 + 1) * 8; + host->align_buffer_sz = 128 * 4; + host->desc_sz = 8; + host->align_sz = 4; + host->align_mask = 3; host->adma_table = dma_alloc_coherent(mmc_dev(mmc), - ADMA_SIZE, + host->adma_table_sz, &host->adma_addr, GFP_KERNEL); - host->align_buffer = kmalloc(128 * 4, GFP_KERNEL); + host->align_buffer = kmalloc(host->align_buffer_sz, GFP_KERNEL); if (!host->adma_table || !host->align_buffer) { - dma_free_coherent(mmc_dev(mmc), ADMA_SIZE, + dma_free_coherent(mmc_dev(mmc), host->adma_table_sz, host->adma_table, host->adma_addr); kfree(host->align_buffer); pr_warn("%s: Unable to allocate ADMA buffers - falling back to standard DMA\n", @@ -2896,11 +2896,11 @@ int sdhci_add_host(struct sdhci_host *host) host->flags &= ~SDHCI_USE_ADMA; host->adma_table = NULL; host->align_buffer = NULL; - } else if (host->adma_addr & 3) { + } else if (host->adma_addr & host->align_mask) { pr_warn("%s: unable to allocate aligned ADMA descriptor\n", mmc_hostname(mmc)); host->flags &= ~SDHCI_USE_ADMA; - dma_free_coherent(mmc_dev(mmc), ADMA_SIZE, + dma_free_coherent(mmc_dev(mmc), host->adma_table_sz, host->adma_table, host->adma_addr); kfree(host->align_buffer); host->adma_table = NULL; @@ -3360,7 +3360,7 @@ void sdhci_remove_host(struct sdhci_host *host, int dead) regulator_disable(mmc->supply.vqmmc); if (host->adma_table) - dma_free_coherent(mmc_dev(mmc), ADMA_SIZE, + dma_free_coherent(mmc_dev(mmc), host->adma_table_sz, host->adma_table, host->adma_addr); kfree(host->align_buffer); diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h index 933dbbb50742..2a72e9510833 100644 --- a/include/linux/mmc/sdhci.h +++ b/include/linux/mmc/sdhci.h @@ -158,9 +158,16 @@ struct sdhci_host { void *adma_table; /* ADMA descriptor table */ void *align_buffer; /* Bounce buffer */ + size_t adma_table_sz; /* ADMA descriptor table size */ + size_t align_buffer_sz; /* Bounce buffer size */ + dma_addr_t adma_addr; /* Mapped ADMA descr. table */ dma_addr_t align_addr; /* Mapped bounce buffer */ + unsigned int desc_sz; /* ADMA descriptor size */ + unsigned int align_sz; /* ADMA alignment */ + unsigned int align_mask; /* ADMA alignment mask */ + struct tasklet_struct finish_tasklet; /* Tasklet structures */ struct timer_list timer; /* Timer for timeouts */ -- cgit v1.2.3-59-g8ed1b From 4fb213f81fe51ace7dea7d2f7cc2417fa2a2dd9e Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Tue, 4 Nov 2014 12:42:43 +0200 Subject: mmc: sdhci: Define maximum segments Define the maximum number of segments instead of having the constant 128 appearing in the code in various places. Signed-off-by: Adrian Hunter Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci.c | 8 ++++---- drivers/mmc/host/sdhci.h | 6 ++++++ 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 053b55df9df1..586c7391a066 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -2877,8 +2877,8 @@ int sdhci_add_host(struct sdhci_host *host) * descriptor for each segment, plus 1 for a nop end descriptor, * all multipled by the descriptor size. */ - host->adma_table_sz = (128 * 2 + 1) * 8; - host->align_buffer_sz = 128 * 4; + host->adma_table_sz = (SDHCI_MAX_SEGS * 2 + 1) * 8; + host->align_buffer_sz = SDHCI_MAX_SEGS * 4; host->desc_sz = 8; host->align_sz = 4; host->align_mask = 3; @@ -3192,11 +3192,11 @@ int sdhci_add_host(struct sdhci_host *host) * can do scatter/gather or not. */ if (host->flags & SDHCI_USE_ADMA) - mmc->max_segs = 128; + mmc->max_segs = SDHCI_MAX_SEGS; else if (host->flags & SDHCI_USE_SDMA) mmc->max_segs = 1; else /* PIO */ - mmc->max_segs = 128; + mmc->max_segs = SDHCI_MAX_SEGS; /* * Maximum number of sectors in one transfer. Limited by DMA boundary diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index 31896a779d4e..6ae75cdd5f41 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -266,6 +266,12 @@ #define SDHCI_DEFAULT_BOUNDARY_SIZE (512 * 1024) #define SDHCI_DEFAULT_BOUNDARY_ARG (ilog2(SDHCI_DEFAULT_BOUNDARY_SIZE) - 12) +/* + * Maximum segments assuming a 512KiB maximum requisition size and a minimum + * 4KiB page size. + */ +#define SDHCI_MAX_SEGS 128 + struct sdhci_ops { #ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS u32 (*read_l)(struct sdhci_host *host, int reg); -- cgit v1.2.3-59-g8ed1b From 739d46dcc24d9fabeed1dea6705d2c7f444b092c Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Tue, 4 Nov 2014 12:42:44 +0200 Subject: mmc: sdhci: Define ADMA constants Define all the ADMA constants instead of having numbers scattered throughout the code. Signed-off-by: Adrian Hunter Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci.c | 23 +++++++++++++---------- drivers/mmc/host/sdhci.h | 10 ++++++++++ 2 files changed, 23 insertions(+), 10 deletions(-) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 586c7391a066..11b62171f94e 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -464,7 +464,7 @@ static void sdhci_adma_mark_end(void *desc) { u8 *dma_desc = desc; - dma_desc[0] |= 0x2; /* end */ + dma_desc[0] |= ADMA2_END; } static int sdhci_adma_table_pre(struct sdhci_host *host, @@ -532,7 +532,8 @@ static int sdhci_adma_table_pre(struct sdhci_host *host, } /* tran, valid */ - sdhci_adma_write_desc(desc, align_addr, offset, 0x21); + sdhci_adma_write_desc(desc, align_addr, offset, + ADMA2_TRAN_VALID); BUG_ON(offset > 65536); @@ -548,7 +549,7 @@ static int sdhci_adma_table_pre(struct sdhci_host *host, BUG_ON(len > 65536); /* tran, valid */ - sdhci_adma_write_desc(desc, addr, len, 0x21); + sdhci_adma_write_desc(desc, addr, len, ADMA2_TRAN_VALID); desc += host->desc_sz; /* @@ -572,7 +573,7 @@ static int sdhci_adma_table_pre(struct sdhci_host *host, */ /* nop, end, valid */ - sdhci_adma_write_desc(desc, 0, 0, 0x3); + sdhci_adma_write_desc(desc, 0, 0, ADMA2_NOP_END_VALID); } /* @@ -2312,7 +2313,7 @@ static void sdhci_adma_show_error(struct sdhci_host *host) desc += host->desc_sz; - if (attr & 2) + if (attr & ADMA2_END) break; } } @@ -2877,11 +2878,13 @@ int sdhci_add_host(struct sdhci_host *host) * descriptor for each segment, plus 1 for a nop end descriptor, * all multipled by the descriptor size. */ - host->adma_table_sz = (SDHCI_MAX_SEGS * 2 + 1) * 8; - host->align_buffer_sz = SDHCI_MAX_SEGS * 4; - host->desc_sz = 8; - host->align_sz = 4; - host->align_mask = 3; + host->adma_table_sz = (SDHCI_MAX_SEGS * 2 + 1) * + SDHCI_ADMA2_32_DESC_SZ; + host->align_buffer_sz = SDHCI_MAX_SEGS * + SDHCI_ADMA2_32_ALIGN; + host->desc_sz = SDHCI_ADMA2_32_DESC_SZ; + host->align_sz = SDHCI_ADMA2_32_ALIGN; + host->align_mask = SDHCI_ADMA2_32_ALIGN - 1; host->adma_table = dma_alloc_coherent(mmc_dev(mmc), host->adma_table_sz, &host->adma_addr, diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index 6ae75cdd5f41..823cce177498 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -266,6 +266,16 @@ #define SDHCI_DEFAULT_BOUNDARY_SIZE (512 * 1024) #define SDHCI_DEFAULT_BOUNDARY_ARG (ilog2(SDHCI_DEFAULT_BOUNDARY_SIZE) - 12) +/* ADMA2 32-bit DMA descriptor size */ +#define SDHCI_ADMA2_32_DESC_SZ 8 + +/* ADMA2 32-bit DMA alignment */ +#define SDHCI_ADMA2_32_ALIGN 4 + +#define ADMA2_TRAN_VALID 0x21 +#define ADMA2_NOP_END_VALID 0x3 +#define ADMA2_END 0x2 + /* * Maximum segments assuming a 512KiB maximum requisition size and a minimum * 4KiB page size. -- cgit v1.2.3-59-g8ed1b From 0545230f1764bc639e14eea3fe944d9d16e91a92 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Tue, 4 Nov 2014 12:42:45 +0200 Subject: mmc: sdhci: Define ADMA descriptor structure Define the ADMA descriptor structure instead of using manual offsets and casts. Signed-off-by: Adrian Hunter Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci.c | 30 +++++++++++------------------- drivers/mmc/host/sdhci.h | 7 +++++++ 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 11b62171f94e..ec093490a24f 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -448,23 +448,18 @@ static void sdhci_kunmap_atomic(void *buffer, unsigned long *flags) static void sdhci_adma_write_desc(void *desc, u32 addr, int len, unsigned cmd) { - __le32 *dataddr = (__le32 __force *)(desc + 4); - __le16 *cmdlen = (__le16 __force *)desc; + struct sdhci_adma2_32_desc *dma_desc = desc; - /* SDHCI specification says ADMA descriptors should be 4 byte - * aligned, so using 16 or 32bit operations should be safe. */ - - cmdlen[0] = cpu_to_le16(cmd); - cmdlen[1] = cpu_to_le16(len); - - dataddr[0] = cpu_to_le32(addr); + dma_desc->cmd = cpu_to_le16(cmd); + dma_desc->len = cpu_to_le16(len); + dma_desc->addr = cpu_to_le32(addr); } static void sdhci_adma_mark_end(void *desc) { - u8 *dma_desc = desc; + struct sdhci_adma2_32_desc *dma_desc = desc; - dma_desc[0] |= ADMA2_END; + dma_desc->cmd |= cpu_to_le16(ADMA2_END); } static int sdhci_adma_table_pre(struct sdhci_host *host, @@ -2297,23 +2292,20 @@ static void sdhci_adma_show_error(struct sdhci_host *host) { const char *name = mmc_hostname(host->mmc); void *desc = host->adma_table; - __le32 *dma; - __le16 *len; - u8 attr; sdhci_dumpregs(host); while (true) { - dma = (__le32 *)(desc + 4); - len = (__le16 *)(desc + 2); - attr = *(u8 *)desc; + struct sdhci_adma2_32_desc *dma_desc = desc; DBG("%s: %p: DMA 0x%08x, LEN 0x%04x, Attr=0x%02x\n", - name, desc, le32_to_cpu(*dma), le16_to_cpu(*len), attr); + name, desc, le32_to_cpu(dma_desc->addr), + le16_to_cpu(dma_desc->len), + le16_to_cpu(dma_desc->cmd)); desc += host->desc_sz; - if (attr & ADMA2_END) + if (dma_desc->cmd & cpu_to_le16(ADMA2_END)) break; } } diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index 823cce177498..14c8b6773dbb 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -272,6 +272,13 @@ /* ADMA2 32-bit DMA alignment */ #define SDHCI_ADMA2_32_ALIGN 4 +/* ADMA2 32-bit descriptor */ +struct sdhci_adma2_32_desc { + __le16 cmd; + __le16 len; + __le32 addr; +} __packed __aligned(SDHCI_ADMA2_32_ALIGN); + #define ADMA2_TRAN_VALID 0x21 #define ADMA2_NOP_END_VALID 0x3 #define ADMA2_END 0x2 -- cgit v1.2.3-59-g8ed1b From e57a5f61eae7e145aeeda18ccb22576822f534bf Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Tue, 4 Nov 2014 12:42:46 +0200 Subject: mmc: sdhci: Add 64-bit ADMA support Add 64-bit ADMA support including: - add 64-bit ADMA descriptor - add SDHCI_USE_64_BIT_DMA flag - set upper 32-bits of DMA addresses - ability to select 64-bit ADMA - ability to use 64-bit ADMA sizes and alignment - display "ADMA 64-bit" when host is added It is assumed that a 64-bit capable device has set a 64-bit DMA mask and *must* do 64-bit DMA. A driver has the opportunity to change that during the first call to ->enable_dma(). Similarly SDHCI_QUIRK2_BROKEN_64_BIT_DMA must be left to the drivers to implement. Signed-off-by: Adrian Hunter Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci.c | 109 ++++++++++++++++++++++++++++++++++------------ drivers/mmc/host/sdhci.h | 18 ++++++++ include/linux/mmc/sdhci.h | 3 ++ 3 files changed, 102 insertions(+), 28 deletions(-) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index ec093490a24f..f895ab07fcc2 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -117,10 +117,17 @@ static void sdhci_dumpregs(struct sdhci_host *host) pr_debug(DRIVER_NAME ": Host ctl2: 0x%08x\n", sdhci_readw(host, SDHCI_HOST_CONTROL2)); - if (host->flags & SDHCI_USE_ADMA) - pr_debug(DRIVER_NAME ": ADMA Err: 0x%08x | ADMA Ptr: 0x%08x\n", - readl(host->ioaddr + SDHCI_ADMA_ERROR), - readl(host->ioaddr + SDHCI_ADMA_ADDRESS)); + if (host->flags & SDHCI_USE_ADMA) { + if (host->flags & SDHCI_USE_64_BIT_DMA) + pr_debug(DRIVER_NAME ": ADMA Err: 0x%08x | ADMA Ptr: 0x%08x%08x\n", + readl(host->ioaddr + SDHCI_ADMA_ERROR), + readl(host->ioaddr + SDHCI_ADMA_ADDRESS_HI), + readl(host->ioaddr + SDHCI_ADMA_ADDRESS)); + else + pr_debug(DRIVER_NAME ": ADMA Err: 0x%08x | ADMA Ptr: 0x%08x\n", + readl(host->ioaddr + SDHCI_ADMA_ERROR), + readl(host->ioaddr + SDHCI_ADMA_ADDRESS)); + } pr_debug(DRIVER_NAME ": ===========================================\n"); } @@ -446,19 +453,25 @@ static void sdhci_kunmap_atomic(void *buffer, unsigned long *flags) local_irq_restore(*flags); } -static void sdhci_adma_write_desc(void *desc, u32 addr, int len, unsigned cmd) +static void sdhci_adma_write_desc(struct sdhci_host *host, void *desc, + dma_addr_t addr, int len, unsigned cmd) { - struct sdhci_adma2_32_desc *dma_desc = desc; + struct sdhci_adma2_64_desc *dma_desc = desc; + /* 32-bit and 64-bit descriptors have these members in same position */ dma_desc->cmd = cpu_to_le16(cmd); dma_desc->len = cpu_to_le16(len); - dma_desc->addr = cpu_to_le32(addr); + dma_desc->addr_lo = cpu_to_le32((u32)addr); + + if (host->flags & SDHCI_USE_64_BIT_DMA) + dma_desc->addr_hi = cpu_to_le32((u64)addr >> 32); } static void sdhci_adma_mark_end(void *desc) { - struct sdhci_adma2_32_desc *dma_desc = desc; + struct sdhci_adma2_64_desc *dma_desc = desc; + /* 32-bit and 64-bit descriptors have 'cmd' in same position */ dma_desc->cmd |= cpu_to_le16(ADMA2_END); } @@ -527,7 +540,7 @@ static int sdhci_adma_table_pre(struct sdhci_host *host, } /* tran, valid */ - sdhci_adma_write_desc(desc, align_addr, offset, + sdhci_adma_write_desc(host, desc, align_addr, offset, ADMA2_TRAN_VALID); BUG_ON(offset > 65536); @@ -544,7 +557,7 @@ static int sdhci_adma_table_pre(struct sdhci_host *host, BUG_ON(len > 65536); /* tran, valid */ - sdhci_adma_write_desc(desc, addr, len, ADMA2_TRAN_VALID); + sdhci_adma_write_desc(host, desc, addr, len, ADMA2_TRAN_VALID); desc += host->desc_sz; /* @@ -568,7 +581,7 @@ static int sdhci_adma_table_pre(struct sdhci_host *host, */ /* nop, end, valid */ - sdhci_adma_write_desc(desc, 0, 0, ADMA2_NOP_END_VALID); + sdhci_adma_write_desc(host, desc, 0, 0, ADMA2_NOP_END_VALID); } /* @@ -827,6 +840,10 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd) } else { sdhci_writel(host, host->adma_addr, SDHCI_ADMA_ADDRESS); + if (host->flags & SDHCI_USE_64_BIT_DMA) + sdhci_writel(host, + (u64)host->adma_addr >> 32, + SDHCI_ADMA_ADDRESS_HI); } } else { int sg_cnt; @@ -860,10 +877,14 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd) ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); ctrl &= ~SDHCI_CTRL_DMA_MASK; if ((host->flags & SDHCI_REQ_USE_DMA) && - (host->flags & SDHCI_USE_ADMA)) - ctrl |= SDHCI_CTRL_ADMA32; - else + (host->flags & SDHCI_USE_ADMA)) { + if (host->flags & SDHCI_USE_64_BIT_DMA) + ctrl |= SDHCI_CTRL_ADMA64; + else + ctrl |= SDHCI_CTRL_ADMA32; + } else { ctrl |= SDHCI_CTRL_SDMA; + } sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); } @@ -2296,12 +2317,19 @@ static void sdhci_adma_show_error(struct sdhci_host *host) sdhci_dumpregs(host); while (true) { - struct sdhci_adma2_32_desc *dma_desc = desc; - - DBG("%s: %p: DMA 0x%08x, LEN 0x%04x, Attr=0x%02x\n", - name, desc, le32_to_cpu(dma_desc->addr), - le16_to_cpu(dma_desc->len), - le16_to_cpu(dma_desc->cmd)); + struct sdhci_adma2_64_desc *dma_desc = desc; + + if (host->flags & SDHCI_USE_64_BIT_DMA) + DBG("%s: %p: DMA 0x%08x%08x, LEN 0x%04x, Attr=0x%02x\n", + name, desc, le32_to_cpu(dma_desc->addr_hi), + le32_to_cpu(dma_desc->addr_lo), + le16_to_cpu(dma_desc->len), + le16_to_cpu(dma_desc->cmd)); + else + DBG("%s: %p: DMA 0x%08x, LEN 0x%04x, Attr=0x%02x\n", + name, desc, le32_to_cpu(dma_desc->addr_lo), + le16_to_cpu(dma_desc->len), + le16_to_cpu(dma_desc->cmd)); desc += host->desc_sz; @@ -2852,6 +2880,16 @@ int sdhci_add_host(struct sdhci_host *host) host->flags &= ~SDHCI_USE_ADMA; } + /* + * It is assumed that a 64-bit capable device has set a 64-bit DMA mask + * and *must* do 64-bit DMA. A driver has the opportunity to change + * that during the first call to ->enable_dma(). Similarly + * SDHCI_QUIRK2_BROKEN_64_BIT_DMA must be left to the drivers to + * implement. + */ + if (sdhci_readl(host, SDHCI_CAPABILITIES) & SDHCI_CAN_64BIT) + host->flags |= SDHCI_USE_64_BIT_DMA; + if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) { if (host->ops->enable_dma) { if (host->ops->enable_dma(host)) { @@ -2863,6 +2901,10 @@ int sdhci_add_host(struct sdhci_host *host) } } + /* SDMA does not support 64-bit DMA */ + if (host->flags & SDHCI_USE_64_BIT_DMA) + host->flags &= ~SDHCI_USE_SDMA; + if (host->flags & SDHCI_USE_ADMA) { /* * The DMA descriptor table size is calculated as the maximum @@ -2870,13 +2912,23 @@ int sdhci_add_host(struct sdhci_host *host) * descriptor for each segment, plus 1 for a nop end descriptor, * all multipled by the descriptor size. */ - host->adma_table_sz = (SDHCI_MAX_SEGS * 2 + 1) * - SDHCI_ADMA2_32_DESC_SZ; - host->align_buffer_sz = SDHCI_MAX_SEGS * - SDHCI_ADMA2_32_ALIGN; - host->desc_sz = SDHCI_ADMA2_32_DESC_SZ; - host->align_sz = SDHCI_ADMA2_32_ALIGN; - host->align_mask = SDHCI_ADMA2_32_ALIGN - 1; + if (host->flags & SDHCI_USE_64_BIT_DMA) { + host->adma_table_sz = (SDHCI_MAX_SEGS * 2 + 1) * + SDHCI_ADMA2_64_DESC_SZ; + host->align_buffer_sz = SDHCI_MAX_SEGS * + SDHCI_ADMA2_64_ALIGN; + host->desc_sz = SDHCI_ADMA2_64_DESC_SZ; + host->align_sz = SDHCI_ADMA2_64_ALIGN; + host->align_mask = SDHCI_ADMA2_64_ALIGN - 1; + } else { + host->adma_table_sz = (SDHCI_MAX_SEGS * 2 + 1) * + SDHCI_ADMA2_32_DESC_SZ; + host->align_buffer_sz = SDHCI_MAX_SEGS * + SDHCI_ADMA2_32_ALIGN; + host->desc_sz = SDHCI_ADMA2_32_DESC_SZ; + host->align_sz = SDHCI_ADMA2_32_ALIGN; + host->align_mask = SDHCI_ADMA2_32_ALIGN - 1; + } host->adma_table = dma_alloc_coherent(mmc_dev(mmc), host->adma_table_sz, &host->adma_addr, @@ -3289,7 +3341,8 @@ int sdhci_add_host(struct sdhci_host *host) pr_info("%s: SDHCI controller on %s [%s] using %s\n", mmc_hostname(mmc), host->hw_name, dev_name(mmc_dev(mmc)), - (host->flags & SDHCI_USE_ADMA) ? "ADMA" : + (host->flags & SDHCI_USE_ADMA) ? + (host->flags & SDHCI_USE_64_BIT_DMA) ? "ADMA 64-bit" : "ADMA" : (host->flags & SDHCI_USE_SDMA) ? "DMA" : "PIO"); sdhci_enable_card_detection(host); diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index 14c8b6773dbb..c2ec7fcd8a1f 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -227,6 +227,7 @@ /* 55-57 reserved */ #define SDHCI_ADMA_ADDRESS 0x58 +#define SDHCI_ADMA_ADDRESS_HI 0x5C /* 60-FB reserved */ @@ -279,6 +280,23 @@ struct sdhci_adma2_32_desc { __le32 addr; } __packed __aligned(SDHCI_ADMA2_32_ALIGN); +/* ADMA2 64-bit DMA descriptor size */ +#define SDHCI_ADMA2_64_DESC_SZ 12 + +/* ADMA2 64-bit DMA alignment */ +#define SDHCI_ADMA2_64_ALIGN 8 + +/* + * ADMA2 64-bit descriptor. Note 12-byte descriptor can't always be 8-byte + * aligned. + */ +struct sdhci_adma2_64_desc { + __le16 cmd; + __le16 len; + __le32 addr_lo; + __le32 addr_hi; +} __packed __aligned(4); + #define ADMA2_TRAN_VALID 0x21 #define ADMA2_NOP_END_VALID 0x3 #define ADMA2_END 0x2 diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h index 2a72e9510833..931ac5e05453 100644 --- a/include/linux/mmc/sdhci.h +++ b/include/linux/mmc/sdhci.h @@ -100,6 +100,8 @@ struct sdhci_host { #define SDHCI_QUIRK2_BROKEN_DDR50 (1<<7) /* Stop command (CMD12) can set Transfer Complete when not using MMC_RSP_BUSY */ #define SDHCI_QUIRK2_STOP_WITH_TC (1<<8) +/* Controller does not support 64-bit DMA */ +#define SDHCI_QUIRK2_BROKEN_64_BIT_DMA (1<<9) int irq; /* Device IRQ */ void __iomem *ioaddr; /* Mapped address */ @@ -130,6 +132,7 @@ struct sdhci_host { #define SDHCI_SDIO_IRQ_ENABLED (1<<9) /* SDIO irq enabled */ #define SDHCI_SDR104_NEEDS_TUNING (1<<10) /* SDR104/HS200 needs tuning */ #define SDHCI_USING_RETUNING_TIMER (1<<11) /* Host is using a retuning timer for the card */ +#define SDHCI_USE_64_BIT_DMA (1<<12) /* Use 64-bit DMA */ unsigned int version; /* SDHCI spec. version */ -- cgit v1.2.3-59-g8ed1b From 4f64f84348e029c442b9caa37944754e6513cbf1 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Tue, 4 Nov 2014 12:42:47 +0200 Subject: mmc: sdhci-acpi: Add 64-bit DMA support Set the DMA mask during the first call to ->enable_dma() to make use of the SDHCI_USE_64_BIT_DMA flag. This patch is dependent on commit 8a2f38ddfeb526c30b3ec209468172a30a38d996 ("ACPI / platform: provide default DMA mask") which provides the dev->dma_mask pointer without which dma_set_mask_and_coherent() will always fail. Signed-off-by: Adrian Hunter Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-acpi.c | 40 ++++++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/drivers/mmc/host/sdhci-acpi.c b/drivers/mmc/host/sdhci-acpi.c index 9cccc0e89b04..310976307954 100644 --- a/drivers/mmc/host/sdhci-acpi.c +++ b/drivers/mmc/host/sdhci-acpi.c @@ -76,6 +76,7 @@ struct sdhci_acpi_host { const struct sdhci_acpi_slot *slot; struct platform_device *pdev; bool use_runtime_pm; + bool dma_setup; }; static inline bool sdhci_acpi_flag(struct sdhci_acpi_host *c, unsigned int flag) @@ -85,7 +86,29 @@ static inline bool sdhci_acpi_flag(struct sdhci_acpi_host *c, unsigned int flag) static int sdhci_acpi_enable_dma(struct sdhci_host *host) { - return 0; + struct sdhci_acpi_host *c = sdhci_priv(host); + struct device *dev = &c->pdev->dev; + int err = -1; + + if (c->dma_setup) + return 0; + + if (host->flags & SDHCI_USE_64_BIT_DMA) { + if (host->quirks2 & SDHCI_QUIRK2_BROKEN_64_BIT_DMA) { + host->flags &= ~SDHCI_USE_64_BIT_DMA; + } else { + err = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)); + if (err) + dev_warn(dev, "Failed to set 64-bit DMA mask\n"); + } + } + + if (err) + err = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32)); + + c->dma_setup = !err; + + return err; } static void sdhci_acpi_int_hw_reset(struct sdhci_host *host) @@ -305,21 +328,6 @@ static int sdhci_acpi_probe(struct platform_device *pdev) goto err_free; } - if (!dev->dma_mask) { - u64 dma_mask; - - if (sdhci_readl(host, SDHCI_CAPABILITIES) & SDHCI_CAN_64BIT) { - /* 64-bit DMA is not supported at present */ - dma_mask = DMA_BIT_MASK(32); - } else { - dma_mask = DMA_BIT_MASK(32); - } - - err = dma_coerce_mask_and_coherent(dev, dma_mask); - if (err) - goto err_free; - } - if (c->slot) { if (c->slot->probe_slot) { err = c->slot->probe_slot(pdev, hid, uid); -- cgit v1.2.3-59-g8ed1b From 3828ecaa1d5c55b4ed7522079e1a66a899f70d98 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Tue, 4 Nov 2014 12:42:48 +0200 Subject: mmc: sdhci-pci: Add 64-bit DMA support Set a 64-bit DMA mask when using 64-bit DMA. Signed-off-by: Adrian Hunter Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-pci.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c index 61192973e7cb..c25639b839cd 100644 --- a/drivers/mmc/host/sdhci-pci.c +++ b/drivers/mmc/host/sdhci-pci.c @@ -1064,7 +1064,7 @@ static int sdhci_pci_enable_dma(struct sdhci_host *host) { struct sdhci_pci_slot *slot; struct pci_dev *pdev; - int ret; + int ret = -1; slot = sdhci_priv(host); pdev = slot->chip->pdev; @@ -1076,7 +1076,17 @@ static int sdhci_pci_enable_dma(struct sdhci_host *host) "doesn't fully claim to support it.\n"); } - ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); + if (host->flags & SDHCI_USE_64_BIT_DMA) { + if (host->quirks2 & SDHCI_QUIRK2_BROKEN_64_BIT_DMA) { + host->flags &= ~SDHCI_USE_64_BIT_DMA; + } else { + ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(64)); + if (ret) + dev_warn(&pdev->dev, "Failed to set 64-bit DMA mask\n"); + } + } + if (ret) + ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); if (ret) return ret; -- cgit v1.2.3-59-g8ed1b From 3ee14bf79d2f662f58009eb475083880ee8bfd27 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Tue, 4 Nov 2014 12:42:49 +0200 Subject: mmc: mmc_test: Extend "Badly aligned" tests for 8-byte alignment The "Badly aligned" tests, test reading/writing with alignments of 1,2 and 3. SDHCI now has 64-bit ADMA which has 8-byte alignment, so extend the tests to test up to 7. Signed-off-by: Adrian Hunter Signed-off-by: Ulf Hansson --- drivers/mmc/card/mmc_test.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/mmc/card/mmc_test.c b/drivers/mmc/card/mmc_test.c index b0643432d6d9..0a7430f94d29 100644 --- a/drivers/mmc/card/mmc_test.c +++ b/drivers/mmc/card/mmc_test.c @@ -33,6 +33,8 @@ #define BUFFER_ORDER 2 #define BUFFER_SIZE (PAGE_SIZE << BUFFER_ORDER) +#define TEST_ALIGN_END 8 + /* * Limit the test area size to the maximum MMC HC erase group size. Note that * the maximum SD allocation unit size is just 4MiB. @@ -1175,7 +1177,7 @@ static int mmc_test_align_write(struct mmc_test_card *test) int ret, i; struct scatterlist sg; - for (i = 1;i < 4;i++) { + for (i = 1; i < TEST_ALIGN_END; i++) { sg_init_one(&sg, test->buffer + i, 512); ret = mmc_test_transfer(test, &sg, 1, 0, 1, 512, 1); if (ret) @@ -1190,7 +1192,7 @@ static int mmc_test_align_read(struct mmc_test_card *test) int ret, i; struct scatterlist sg; - for (i = 1;i < 4;i++) { + for (i = 1; i < TEST_ALIGN_END; i++) { sg_init_one(&sg, test->buffer + i, 512); ret = mmc_test_transfer(test, &sg, 1, 0, 1, 512, 0); if (ret) @@ -1217,7 +1219,7 @@ static int mmc_test_align_multi_write(struct mmc_test_card *test) if (size < 1024) return RESULT_UNSUP_HOST; - for (i = 1;i < 4;i++) { + 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); if (ret) @@ -1244,7 +1246,7 @@ static int mmc_test_align_multi_read(struct mmc_test_card *test) if (size < 1024) return RESULT_UNSUP_HOST; - for (i = 1;i < 4;i++) { + 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); if (ret) -- cgit v1.2.3-59-g8ed1b From ae552ab02cd556f53047959f15a5f870ab7c5ebe Mon Sep 17 00:00:00 2001 From: Wenyou Yang Date: Thu, 30 Oct 2014 12:00:41 +0800 Subject: mmc: atmel-mci: add runtime pm support Add runtime pm support to atmel mci controller. Use runtime pm APIs to enable/disable atmel mci's clock. Use runtime autosuspend APIs to enable auto suspend delay. Signed-off-by: Wenyou Yang Acked-by: Ludovic Desroches Signed-off-by: Ulf Hansson [Ulf: Fixed compile error] --- drivers/mmc/host/atmel-mci.c | 90 +++++++++++++++++++++++++++++++++----------- 1 file changed, 67 insertions(+), 23 deletions(-) diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c index d9646e5ae2c8..4df1599583f8 100644 --- a/drivers/mmc/host/atmel-mci.c +++ b/drivers/mmc/host/atmel-mci.c @@ -37,6 +37,8 @@ #include #include +#include +#include #include #include @@ -44,6 +46,8 @@ #include "atmel-mci-regs.h" +#define AUTOSUSPEND_DELAY 50 + #define ATMCI_DATA_ERROR_FLAGS (ATMCI_DCRCE | ATMCI_DTOE | ATMCI_OVRE | ATMCI_UNRE) #define ATMCI_DMA_THRESHOLD 16 @@ -386,20 +390,19 @@ static int atmci_regs_show(struct seq_file *s, void *v) if (!buf) return -ENOMEM; + pm_runtime_get_sync(&host->pdev->dev); + /* * Grab a more or less consistent snapshot. Note that we're * not disabling interrupts, so IMR and SR may not be * consistent. */ - ret = clk_prepare_enable(host->mck); - if (ret) - goto out; - spin_lock_bh(&host->lock); memcpy_fromio(buf, host->regs, ATMCI_REGS_SIZE); spin_unlock_bh(&host->lock); - clk_disable_unprepare(host->mck); + pm_runtime_mark_last_busy(&host->pdev->dev); + pm_runtime_put_autosuspend(&host->pdev->dev); seq_printf(s, "MR:\t0x%08x%s%s ", buf[ATMCI_MR / 4], @@ -449,7 +452,6 @@ static int atmci_regs_show(struct seq_file *s, void *v) val & ATMCI_CFG_LSYNC ? " LSYNC" : ""); } -out: kfree(buf); return ret; @@ -1255,6 +1257,8 @@ static void atmci_request(struct mmc_host *mmc, struct mmc_request *mrq) WARN_ON(slot->mrq); dev_dbg(&host->pdev->dev, "MRQ: cmd %u\n", mrq->cmd->opcode); + pm_runtime_get_sync(&host->pdev->dev); + /* * We may "know" the card is gone even though there's still an * electrical connection. If so, we really need to communicate @@ -1284,7 +1288,8 @@ static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) struct atmel_mci_slot *slot = mmc_priv(mmc); struct atmel_mci *host = slot->host; unsigned int i; - bool unprepare_clk; + + pm_runtime_get_sync(&host->pdev->dev); slot->sdc_reg &= ~ATMCI_SDCBUS_MASK; switch (ios->bus_width) { @@ -1300,13 +1305,8 @@ static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) unsigned int clock_min = ~0U; u32 clkdiv; - clk_prepare(host->mck); - unprepare_clk = true; - spin_lock_bh(&host->lock); if (!host->mode_reg) { - clk_enable(host->mck); - unprepare_clk = false; atmci_writel(host, ATMCI_CR, ATMCI_CR_SWRST); atmci_writel(host, ATMCI_CR, ATMCI_CR_MCIEN); if (host->caps.has_cfg_reg) @@ -1374,8 +1374,6 @@ static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) } else { bool any_slot_active = false; - unprepare_clk = false; - spin_lock_bh(&host->lock); slot->clock = 0; for (i = 0; i < ATMCI_MAX_NR_SLOTS; i++) { @@ -1388,17 +1386,12 @@ static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) atmci_writel(host, ATMCI_CR, ATMCI_CR_MCIDIS); if (host->mode_reg) { atmci_readl(host, ATMCI_MR); - clk_disable(host->mck); - unprepare_clk = true; } host->mode_reg = 0; } spin_unlock_bh(&host->lock); } - if (unprepare_clk) - clk_unprepare(host->mck); - switch (ios->power_mode) { case MMC_POWER_OFF: if (!IS_ERR(mmc->supply.vmmc)) @@ -1424,6 +1417,9 @@ static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) */ break; } + + pm_runtime_mark_last_busy(&host->pdev->dev); + pm_runtime_put_autosuspend(&host->pdev->dev); } static int atmci_get_ro(struct mmc_host *mmc) @@ -1515,6 +1511,9 @@ static void atmci_request_end(struct atmel_mci *host, struct mmc_request *mrq) spin_unlock(&host->lock); mmc_request_done(prev_mmc, mrq); spin_lock(&host->lock); + + pm_runtime_mark_last_busy(&host->pdev->dev); + pm_runtime_put_autosuspend(&host->pdev->dev); } static void atmci_command_complete(struct atmel_mci *host, @@ -2424,15 +2423,16 @@ static int __init atmci_probe(struct platform_device *pdev) atmci_writel(host, ATMCI_CR, ATMCI_CR_SWRST); host->bus_hz = clk_get_rate(host->mck); - clk_disable_unprepare(host->mck); host->mapbase = regs->start; tasklet_init(&host->tasklet, atmci_tasklet_func, (unsigned long)host); ret = request_irq(irq, atmci_interrupt, 0, dev_name(&pdev->dev), host); - if (ret) + if (ret) { + clk_disable_unprepare(host->mck); return ret; + } /* Get MCI capabilities and set operations according to it */ atmci_get_cap(host); @@ -2456,6 +2456,12 @@ static int __init atmci_probe(struct platform_device *pdev) setup_timer(&host->timer, atmci_timeout_timer, (unsigned long)host); + pm_runtime_get_noresume(&pdev->dev); + pm_runtime_set_active(&pdev->dev); + pm_runtime_set_autosuspend_delay(&pdev->dev, AUTOSUSPEND_DELAY); + pm_runtime_use_autosuspend(&pdev->dev); + pm_runtime_enable(&pdev->dev); + /* We need at least one slot to succeed */ nr_slots = 0; ret = -ENODEV; @@ -2498,6 +2504,9 @@ static int __init atmci_probe(struct platform_device *pdev) "Atmel MCI controller at 0x%08lx irq %d, %u slots\n", host->mapbase, irq, nr_slots); + pm_runtime_mark_last_busy(&host->pdev->dev); + pm_runtime_put_autosuspend(&pdev->dev); + return 0; err_dma_alloc: @@ -2506,6 +2515,11 @@ err_dma_alloc: atmci_cleanup_slot(host->slot[i], i); } err_init_slot: + clk_disable_unprepare(host->mck); + + pm_runtime_disable(&pdev->dev); + pm_runtime_put_noidle(&pdev->dev); + del_timer_sync(&host->timer); if (host->dma.chan) dma_release_channel(host->dma.chan); @@ -2518,6 +2532,8 @@ static int __exit atmci_remove(struct platform_device *pdev) struct atmel_mci *host = platform_get_drvdata(pdev); unsigned int i; + pm_runtime_get_sync(&pdev->dev); + if (host->buffer) dma_free_coherent(&pdev->dev, host->buf_size, host->buffer, host->buf_phys_addr); @@ -2527,11 +2543,9 @@ static int __exit atmci_remove(struct platform_device *pdev) atmci_cleanup_slot(host->slot[i], i); } - clk_prepare_enable(host->mck); atmci_writel(host, ATMCI_IDR, ~0UL); atmci_writel(host, ATMCI_CR, ATMCI_CR_MCIDIS); atmci_readl(host, ATMCI_SR); - clk_disable_unprepare(host->mck); del_timer_sync(&host->timer); if (host->dma.chan) @@ -2539,14 +2553,44 @@ static int __exit atmci_remove(struct platform_device *pdev) free_irq(platform_get_irq(pdev, 0), host); + clk_disable_unprepare(host->mck); + + pm_runtime_disable(&pdev->dev); + pm_runtime_put_noidle(&pdev->dev); + + return 0; +} + +#ifdef CONFIG_PM +static int atmci_runtime_suspend(struct device *dev) +{ + struct atmel_mci *host = dev_get_drvdata(dev); + + clk_disable_unprepare(host->mck); + return 0; } +static int atmci_runtime_resume(struct device *dev) +{ + struct atmel_mci *host = dev_get_drvdata(dev); + + return clk_prepare_enable(host->mck); +} +#endif + +static const struct dev_pm_ops atmci_dev_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) + SET_PM_RUNTIME_PM_OPS(atmci_runtime_suspend, atmci_runtime_resume, NULL) +}; + static struct platform_driver atmci_driver = { .remove = __exit_p(atmci_remove), .driver = { .name = "atmel_mci", .of_match_table = of_match_ptr(atmci_dt_ids), + .pm = &atmci_dev_pm_ops, }, }; -- cgit v1.2.3-59-g8ed1b From cd0cfdd2485e6252b3c69284bf09d06c4d303116 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 4 Nov 2014 12:26:42 +0000 Subject: mmc: sdhci-s3c: Check if clk_set_rate() succeeds It is possible that we may fail to set the clock rate, if we do so then log the failure and don't bother reprogramming the IP. Signed-off-by: Mark Brown Acked-by: Jaehoon Chung Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-s3c.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/host/sdhci-s3c.c b/drivers/mmc/host/sdhci-s3c.c index 0ce6eb17deaf..4f7a63213b33 100644 --- a/drivers/mmc/host/sdhci-s3c.c +++ b/drivers/mmc/host/sdhci-s3c.c @@ -300,6 +300,7 @@ static void sdhci_cmu_set_clock(struct sdhci_host *host, unsigned int clock) struct device *dev = &ourhost->pdev->dev; unsigned long timeout; u16 clk = 0; + int ret; host->mmc->actual_clock = 0; @@ -311,7 +312,12 @@ static void sdhci_cmu_set_clock(struct sdhci_host *host, unsigned int clock) sdhci_s3c_set_clock(host, clock); - clk_set_rate(ourhost->clk_bus[ourhost->cur_clk], clock); + ret = clk_set_rate(ourhost->clk_bus[ourhost->cur_clk], clock); + if (ret != 0) { + dev_err(dev, "%s: failed to set clock rate %uHz\n", + mmc_hostname(host->mmc), clock); + return; + } clk = SDHCI_CLOCK_INT_EN; sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); -- cgit v1.2.3-59-g8ed1b From ad89fcb290b0b121a3de96d8c5d5f13a23663875 Mon Sep 17 00:00:00 2001 From: Johan Rudholm Date: Tue, 4 Nov 2014 16:07:03 +0100 Subject: mmc: core: use mmc_send_status to check hw_reset Signed-off-by: Johan Rudholm Signed-off-by: Ulf Hansson --- drivers/mmc/core/core.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 943f9051ec6d..a32bea23e70c 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -2270,15 +2270,9 @@ static int mmc_do_hw_reset(struct mmc_host *host, int check) /* If the reset has happened, then a status command will fail */ if (check) { - struct mmc_command cmd = {0}; - int err; + u32 status; - cmd.opcode = MMC_SEND_STATUS; - if (!mmc_host_is_spi(card->host)) - cmd.arg = card->rca << 16; - cmd.flags = MMC_RSP_SPI_R2 | MMC_RSP_R1 | MMC_CMD_AC; - err = mmc_wait_for_cmd(card->host, &cmd, 0); - if (!err) { + if (!mmc_send_status(card, &status)) { mmc_host_clk_release(host); return -ENOSYS; } -- cgit v1.2.3-59-g8ed1b From 9b8ffea6efb0d0edcac265a1ca422188fc1b6dfb Mon Sep 17 00:00:00 2001 From: Vincent Wan Date: Wed, 5 Nov 2014 14:09:00 +0800 Subject: mmc: sdhci: Add a quirk for AMD SDHC transfer mode register need to be cleared for cmd without data SDHC controller in AMD chipsets require SDHC transfer mode register to be cleared for commands without data. The issue was uncovered during testing eMMC cards on KB/ML based platforms Signed-off-by: Vincent Wan Signed-off-by: Wan Zongshun Signed-off-by: Arindam Nath Tested-by: Vikram B Tested-by: Raghavendra Swamy Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci.c | 9 +++++++-- include/linux/mmc/sdhci.h | 2 ++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index f895ab07fcc2..a743d5227eda 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -915,10 +915,15 @@ static void sdhci_set_transfer_mode(struct sdhci_host *host, struct mmc_data *data = cmd->data; if (data == NULL) { + if (host->quirks2 & + SDHCI_QUIRK2_CLEAR_TRANSFERMODE_REG_BEFORE_CMD) { + sdhci_writew(host, 0x0, SDHCI_TRANSFER_MODE); + } else { /* clear Auto CMD settings for no data CMDs */ - mode = sdhci_readw(host, SDHCI_TRANSFER_MODE); - sdhci_writew(host, mode & ~(SDHCI_TRNS_AUTO_CMD12 | + mode = sdhci_readw(host, SDHCI_TRANSFER_MODE); + sdhci_writew(host, mode & ~(SDHCI_TRNS_AUTO_CMD12 | SDHCI_TRNS_AUTO_CMD23), SDHCI_TRANSFER_MODE); + } return; } diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h index 931ac5e05453..ae7f357b78c9 100644 --- a/include/linux/mmc/sdhci.h +++ b/include/linux/mmc/sdhci.h @@ -102,6 +102,8 @@ struct sdhci_host { #define SDHCI_QUIRK2_STOP_WITH_TC (1<<8) /* Controller does not support 64-bit DMA */ #define SDHCI_QUIRK2_BROKEN_64_BIT_DMA (1<<9) +/* need clear transfer mode register before send cmd */ +#define SDHCI_QUIRK2_CLEAR_TRANSFERMODE_REG_BEFORE_CMD (1<<10) int irq; /* Device IRQ */ void __iomem *ioaddr; /* Mapped address */ -- cgit v1.2.3-59-g8ed1b From d44f88da42d2a75eeac02f87455043f44e10d7cc Mon Sep 17 00:00:00 2001 From: Vincent Wan Date: Wed, 5 Nov 2014 14:09:14 +0800 Subject: mmc: sdhci-pci: enable the clear transfer mode register quirk for AMD sdhci This patch is to enable the quirk for AMD sdhci requiring transfer mode register need to be cleared for commands without data Signed-off-by: Vincent Wan Signed-off-by: Wan Zongshun Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-pci.c | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c index c25639b839cd..5a77f188b503 100644 --- a/drivers/mmc/host/sdhci-pci.c +++ b/drivers/mmc/host/sdhci-pci.c @@ -645,6 +645,23 @@ static const struct sdhci_pci_fixes sdhci_rtsx = { .probe_slot = rtsx_probe_slot, }; +static int amd_probe(struct sdhci_pci_chip *chip) +{ + struct pci_dev *smbus_dev; + + smbus_dev = pci_get_device(PCI_VENDOR_ID_AMD, + PCI_DEVICE_ID_AMD_HUDSON2_SMBUS, NULL); + + if (smbus_dev && (smbus_dev->revision < 0x51)) + chip->quirks2 |= SDHCI_QUIRK2_CLEAR_TRANSFERMODE_REG_BEFORE_CMD; + + return 0; +} + +static const struct sdhci_pci_fixes sdhci_amd = { + .probe = amd_probe, +}; + static const struct pci_device_id pci_ids[] = { { .vendor = PCI_VENDOR_ID_RICOH, @@ -1044,7 +1061,15 @@ static const struct pci_device_id pci_ids[] = { .subdevice = PCI_ANY_ID, .driver_data = (kernel_ulong_t)&sdhci_o2, }, - + { + .vendor = PCI_VENDOR_ID_AMD, + .device = PCI_ANY_ID, + .class = PCI_CLASS_SYSTEM_SDHCI << 8, + .class_mask = 0xFFFF00, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = (kernel_ulong_t)&sdhci_amd, + }, { /* Generic SD host controller */ PCI_DEVICE_CLASS((PCI_CLASS_SYSTEM_SDHCI << 8), 0xFFFF00) }, -- cgit v1.2.3-59-g8ed1b From e765bfa22a8f06f0964a97e3e81148511d75140a Mon Sep 17 00:00:00 2001 From: Vincent Wan Date: Wed, 5 Nov 2014 14:09:28 +0800 Subject: mmc: sdhci-pci: enable sdhci doesn't support hs200 quirk for AMD sdhci AMD SD controller supports the SDR104 mode, but caps2 can not be promoted to support hs200 for eMMC. Signed-off-by: Vincent Wan Signed-off-by: Wan Zongshun Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-pci.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c index 5a77f188b503..c1ecd204c194 100644 --- a/drivers/mmc/host/sdhci-pci.c +++ b/drivers/mmc/host/sdhci-pci.c @@ -652,8 +652,10 @@ static int amd_probe(struct sdhci_pci_chip *chip) smbus_dev = pci_get_device(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_HUDSON2_SMBUS, NULL); - if (smbus_dev && (smbus_dev->revision < 0x51)) + if (smbus_dev && (smbus_dev->revision < 0x51)) { chip->quirks2 |= SDHCI_QUIRK2_CLEAR_TRANSFERMODE_REG_BEFORE_CMD; + chip->quirks2 |= SDHCI_QUIRK2_BROKEN_HS200; + } return 0; } -- cgit v1.2.3-59-g8ed1b From 69d99fdcfd7815dfb2318f0777a46181d5bf42dc Mon Sep 17 00:00:00 2001 From: Prabu Thangamuthu Date: Mon, 20 Oct 2014 07:12:33 +0000 Subject: mmc: dw_mmc: Add IDMAC 64-bit address mode support Synopsys DW_MMC IP core supports Internal DMA Controller with 64-bit address mode from IP version 2.70a onwards. Updated the driver to support IDMAC 64-bit addressing mode. Signed-off-by: Prabu Thangamuthu Reviewed-by: Alim Akhtar Acked-by: Jaehoon Chung Signed-off-by: Ulf Hansson --- drivers/mmc/host/dw_mmc.c | 199 ++++++++++++++++++++++++++++++++++++--------- drivers/mmc/host/dw_mmc.h | 11 +++ include/linux/mmc/dw_mmc.h | 2 + 3 files changed, 174 insertions(+), 38 deletions(-) diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index bb46b1b8d16b..5a37c33879a1 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -61,6 +61,24 @@ SDMMC_IDMAC_INT_FBE | SDMMC_IDMAC_INT_RI | \ SDMMC_IDMAC_INT_TI) +struct idmac_desc_64addr { + u32 des0; /* Control Descriptor */ + + u32 des1; /* Reserved */ + + u32 des2; /*Buffer sizes */ +#define IDMAC_64ADDR_SET_BUFFER1_SIZE(d, s) \ + ((d)->des2 = ((d)->des2 & 0x03ffe000) | ((s) & 0x1fff)) + + u32 des3; /* Reserved */ + + u32 des4; /* Lower 32-bits of Buffer Address Pointer 1*/ + u32 des5; /* Upper 32-bits of Buffer Address Pointer 1*/ + + u32 des6; /* Lower 32-bits of Next Descriptor Address */ + u32 des7; /* Upper 32-bits of Next Descriptor Address */ +}; + struct idmac_desc { u32 des0; /* Control Descriptor */ #define IDMAC_DES0_DIC BIT(1) @@ -414,30 +432,66 @@ static void dw_mci_translate_sglist(struct dw_mci *host, struct mmc_data *data, unsigned int sg_len) { int i; - struct idmac_desc *desc = host->sg_cpu; + if (host->dma_64bit_address == 1) { + struct idmac_desc_64addr *desc = host->sg_cpu; - for (i = 0; i < sg_len; i++, desc++) { - unsigned int length = sg_dma_len(&data->sg[i]); - u32 mem_addr = sg_dma_address(&data->sg[i]); + for (i = 0; i < sg_len; i++, desc++) { + unsigned int length = sg_dma_len(&data->sg[i]); + u64 mem_addr = sg_dma_address(&data->sg[i]); - /* Set the OWN bit and disable interrupts for this descriptor */ - desc->des0 = IDMAC_DES0_OWN | IDMAC_DES0_DIC | IDMAC_DES0_CH; + /* + * Set the OWN bit and disable interrupts for this + * descriptor + */ + desc->des0 = IDMAC_DES0_OWN | IDMAC_DES0_DIC | + IDMAC_DES0_CH; + /* Buffer length */ + IDMAC_64ADDR_SET_BUFFER1_SIZE(desc, length); + + /* Physical address to DMA to/from */ + desc->des4 = mem_addr & 0xffffffff; + desc->des5 = mem_addr >> 32; + } - /* Buffer length */ - IDMAC_SET_BUFFER1_SIZE(desc, length); + /* Set first descriptor */ + desc = host->sg_cpu; + desc->des0 |= IDMAC_DES0_FD; - /* Physical address to DMA to/from */ - desc->des2 = mem_addr; - } + /* Set last descriptor */ + desc = host->sg_cpu + (i - 1) * + sizeof(struct idmac_desc_64addr); + desc->des0 &= ~(IDMAC_DES0_CH | IDMAC_DES0_DIC); + desc->des0 |= IDMAC_DES0_LD; + + } else { + struct idmac_desc *desc = host->sg_cpu; + + for (i = 0; i < sg_len; i++, desc++) { + unsigned int length = sg_dma_len(&data->sg[i]); + u32 mem_addr = sg_dma_address(&data->sg[i]); + + /* + * Set the OWN bit and disable interrupts for this + * descriptor + */ + desc->des0 = IDMAC_DES0_OWN | IDMAC_DES0_DIC | + IDMAC_DES0_CH; + /* Buffer length */ + IDMAC_SET_BUFFER1_SIZE(desc, length); + + /* Physical address to DMA to/from */ + desc->des2 = mem_addr; + } - /* Set first descriptor */ - desc = host->sg_cpu; - desc->des0 |= IDMAC_DES0_FD; + /* Set first descriptor */ + desc = host->sg_cpu; + desc->des0 |= IDMAC_DES0_FD; - /* Set last descriptor */ - desc = host->sg_cpu + (i - 1) * sizeof(struct idmac_desc); - desc->des0 &= ~(IDMAC_DES0_CH | IDMAC_DES0_DIC); - desc->des0 |= IDMAC_DES0_LD; + /* Set last descriptor */ + desc = host->sg_cpu + (i - 1) * sizeof(struct idmac_desc); + desc->des0 &= ~(IDMAC_DES0_CH | IDMAC_DES0_DIC); + desc->des0 |= IDMAC_DES0_LD; + } wmb(); } @@ -470,29 +524,71 @@ static void dw_mci_idmac_start_dma(struct dw_mci *host, unsigned int sg_len) static int dw_mci_idmac_init(struct dw_mci *host) { - struct idmac_desc *p; int i; - /* Number of descriptors in the ring buffer */ - host->ring_size = PAGE_SIZE / sizeof(struct idmac_desc); + if (host->dma_64bit_address == 1) { + struct idmac_desc_64addr *p; + /* Number of descriptors in the ring buffer */ + host->ring_size = PAGE_SIZE / sizeof(struct idmac_desc_64addr); + + /* Forward link the descriptor list */ + for (i = 0, p = host->sg_cpu; i < host->ring_size - 1; + i++, p++) { + p->des6 = (host->sg_dma + + (sizeof(struct idmac_desc_64addr) * + (i + 1))) & 0xffffffff; + + p->des7 = (u64)(host->sg_dma + + (sizeof(struct idmac_desc_64addr) * + (i + 1))) >> 32; + /* Initialize reserved and buffer size fields to "0" */ + p->des1 = 0; + p->des2 = 0; + p->des3 = 0; + } + + /* Set the last descriptor as the end-of-ring descriptor */ + p->des6 = host->sg_dma & 0xffffffff; + p->des7 = (u64)host->sg_dma >> 32; + p->des0 = IDMAC_DES0_ER; + + } else { + struct idmac_desc *p; + /* Number of descriptors in the ring buffer */ + host->ring_size = PAGE_SIZE / sizeof(struct idmac_desc); - /* Forward link the descriptor list */ - for (i = 0, p = host->sg_cpu; i < host->ring_size - 1; i++, p++) - p->des3 = host->sg_dma + (sizeof(struct idmac_desc) * (i + 1)); + /* Forward link the descriptor list */ + for (i = 0, p = host->sg_cpu; i < host->ring_size - 1; i++, p++) + p->des3 = host->sg_dma + (sizeof(struct idmac_desc) * + (i + 1)); - /* Set the last descriptor as the end-of-ring descriptor */ - p->des3 = host->sg_dma; - p->des0 = IDMAC_DES0_ER; + /* Set the last descriptor as the end-of-ring descriptor */ + p->des3 = host->sg_dma; + p->des0 = IDMAC_DES0_ER; + } dw_mci_idmac_reset(host); - /* Mask out interrupts - get Tx & Rx complete only */ - mci_writel(host, IDSTS, IDMAC_INT_CLR); - mci_writel(host, IDINTEN, SDMMC_IDMAC_INT_NI | SDMMC_IDMAC_INT_RI | - SDMMC_IDMAC_INT_TI); + if (host->dma_64bit_address == 1) { + /* Mask out interrupts - get Tx & Rx complete only */ + mci_writel(host, IDSTS64, IDMAC_INT_CLR); + mci_writel(host, IDINTEN64, SDMMC_IDMAC_INT_NI | + SDMMC_IDMAC_INT_RI | SDMMC_IDMAC_INT_TI); + + /* Set the descriptor base address */ + mci_writel(host, DBADDRL, host->sg_dma & 0xffffffff); + mci_writel(host, DBADDRU, (u64)host->sg_dma >> 32); + + } else { + /* Mask out interrupts - get Tx & Rx complete only */ + mci_writel(host, IDSTS, IDMAC_INT_CLR); + mci_writel(host, IDINTEN, SDMMC_IDMAC_INT_NI | + SDMMC_IDMAC_INT_RI | SDMMC_IDMAC_INT_TI); + + /* Set the descriptor base address */ + mci_writel(host, DBADDR, host->sg_dma); + } - /* Set the descriptor base address */ - mci_writel(host, DBADDR, host->sg_dma); return 0; } @@ -2066,11 +2162,22 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id) #ifdef CONFIG_MMC_DW_IDMAC /* Handle DMA interrupts */ - pending = mci_readl(host, IDSTS); - if (pending & (SDMMC_IDMAC_INT_TI | SDMMC_IDMAC_INT_RI)) { - mci_writel(host, IDSTS, SDMMC_IDMAC_INT_TI | SDMMC_IDMAC_INT_RI); - mci_writel(host, IDSTS, SDMMC_IDMAC_INT_NI); - host->dma_ops->complete(host); + if (host->dma_64bit_address == 1) { + pending = mci_readl(host, IDSTS64); + if (pending & (SDMMC_IDMAC_INT_TI | SDMMC_IDMAC_INT_RI)) { + mci_writel(host, IDSTS64, SDMMC_IDMAC_INT_TI | + SDMMC_IDMAC_INT_RI); + mci_writel(host, IDSTS64, SDMMC_IDMAC_INT_NI); + host->dma_ops->complete(host); + } + } else { + pending = mci_readl(host, IDSTS); + if (pending & (SDMMC_IDMAC_INT_TI | SDMMC_IDMAC_INT_RI)) { + mci_writel(host, IDSTS, SDMMC_IDMAC_INT_TI | + SDMMC_IDMAC_INT_RI); + mci_writel(host, IDSTS, SDMMC_IDMAC_INT_NI); + host->dma_ops->complete(host); + } } #endif @@ -2245,6 +2352,22 @@ static void dw_mci_cleanup_slot(struct dw_mci_slot *slot, unsigned int id) static void dw_mci_init_dma(struct dw_mci *host) { + int addr_config; + /* Check ADDR_CONFIG bit in HCON to find IDMAC address bus width */ + addr_config = (mci_readl(host, HCON) >> 27) & 0x01; + + if (addr_config == 1) { + /* host supports IDMAC in 64-bit address mode */ + host->dma_64bit_address = 1; + dev_info(host->dev, "IDMAC supports 64-bit address mode.\n"); + if (!dma_set_mask(host->dev, DMA_BIT_MASK(64))) + dma_set_coherent_mask(host->dev, DMA_BIT_MASK(64)); + } else { + /* host supports IDMAC in 32-bit address mode */ + host->dma_64bit_address = 0; + dev_info(host->dev, "IDMAC supports 32-bit address mode.\n"); + } + /* Alloc memory for sg translation */ host->sg_cpu = dmam_alloc_coherent(host->dev, PAGE_SIZE, &host->sg_dma, GFP_KERNEL); diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h index 71d499557edc..58d8a54d644b 100644 --- a/drivers/mmc/host/dw_mmc.h +++ b/drivers/mmc/host/dw_mmc.h @@ -55,6 +55,17 @@ #define SDMMC_BUFADDR 0x098 #define SDMMC_CDTHRCTL 0x100 #define SDMMC_DATA(x) (x) +/* +* Registers to support idmac 64-bit address mode +*/ +#define SDMMC_DBADDRL 0x088 +#define SDMMC_DBADDRU 0x08c +#define SDMMC_IDSTS64 0x090 +#define SDMMC_IDINTEN64 0x094 +#define SDMMC_DSCADDRL 0x098 +#define SDMMC_DSCADDRU 0x09c +#define SDMMC_BUFADDRL 0x0A0 +#define SDMMC_BUFADDRU 0x0A4 /* * Data offset is difference according to Version diff --git a/include/linux/mmc/dw_mmc.h b/include/linux/mmc/dw_mmc.h index 69d08144cfad..0a551152d600 100644 --- a/include/linux/mmc/dw_mmc.h +++ b/include/linux/mmc/dw_mmc.h @@ -54,6 +54,7 @@ struct mmc_data; * transfer is in progress. * @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. @@ -139,6 +140,7 @@ struct dw_mci { /* DMA interface members*/ int use_dma; int using_dma; + int dma_64bit_address; dma_addr_t sg_dma; void *sg_cpu; -- cgit v1.2.3-59-g8ed1b From 04834a78bd2b40dbd8396382210db8707aecf281 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Thu, 6 Nov 2014 15:19:03 +0200 Subject: mmc: sdhci: Remove unused SDHCI_CTRL_HS_SDR200 SDHCI_CTRL_HS_SDR200 is unused. Remove it. Signed-off-by: Adrian Hunter Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci.h | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index c2ec7fcd8a1f..79937cfff4ca 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -161,7 +161,6 @@ #define SDHCI_CTRL_UHS_SDR50 0x0002 #define SDHCI_CTRL_UHS_SDR104 0x0003 #define SDHCI_CTRL_UHS_DDR50 0x0004 -#define SDHCI_CTRL_HS_SDR200 0x0005 /* reserved value in SDIO spec */ #define SDHCI_CTRL_VDD_180 0x0008 #define SDHCI_CTRL_DRV_TYPE_MASK 0x0030 #define SDHCI_CTRL_DRV_TYPE_B 0x0000 -- cgit v1.2.3-59-g8ed1b From 4bb74313b3549f5c0c28c4652cae2cee1c2b9c95 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Thu, 6 Nov 2014 15:19:04 +0200 Subject: mmc: sdhci: Fix vqmmc error setting supply.vqmmc is used with the IS_ERR macro which means the value must be valid or an error code. NULL is neither, so replace with ERR_PTR(-EINVAL). Signed-off-by: Adrian Hunter Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index a743d5227eda..c2f4754a28b6 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -3096,7 +3096,7 @@ int sdhci_add_host(struct sdhci_host *host) if (ret) { pr_warn("%s: Failed to enable vqmmc regulator: %d\n", mmc_hostname(mmc), ret); - mmc->supply.vqmmc = NULL; + mmc->supply.vqmmc = ERR_PTR(-EINVAL); } } -- cgit v1.2.3-59-g8ed1b From 549c0b18485d10bb419a81b24efe719df75089bd Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Thu, 6 Nov 2014 15:19:05 +0200 Subject: mmc: sdhci: Clear also HS400 1.2V capability if 1.2V is not supported 1.2V HS200 mode capability is cleared if there is not a voltage regulator that supports 1.2V. Do the same for 1.2V HS400 mode. Signed-off-by: Adrian Hunter Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci.c | 13 +++++++------ include/linux/mmc/host.h | 1 + 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index c2f4754a28b6..5589563761f8 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -3115,16 +3115,17 @@ int sdhci_add_host(struct sdhci_host *host) /* SD3.0: SDR104 is supported so (for eMMC) the caps2 * field can be promoted to support HS200. */ - if (!(host->quirks2 & SDHCI_QUIRK2_BROKEN_HS200)) { + if (!(host->quirks2 & SDHCI_QUIRK2_BROKEN_HS200)) mmc->caps2 |= MMC_CAP2_HS200; - if (IS_ERR(mmc->supply.vqmmc) || - !regulator_is_supported_voltage - (mmc->supply.vqmmc, 1100000, 1300000)) - mmc->caps2 &= ~MMC_CAP2_HS200_1_2V_SDR; - } } else if (caps[1] & SDHCI_SUPPORT_SDR50) mmc->caps |= MMC_CAP_UHS_SDR50; + if ((mmc->caps2 & MMC_CAP2_HSX00_1_2V) && + (IS_ERR(mmc->supply.vqmmc) || + !regulator_is_supported_voltage(mmc->supply.vqmmc, 1100000, + 1300000))) + mmc->caps2 &= ~MMC_CAP2_HSX00_1_2V; + if ((caps[1] & SDHCI_SUPPORT_DDR50) && !(host->quirks2 & SDHCI_QUIRK2_BROKEN_DDR50)) mmc->caps |= MMC_CAP_UHS_DDR50; diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index df0c15396bbf..9f322706f7cb 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -289,6 +289,7 @@ struct mmc_host { #define MMC_CAP2_HS400_1_2V (1 << 16) /* Can support HS400 1.2V */ #define MMC_CAP2_HS400 (MMC_CAP2_HS400_1_8V | \ MMC_CAP2_HS400_1_2V) +#define MMC_CAP2_HSX00_1_2V (MMC_CAP2_HS200_1_2V_SDR | MMC_CAP2_HS400_1_2V) #define MMC_CAP2_SDIO_IRQ_NOTHREAD (1 << 17) mmc_pm_flag_t pm_caps; /* supported pm features */ -- cgit v1.2.3-59-g8ed1b From e9fb05d5bca7428f2749d059559e9657c710fe53 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Thu, 6 Nov 2014 15:19:06 +0200 Subject: mmc: sdhci: Add HS400 support to SDHCI driver MMC core already has support for HS400. Add HS400 support to SDHCI driver. The SDHC Standard specification does not define HS400 so consequently HS400 support is non-standard. However HS400 is not selected without the host controller setting the corresponding capability flags so host controllers not yet supporting HS400 will not be affected. To support that, a quirk SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400 is introduced to enable the use of capabilities register reserved bit-63 to indicate HS400 support. Because HS400 is non-standard for SDHCI, it is possible that different vendors will do things in different ways. However HS200 support faced the same issue but currently there is only one solution. As such, no attempt has been made to provide for alternate HS400 solutions except for SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400. Signed-off-by: Adrian Hunter Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci.c | 13 ++++++++++++- drivers/mmc/host/sdhci.h | 3 +++ include/linux/mmc/sdhci.h | 2 ++ 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 5589563761f8..73de62a58d70 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -1148,6 +1148,9 @@ static u16 sdhci_get_preset_value(struct sdhci_host *host) case MMC_TIMING_UHS_DDR50: preset = sdhci_readw(host, SDHCI_PRESET_FOR_DDR50); break; + case MMC_TIMING_MMC_HS400: + preset = sdhci_readw(host, SDHCI_PRESET_FOR_HS400); + break; default: pr_warn("%s: Invalid UHS-I mode selected\n", mmc_hostname(host->mmc)); @@ -1475,6 +1478,8 @@ void sdhci_set_uhs_signaling(struct sdhci_host *host, unsigned timing) else if ((timing == MMC_TIMING_UHS_DDR50) || (timing == MMC_TIMING_MMC_DDR52)) ctrl_2 |= SDHCI_CTRL_UHS_DDR50; + else if (timing == MMC_TIMING_MMC_HS400) + ctrl_2 |= SDHCI_CTRL_HS400; /* Non-standard */ sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2); } EXPORT_SYMBOL_GPL(sdhci_set_uhs_signaling); @@ -1546,7 +1551,8 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios) u16 clk, ctrl_2; /* In case of UHS-I modes, set High Speed Enable */ - if ((ios->timing == MMC_TIMING_MMC_HS200) || + if ((ios->timing == MMC_TIMING_MMC_HS400) || + (ios->timing == MMC_TIMING_MMC_HS200) || (ios->timing == MMC_TIMING_MMC_DDR52) || (ios->timing == MMC_TIMING_UHS_SDR50) || (ios->timing == MMC_TIMING_UHS_SDR104) || @@ -1893,6 +1899,7 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode) * tuning function has to be executed. */ switch (host->timing) { + case MMC_TIMING_MMC_HS400: case MMC_TIMING_MMC_HS200: case MMC_TIMING_UHS_SDR104: break; @@ -3120,6 +3127,10 @@ int sdhci_add_host(struct sdhci_host *host) } else if (caps[1] & SDHCI_SUPPORT_SDR50) mmc->caps |= MMC_CAP_UHS_SDR50; + if (host->quirks2 & SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400 && + (caps[1] & SDHCI_SUPPORT_HS400)) + mmc->caps2 |= MMC_CAP2_HS400; + if ((mmc->caps2 & MMC_CAP2_HSX00_1_2V) && (IS_ERR(mmc->supply.vqmmc) || !regulator_is_supported_voltage(mmc->supply.vqmmc, 1100000, diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index 79937cfff4ca..ddd31cda2370 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -161,6 +161,7 @@ #define SDHCI_CTRL_UHS_SDR50 0x0002 #define SDHCI_CTRL_UHS_SDR104 0x0003 #define SDHCI_CTRL_UHS_DDR50 0x0004 +#define SDHCI_CTRL_HS400 0x0005 /* Non-standard */ #define SDHCI_CTRL_VDD_180 0x0008 #define SDHCI_CTRL_DRV_TYPE_MASK 0x0030 #define SDHCI_CTRL_DRV_TYPE_B 0x0000 @@ -203,6 +204,7 @@ #define SDHCI_RETUNING_MODE_SHIFT 14 #define SDHCI_CLOCK_MUL_MASK 0x00FF0000 #define SDHCI_CLOCK_MUL_SHIFT 16 +#define SDHCI_SUPPORT_HS400 0x80000000 /* Non-standard */ #define SDHCI_CAPABILITIES_1 0x44 @@ -235,6 +237,7 @@ #define SDHCI_PRESET_FOR_SDR50 0x6A #define SDHCI_PRESET_FOR_SDR104 0x6C #define SDHCI_PRESET_FOR_DDR50 0x6E +#define SDHCI_PRESET_FOR_HS400 0x74 /* Non-standard */ #define SDHCI_PRESET_DRV_MASK 0xC000 #define SDHCI_PRESET_DRV_SHIFT 14 #define SDHCI_PRESET_CLKGEN_SEL_MASK 0x400 diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h index ae7f357b78c9..375af80bde7d 100644 --- a/include/linux/mmc/sdhci.h +++ b/include/linux/mmc/sdhci.h @@ -104,6 +104,8 @@ struct sdhci_host { #define SDHCI_QUIRK2_BROKEN_64_BIT_DMA (1<<9) /* need clear transfer mode register before send cmd */ #define SDHCI_QUIRK2_CLEAR_TRANSFERMODE_REG_BEFORE_CMD (1<<10) +/* Capability register bit-63 indicates HS400 support */ +#define SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400 (1<<11) int irq; /* Device IRQ */ void __iomem *ioaddr; /* Mapped address */ -- cgit v1.2.3-59-g8ed1b From b5b64fa6cd6bd053db2b89a41792597d08913036 Mon Sep 17 00:00:00 2001 From: Wenyou Yang Date: Fri, 7 Nov 2014 08:48:13 +0800 Subject: mmc: atmel-mci: adopt pinctrl support Amend the atmel mci pin controller to optionally take a pin control handle and set the state of the pins to: - "default" on boot, resume and before performing an transfer. - "sleep" on suspend(). This should make it possible to optimize energy usage for the pins both for the suspend/resume cycle. Signed-off-by: Wenyou Yang Signed-off-by: Ulf Hansson --- drivers/mmc/host/atmel-mci.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c index 4df1599583f8..a7b59ba399a1 100644 --- a/drivers/mmc/host/atmel-mci.c +++ b/drivers/mmc/host/atmel-mci.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include @@ -2568,6 +2569,8 @@ static int atmci_runtime_suspend(struct device *dev) clk_disable_unprepare(host->mck); + pinctrl_pm_select_sleep_state(dev); + return 0; } @@ -2575,6 +2578,8 @@ static int atmci_runtime_resume(struct device *dev) { struct atmel_mci *host = dev_get_drvdata(dev); + pinctrl_pm_select_default_state(dev); + return clk_prepare_enable(host->mck); } #endif -- cgit v1.2.3-59-g8ed1b From 826c71a06588675a797534220364ed74df6188c0 Mon Sep 17 00:00:00 2001 From: Andreas Fenkart Date: Sat, 8 Nov 2014 15:33:08 +0100 Subject: ARM: OMAP2: MMC: include mmc-omap platform header directly Only a few files really need that platform header. When later splitting omap_mmc_platform_data into omap_mmc and omap_mmc_hs, those files declaring an hs mmc platform data will have to change the platform include, which is a good sanity check. Also removing omap242x_init_mmc, which is not used anywhere, checked with grep. Signed-off-by: Andreas Fenkart Signed-off-by: Ulf Hansson --- arch/arm/mach-omap2/board-n8x0.c | 2 ++ arch/arm/mach-omap2/hsmmc.c | 3 ++- arch/arm/mach-omap2/mmc.h | 10 ---------- arch/arm/mach-omap2/omap4-common.c | 1 - arch/arm/mach-omap2/omap_hwmod_2430_data.c | 2 +- arch/arm/mach-omap2/omap_hwmod_33xx_43xx_ipblock_data.c | 2 +- arch/arm/mach-omap2/omap_hwmod_33xx_data.c | 1 - arch/arm/mach-omap2/omap_hwmod_3xxx_data.c | 2 +- arch/arm/mach-omap2/omap_hwmod_44xx_data.c | 2 +- arch/arm/mach-omap2/omap_hwmod_54xx_data.c | 2 +- arch/arm/mach-omap2/omap_hwmod_7xx_data.c | 2 +- 11 files changed, 10 insertions(+), 19 deletions(-) diff --git a/arch/arm/mach-omap2/board-n8x0.c b/arch/arm/mach-omap2/board-n8x0.c index 97767a27ca9d..e0ad64fde20e 100644 --- a/arch/arm/mach-omap2/board-n8x0.c +++ b/arch/arm/mach-omap2/board-n8x0.c @@ -21,8 +21,10 @@ #include #include #include +#include #include #include +#include #include #include diff --git a/arch/arm/mach-omap2/hsmmc.c b/arch/arm/mach-omap2/hsmmc.c index 07d4c7b35754..73e28ac45d99 100644 --- a/arch/arm/mach-omap2/hsmmc.c +++ b/arch/arm/mach-omap2/hsmmc.c @@ -14,14 +14,15 @@ #include #include #include +#include #include +#include #include "soc.h" #include "omap_device.h" #include "omap-pm.h" #include "mux.h" -#include "mmc.h" #include "hsmmc.h" #include "control.h" diff --git a/arch/arm/mach-omap2/mmc.h b/arch/arm/mach-omap2/mmc.h index 0cd4b089da9c..30d39b97e7dd 100644 --- a/arch/arm/mach-omap2/mmc.h +++ b/arch/arm/mach-omap2/mmc.h @@ -1,5 +1,3 @@ -#include -#include #define OMAP24XX_NR_MMC 2 #define OMAP2420_MMC_SIZE OMAP1_MMC_SIZE @@ -7,14 +5,6 @@ #define OMAP4_MMC_REG_OFFSET 0x100 -#if defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE) -void omap242x_init_mmc(struct omap_mmc_platform_data **mmc_data); -#else -static inline void omap242x_init_mmc(struct omap_mmc_platform_data **mmc_data) -{ -} -#endif - struct omap_hwmod; int omap_msdi_reset(struct omap_hwmod *oh); diff --git a/arch/arm/mach-omap2/omap4-common.c b/arch/arm/mach-omap2/omap4-common.c index 16b20cedc38d..b7cb44abe49b 100644 --- a/arch/arm/mach-omap2/omap4-common.c +++ b/arch/arm/mach-omap2/omap4-common.c @@ -36,7 +36,6 @@ #include "soc.h" #include "iomap.h" #include "common.h" -#include "mmc.h" #include "prminst44xx.h" #include "prcm_mpu44xx.h" #include "omap4-sar-layout.h" diff --git a/arch/arm/mach-omap2/omap_hwmod_2430_data.c b/arch/arm/mach-omap2/omap_hwmod_2430_data.c index c2555cb95e71..cd95e820c6d4 100644 --- a/arch/arm/mach-omap2/omap_hwmod_2430_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_2430_data.c @@ -15,12 +15,12 @@ #include #include +#include #include #include #include #include "omap_hwmod.h" -#include "mmc.h" #include "l3_2xxx.h" #include "soc.h" diff --git a/arch/arm/mach-omap2/omap_hwmod_33xx_43xx_ipblock_data.c b/arch/arm/mach-omap2/omap_hwmod_33xx_43xx_ipblock_data.c index a579b89ce9b7..bf8c12d595bf 100644 --- a/arch/arm/mach-omap2/omap_hwmod_33xx_43xx_ipblock_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_33xx_43xx_ipblock_data.c @@ -15,10 +15,10 @@ */ #include +#include #include #include "omap_hwmod.h" #include "i2c.h" -#include "mmc.h" #include "wd_timer.h" #include "cm33xx.h" #include "prm33xx.h" diff --git a/arch/arm/mach-omap2/omap_hwmod_33xx_data.c b/arch/arm/mach-omap2/omap_hwmod_33xx_data.c index 6b406ca4bd3b..0cf7b563dcd1 100644 --- a/arch/arm/mach-omap2/omap_hwmod_33xx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_33xx_data.c @@ -27,7 +27,6 @@ #include "prm33xx.h" #include "prm-regbits-33xx.h" #include "i2c.h" -#include "mmc.h" #include "wd_timer.h" #include "omap_hwmod_33xx_43xx_common_data.h" diff --git a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c index 2a78b093c0ce..5f244a90eee5 100644 --- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include "l3_3xxx.h" @@ -37,7 +38,6 @@ #include "cm-regbits-34xx.h" #include "i2c.h" -#include "mmc.h" #include "wd_timer.h" #include "serial.h" diff --git a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c index 44e5634bba34..c385185c755d 100644 --- a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c @@ -22,6 +22,7 @@ #include #include +#include #include #include @@ -39,7 +40,6 @@ #include "prm44xx.h" #include "prm-regbits-44xx.h" #include "i2c.h" -#include "mmc.h" #include "wd_timer.h" /* Base offset for all OMAP4 interrupts external to MPUSS */ diff --git a/arch/arm/mach-omap2/omap_hwmod_54xx_data.c b/arch/arm/mach-omap2/omap_hwmod_54xx_data.c index 1103aa0e0d29..13bf6a72c5ee 100644 --- a/arch/arm/mach-omap2/omap_hwmod_54xx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_54xx_data.c @@ -19,6 +19,7 @@ #include #include +#include #include #include @@ -33,7 +34,6 @@ #include "cm2_54xx.h" #include "prm54xx.h" #include "i2c.h" -#include "mmc.h" #include "wd_timer.h" /* Base offset for all OMAP5 interrupts external to MPUSS */ diff --git a/arch/arm/mach-omap2/omap_hwmod_7xx_data.c b/arch/arm/mach-omap2/omap_hwmod_7xx_data.c index 5684f112654b..8523821fe78f 100644 --- a/arch/arm/mach-omap2/omap_hwmod_7xx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_7xx_data.c @@ -19,6 +19,7 @@ #include #include +#include #include #include @@ -33,7 +34,6 @@ #include "cm2_7xx.h" #include "prm7xx.h" #include "i2c.h" -#include "mmc.h" #include "wd_timer.h" #include "soc.h" -- cgit v1.2.3-59-g8ed1b From 551434389074791da30b7afbf44c4bbe9b8b0116 Mon Sep 17 00:00:00 2001 From: Andreas Fenkart Date: Sat, 8 Nov 2014 15:33:09 +0100 Subject: ARM: OMAP1/2+: MMC: separate platform data for mmc and mmc hs driver - omap mmc driver supports multiplexing, omap_mmc_hs doesn't this leads to one of the major confusions in the omap_hsmmc driver - platform data should be read-only for the driver most callbacks are not set by the omap3 platform init code while still required. So they are set from the driver probe function, which is against the paradigm that platform-data should not be modified by the driver typical examples are card_detect, read_only callbacks un-bundling by searching for driver name \"omap_hsmmc in the arch/arm folder. omap_hsmmc_platform_data is not initialized directly, but from omap2_hsmmc_info, which is defined in a separate header file not touched by this patch hwmod includes platform headers to declare features of the platform. All the declared features are prefixed OMAP_HSMMC. There is no need to include platform header from hwmod other except for feature defines Acked-by: Tony Lindgren Signed-off-by: Andreas Fenkart Signed-off-by: Ulf Hansson --- arch/arm/mach-omap2/hsmmc.c | 26 ++-- arch/arm/mach-omap2/omap_hwmod_2430_data.c | 4 +- .../mach-omap2/omap_hwmod_33xx_43xx_ipblock_data.c | 8 +- arch/arm/mach-omap2/omap_hwmod_3xxx_data.c | 8 +- arch/arm/mach-omap2/omap_hwmod_44xx_data.c | 4 +- arch/arm/mach-omap2/omap_hwmod_54xx_data.c | 4 +- arch/arm/mach-omap2/omap_hwmod_7xx_data.c | 4 +- drivers/mmc/host/omap_hsmmc.c | 28 ++-- include/linux/platform_data/hsmmc-omap.h | 149 +++++++++++++++++++++ include/linux/platform_data/mmc-omap.h | 27 ---- 10 files changed, 192 insertions(+), 70 deletions(-) create mode 100644 include/linux/platform_data/hsmmc-omap.h diff --git a/arch/arm/mach-omap2/hsmmc.c b/arch/arm/mach-omap2/hsmmc.c index 73e28ac45d99..9edd7596d1e7 100644 --- a/arch/arm/mach-omap2/hsmmc.c +++ b/arch/arm/mach-omap2/hsmmc.c @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include "soc.h" #include "omap_device.h" @@ -48,7 +48,7 @@ static void omap_hsmmc1_before_set_reg(struct device *dev, int slot, int power_on, int vdd) { u32 reg, prog_io; - struct omap_mmc_platform_data *mmc = dev->platform_data; + struct omap_hsmmc_platform_data *mmc = dev->platform_data; if (mmc->slots[0].remux) mmc->slots[0].remux(dev, slot, power_on); @@ -121,7 +121,7 @@ static void omap_hsmmc1_after_set_reg(struct device *dev, int slot, } } -static void hsmmc2_select_input_clk_src(struct omap_mmc_platform_data *mmc) +static void hsmmc2_select_input_clk_src(struct omap_hsmmc_platform_data *mmc) { u32 reg; @@ -136,7 +136,7 @@ static void hsmmc2_select_input_clk_src(struct omap_mmc_platform_data *mmc) static void hsmmc2_before_set_reg(struct device *dev, int slot, int power_on, int vdd) { - struct omap_mmc_platform_data *mmc = dev->platform_data; + struct omap_hsmmc_platform_data *mmc = dev->platform_data; if (mmc->slots[0].remux) mmc->slots[0].remux(dev, slot, power_on); @@ -148,7 +148,7 @@ static void hsmmc2_before_set_reg(struct device *dev, int slot, static int am35x_hsmmc2_set_power(struct device *dev, int slot, int power_on, int vdd) { - struct omap_mmc_platform_data *mmc = dev->platform_data; + struct omap_hsmmc_platform_data *mmc = dev->platform_data; if (power_on) hsmmc2_select_input_clk_src(mmc); @@ -162,8 +162,8 @@ static int nop_mmc_set_power(struct device *dev, int slot, int power_on, return 0; } -static inline void omap_hsmmc_mux(struct omap_mmc_platform_data *mmc_controller, - int controller_nr) +static inline void omap_hsmmc_mux(struct omap_hsmmc_platform_data + *mmc_controller, int controller_nr) { if (gpio_is_valid(mmc_controller->slots[0].switch_pin) && (mmc_controller->slots[0].switch_pin < OMAP_MAX_GPIO_LINES)) @@ -244,7 +244,7 @@ static inline void omap_hsmmc_mux(struct omap_mmc_platform_data *mmc_controller, } static int __init omap_hsmmc_pdata_init(struct omap2_hsmmc_info *c, - struct omap_mmc_platform_data *mmc) + struct omap_hsmmc_platform_data *mmc) { char *hc_name; @@ -369,7 +369,7 @@ static int omap_hsmmc_done; void omap_hsmmc_late_init(struct omap2_hsmmc_info *c) { struct platform_device *pdev; - struct omap_mmc_platform_data *mmc_pdata; + struct omap_hsmmc_platform_data *mmc_pdata; int res; if (omap_hsmmc_done != 1) @@ -409,12 +409,12 @@ static void __init omap_hsmmc_init_one(struct omap2_hsmmc_info *hsmmcinfo, struct omap_device *od; struct platform_device *pdev; char oh_name[MAX_OMAP_MMC_HWMOD_NAME_LEN]; - struct omap_mmc_platform_data *mmc_data; - struct omap_mmc_dev_attr *mmc_dev_attr; + struct omap_hsmmc_platform_data *mmc_data; + struct omap_hsmmc_dev_attr *mmc_dev_attr; char *name; int res; - mmc_data = kzalloc(sizeof(struct omap_mmc_platform_data), GFP_KERNEL); + mmc_data = kzalloc(sizeof(*mmc_data), GFP_KERNEL); if (!mmc_data) { pr_err("Cannot allocate memory for mmc device!\n"); return; @@ -464,7 +464,7 @@ static void __init omap_hsmmc_init_one(struct omap2_hsmmc_info *hsmmcinfo, } res = platform_device_add_data(pdev, mmc_data, - sizeof(struct omap_mmc_platform_data)); + sizeof(struct omap_hsmmc_platform_data)); if (res) { pr_err("Could not add pdata for %s\n", name); goto put_pdev; diff --git a/arch/arm/mach-omap2/omap_hwmod_2430_data.c b/arch/arm/mach-omap2/omap_hwmod_2430_data.c index cd95e820c6d4..79127b35fe60 100644 --- a/arch/arm/mach-omap2/omap_hwmod_2430_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_2430_data.c @@ -15,7 +15,7 @@ #include #include -#include +#include #include #include #include @@ -372,7 +372,7 @@ static struct omap_hwmod_opt_clk omap2430_mmc1_opt_clks[] = { { .role = "dbck", .clk = "mmchsdb1_fck" }, }; -static struct omap_mmc_dev_attr mmc1_dev_attr = { +static struct omap_hsmmc_dev_attr mmc1_dev_attr = { .flags = OMAP_HSMMC_SUPPORTS_DUAL_VOLT, }; diff --git a/arch/arm/mach-omap2/omap_hwmod_33xx_43xx_ipblock_data.c b/arch/arm/mach-omap2/omap_hwmod_33xx_43xx_ipblock_data.c index bf8c12d595bf..cabc5695b504 100644 --- a/arch/arm/mach-omap2/omap_hwmod_33xx_43xx_ipblock_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_33xx_43xx_ipblock_data.c @@ -15,7 +15,7 @@ */ #include -#include +#include #include #include "omap_hwmod.h" #include "i2c.h" @@ -836,7 +836,7 @@ static struct omap_hwmod_class am33xx_mmc_hwmod_class = { }; /* mmc0 */ -static struct omap_mmc_dev_attr am33xx_mmc0_dev_attr = { +static struct omap_hsmmc_dev_attr am33xx_mmc0_dev_attr = { .flags = OMAP_HSMMC_SUPPORTS_DUAL_VOLT, }; @@ -854,7 +854,7 @@ struct omap_hwmod am33xx_mmc0_hwmod = { }; /* mmc1 */ -static struct omap_mmc_dev_attr am33xx_mmc1_dev_attr = { +static struct omap_hsmmc_dev_attr am33xx_mmc1_dev_attr = { .flags = OMAP_HSMMC_SUPPORTS_DUAL_VOLT, }; @@ -872,7 +872,7 @@ struct omap_hwmod am33xx_mmc1_hwmod = { }; /* mmc2 */ -static struct omap_mmc_dev_attr am33xx_mmc2_dev_attr = { +static struct omap_hsmmc_dev_attr am33xx_mmc2_dev_attr = { .flags = OMAP_HSMMC_SUPPORTS_DUAL_VOLT, }; struct omap_hwmod am33xx_mmc2_hwmod = { diff --git a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c index 5f244a90eee5..11468eea3871 100644 --- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include #include "l3_3xxx.h" @@ -1786,12 +1786,12 @@ static struct omap_hwmod_opt_clk omap34xx_mmc1_opt_clks[] = { { .role = "dbck", .clk = "omap_32k_fck", }, }; -static struct omap_mmc_dev_attr mmc1_dev_attr = { +static struct omap_hsmmc_dev_attr mmc1_dev_attr = { .flags = OMAP_HSMMC_SUPPORTS_DUAL_VOLT, }; /* See 35xx errata 2.1.1.128 in SPRZ278F */ -static struct omap_mmc_dev_attr mmc1_pre_es3_dev_attr = { +static struct omap_hsmmc_dev_attr mmc1_pre_es3_dev_attr = { .flags = (OMAP_HSMMC_SUPPORTS_DUAL_VOLT | OMAP_HSMMC_BROKEN_MULTIBLOCK_READ), }; @@ -1854,7 +1854,7 @@ static struct omap_hwmod_opt_clk omap34xx_mmc2_opt_clks[] = { }; /* See 35xx errata 2.1.1.128 in SPRZ278F */ -static struct omap_mmc_dev_attr mmc2_pre_es3_dev_attr = { +static struct omap_hsmmc_dev_attr mmc2_pre_es3_dev_attr = { .flags = OMAP_HSMMC_BROKEN_MULTIBLOCK_READ, }; diff --git a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c index c385185c755d..d8a3cf1c1787 100644 --- a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c @@ -22,7 +22,7 @@ #include #include -#include +#include #include #include @@ -1952,7 +1952,7 @@ static struct omap_hwmod_dma_info omap44xx_mmc1_sdma_reqs[] = { }; /* mmc1 dev_attr */ -static struct omap_mmc_dev_attr mmc1_dev_attr = { +static struct omap_hsmmc_dev_attr mmc1_dev_attr = { .flags = OMAP_HSMMC_SUPPORTS_DUAL_VOLT, }; diff --git a/arch/arm/mach-omap2/omap_hwmod_54xx_data.c b/arch/arm/mach-omap2/omap_hwmod_54xx_data.c index 13bf6a72c5ee..5ec786a76d3c 100644 --- a/arch/arm/mach-omap2/omap_hwmod_54xx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_54xx_data.c @@ -19,7 +19,7 @@ #include #include -#include +#include #include #include @@ -1269,7 +1269,7 @@ static struct omap_hwmod_opt_clk mmc1_opt_clks[] = { }; /* mmc1 dev_attr */ -static struct omap_mmc_dev_attr mmc1_dev_attr = { +static struct omap_hsmmc_dev_attr mmc1_dev_attr = { .flags = OMAP_HSMMC_SUPPORTS_DUAL_VOLT, }; diff --git a/arch/arm/mach-omap2/omap_hwmod_7xx_data.c b/arch/arm/mach-omap2/omap_hwmod_7xx_data.c index 8523821fe78f..711c97e90990 100644 --- a/arch/arm/mach-omap2/omap_hwmod_7xx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_7xx_data.c @@ -19,7 +19,7 @@ #include #include -#include +#include #include #include @@ -1301,7 +1301,7 @@ static struct omap_hwmod_opt_clk mmc1_opt_clks[] = { }; /* mmc1 dev_attr */ -static struct omap_mmc_dev_attr mmc1_dev_attr = { +static struct omap_hsmmc_dev_attr mmc1_dev_attr = { .flags = OMAP_HSMMC_SUPPORTS_DUAL_VOLT, }; diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index df27bb4fc098..4957c5fe555b 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -42,7 +42,7 @@ #include #include #include -#include +#include /* OMAP HSMMC Host Controller Registers */ #define OMAP_HSMMC_SYSSTATUS 0x0014 @@ -220,7 +220,7 @@ struct omap_hsmmc_host { #define HSMMC_SDIO_IRQ_ENABLED (1 << 1) /* SDIO irq enabled */ #define HSMMC_WAKE_IRQ_ENABLED (1 << 2) struct omap_hsmmc_next next_data; - struct omap_mmc_platform_data *pdata; + struct omap_hsmmc_platform_data *pdata; }; struct omap_mmc_of_data { @@ -233,7 +233,7 @@ static void omap_hsmmc_start_dma_transfer(struct omap_hsmmc_host *host); static int omap_hsmmc_card_detect(struct device *dev, int slot) { struct omap_hsmmc_host *host = dev_get_drvdata(dev); - struct omap_mmc_platform_data *mmc = host->pdata; + struct omap_hsmmc_platform_data *mmc = host->pdata; /* NOTE: assumes card detect signal is active-low */ return !gpio_get_value_cansleep(mmc->slots[0].switch_pin); @@ -242,7 +242,7 @@ static int omap_hsmmc_card_detect(struct device *dev, int slot) static int omap_hsmmc_get_wp(struct device *dev, int slot) { struct omap_hsmmc_host *host = dev_get_drvdata(dev); - struct omap_mmc_platform_data *mmc = host->pdata; + struct omap_hsmmc_platform_data *mmc = host->pdata; /* NOTE: assumes write protect signal is active-high */ return gpio_get_value_cansleep(mmc->slots[0].gpio_wp); @@ -251,7 +251,7 @@ static int omap_hsmmc_get_wp(struct device *dev, int slot) static int omap_hsmmc_get_cover_state(struct device *dev, int slot) { struct omap_hsmmc_host *host = dev_get_drvdata(dev); - struct omap_mmc_platform_data *mmc = host->pdata; + struct omap_hsmmc_platform_data *mmc = host->pdata; /* NOTE: assumes card detect signal is active-low */ return !gpio_get_value_cansleep(mmc->slots[0].switch_pin); @@ -262,7 +262,7 @@ static int omap_hsmmc_get_cover_state(struct device *dev, int slot) static int omap_hsmmc_suspend_cdirq(struct device *dev, int slot) { struct omap_hsmmc_host *host = dev_get_drvdata(dev); - struct omap_mmc_platform_data *mmc = host->pdata; + struct omap_hsmmc_platform_data *mmc = host->pdata; disable_irq(mmc->slots[0].card_detect_irq); return 0; @@ -271,7 +271,7 @@ static int omap_hsmmc_suspend_cdirq(struct device *dev, int slot) static int omap_hsmmc_resume_cdirq(struct device *dev, int slot) { struct omap_hsmmc_host *host = dev_get_drvdata(dev); - struct omap_mmc_platform_data *mmc = host->pdata; + struct omap_hsmmc_platform_data *mmc = host->pdata; enable_irq(mmc->slots[0].card_detect_irq); return 0; @@ -449,7 +449,7 @@ static inline int omap_hsmmc_have_reg(void) #endif -static int omap_hsmmc_gpio_init(struct omap_mmc_platform_data *pdata) +static int omap_hsmmc_gpio_init(struct omap_hsmmc_platform_data *pdata) { int ret; @@ -492,7 +492,7 @@ err_free_sp: return ret; } -static void omap_hsmmc_gpio_free(struct omap_mmc_platform_data *pdata) +static void omap_hsmmc_gpio_free(struct omap_hsmmc_platform_data *pdata) { if (gpio_is_valid(pdata->slots[0].gpio_wp)) gpio_free(pdata->slots[0].gpio_wp); @@ -1286,7 +1286,7 @@ static void omap_hsmmc_protect_card(struct omap_hsmmc_host *host) static irqreturn_t omap_hsmmc_detect(int irq, void *dev_id) { struct omap_hsmmc_host *host = dev_id; - struct omap_mmc_slot_data *slot = &mmc_slot(host); + struct omap_hsmmc_slot_data *slot = &mmc_slot(host); int carddetect; sysfs_notify(&host->mmc->class_dev.kobj, NULL, "cover_switch"); @@ -1957,9 +1957,9 @@ static const struct of_device_id omap_mmc_of_match[] = { }; MODULE_DEVICE_TABLE(of, omap_mmc_of_match); -static struct omap_mmc_platform_data *of_get_hsmmc_pdata(struct device *dev) +static struct omap_hsmmc_platform_data *of_get_hsmmc_pdata(struct device *dev) { - struct omap_mmc_platform_data *pdata; + struct omap_hsmmc_platform_data *pdata; struct device_node *np = dev->of_node; u32 bus_width, max_freq; int cd_gpio, wp_gpio; @@ -2009,7 +2009,7 @@ static struct omap_mmc_platform_data *of_get_hsmmc_pdata(struct device *dev) return pdata; } #else -static inline struct omap_mmc_platform_data +static inline struct omap_hsmmc_platform_data *of_get_hsmmc_pdata(struct device *dev) { return ERR_PTR(-EINVAL); @@ -2018,7 +2018,7 @@ static inline struct omap_mmc_platform_data static int omap_hsmmc_probe(struct platform_device *pdev) { - struct omap_mmc_platform_data *pdata = pdev->dev.platform_data; + struct omap_hsmmc_platform_data *pdata = pdev->dev.platform_data; struct mmc_host *mmc; struct omap_hsmmc_host *host = NULL; struct resource *res; diff --git a/include/linux/platform_data/hsmmc-omap.h b/include/linux/platform_data/hsmmc-omap.h new file mode 100644 index 000000000000..7dd42e54a587 --- /dev/null +++ b/include/linux/platform_data/hsmmc-omap.h @@ -0,0 +1,149 @@ +/* + * MMC definitions for OMAP2 + * + * Copyright (C) 2006 Nokia Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#define OMAP_HSMMC_MAX_SLOTS 1 + +/* + * struct omap_hsmmc_dev_attr.flags possibilities + * + * OMAP_HSMMC_SUPPORTS_DUAL_VOLT: Some HSMMC controller instances can + * operate with either 1.8Vdc or 3.0Vdc card voltages; this flag + * should be set if this is the case. See for example Section 22.5.3 + * "MMC/SD/SDIO1 Bus Voltage Selection" of the OMAP34xx Multimedia + * Device Silicon Revision 3.1.x Revision ZR (July 2011) (SWPU223R). + * + * OMAP_HSMMC_BROKEN_MULTIBLOCK_READ: Multiple-block read transfers + * don't work correctly on some MMC controller instances on some + * OMAP3 SoCs; this flag should be set if this is the case. See + * for example Advisory 2.1.1.128 "MMC: Multiple Block Read + * Operation Issue" in _OMAP3530/3525/3515/3503 Silicon Errata_ + * Revision F (October 2010) (SPRZ278F). + */ +#define OMAP_HSMMC_SUPPORTS_DUAL_VOLT BIT(0) +#define OMAP_HSMMC_BROKEN_MULTIBLOCK_READ BIT(1) +#define OMAP_HSMMC_SWAKEUP_MISSING BIT(2) + +struct omap_hsmmc_dev_attr { + u8 flags; +}; + +struct mmc_card; + +struct omap_hsmmc_platform_data { + /* back-link to device */ + struct device *dev; + + /* number of slots per controller */ + unsigned nr_slots:2; + + /* set if your board has components or wiring that limits the + * maximum frequency on the MMC bus */ + unsigned int max_freq; + + /* switch the bus to a new slot */ + int (*switch_slot)(struct device *dev, int slot); + /* initialize board-specific MMC functionality, can be NULL if + * not supported */ + int (*init)(struct device *dev); + void (*cleanup)(struct device *dev); + void (*shutdown)(struct device *dev); + + /* To handle board related suspend/resume functionality for MMC */ + int (*suspend)(struct device *dev, int slot); + int (*resume)(struct device *dev, int slot); + + /* Return context loss count due to PM states changing */ + int (*get_context_loss_count)(struct device *dev); + + /* Integrating attributes from the omap_hwmod layer */ + u8 controller_flags; + + /* Register offset deviation */ + u16 reg_offset; + + struct omap_hsmmc_slot_data { + /* + * 4/8 wires and any additional host capabilities + * need to OR'd all capabilities (ref. linux/mmc/host.h) + */ + u8 wires; /* Used for the MMC driver on omap1 and 2420 */ + u32 caps; /* Used for the MMC driver on 2430 and later */ + u32 pm_caps; /* PM capabilities of the mmc */ + + /* + * nomux means "standard" muxing is wrong on this board, and + * that board-specific code handled it before common init logic. + */ + unsigned nomux:1; + + /* switch pin can be for card detect (default) or card cover */ + unsigned cover:1; + + /* use the internal clock */ + unsigned internal_clock:1; + + /* nonremovable e.g. eMMC */ + unsigned nonremovable:1; + + /* Try to sleep or power off when possible */ + unsigned power_saving:1; + + /* If using power_saving and the MMC power is not to go off */ + unsigned no_off:1; + + /* eMMC does not handle power off when not in sleep state */ + unsigned no_regulator_off_init:1; + + /* Regulator off remapped to sleep */ + unsigned vcc_aux_disable_is_sleep:1; + + /* we can put the features above into this variable */ +#define HSMMC_HAS_PBIAS (1 << 0) +#define HSMMC_HAS_UPDATED_RESET (1 << 1) +#define HSMMC_HAS_HSPE_SUPPORT (1 << 2) + unsigned features; + + int switch_pin; /* gpio (card detect) */ + int gpio_wp; /* gpio (write protect) */ + + int (*set_bus_mode)(struct device *dev, int slot, int bus_mode); + int (*set_power)(struct device *dev, int slot, + int power_on, int vdd); + int (*get_ro)(struct device *dev, int slot); + void (*remux)(struct device *dev, int slot, int power_on); + /* Call back before enabling / disabling regulators */ + void (*before_set_reg)(struct device *dev, int slot, + int power_on, int vdd); + /* Call back after enabling / disabling regulators */ + void (*after_set_reg)(struct device *dev, int slot, + int power_on, int vdd); + /* if we have special card, init it using this callback */ + void (*init_card)(struct mmc_card *card); + + /* return MMC cover switch state, can be NULL if not supported. + * + * possible return values: + * 0 - closed + * 1 - open + */ + int (*get_cover_state)(struct device *dev, int slot); + + const char *name; + u32 ocr_mask; + + /* Card detection IRQs */ + int card_detect_irq; + + int (*card_detect)(struct device *dev, int slot); + + unsigned int ban_openended:1; + + } slots[OMAP_HSMMC_MAX_SLOTS]; +}; diff --git a/include/linux/platform_data/mmc-omap.h b/include/linux/platform_data/mmc-omap.h index 51e70cf25cbc..5c188f4e9bec 100644 --- a/include/linux/platform_data/mmc-omap.h +++ b/include/linux/platform_data/mmc-omap.h @@ -10,32 +10,8 @@ #define OMAP_MMC_MAX_SLOTS 2 -/* - * struct omap_mmc_dev_attr.flags possibilities - * - * OMAP_HSMMC_SUPPORTS_DUAL_VOLT: Some HSMMC controller instances can - * operate with either 1.8Vdc or 3.0Vdc card voltages; this flag - * should be set if this is the case. See for example Section 22.5.3 - * "MMC/SD/SDIO1 Bus Voltage Selection" of the OMAP34xx Multimedia - * Device Silicon Revision 3.1.x Revision ZR (July 2011) (SWPU223R). - * - * OMAP_HSMMC_BROKEN_MULTIBLOCK_READ: Multiple-block read transfers - * don't work correctly on some MMC controller instances on some - * OMAP3 SoCs; this flag should be set if this is the case. See - * for example Advisory 2.1.1.128 "MMC: Multiple Block Read - * Operation Issue" in _OMAP3530/3525/3515/3503 Silicon Errata_ - * Revision F (October 2010) (SPRZ278F). - */ -#define OMAP_HSMMC_SUPPORTS_DUAL_VOLT BIT(0) -#define OMAP_HSMMC_BROKEN_MULTIBLOCK_READ BIT(1) -#define OMAP_HSMMC_SWAKEUP_MISSING BIT(2) - struct mmc_card; -struct omap_mmc_dev_attr { - u8 flags; -}; - struct omap_mmc_platform_data { /* back-link to device */ struct device *dev; @@ -106,9 +82,6 @@ struct omap_mmc_platform_data { unsigned vcc_aux_disable_is_sleep:1; /* we can put the features above into this variable */ -#define HSMMC_HAS_PBIAS (1 << 0) -#define HSMMC_HAS_UPDATED_RESET (1 << 1) -#define HSMMC_HAS_HSPE_SUPPORT (1 << 2) #define MMC_OMAP7XX (1 << 3) #define MMC_OMAP15XX (1 << 4) #define MMC_OMAP16XX (1 << 5) -- cgit v1.2.3-59-g8ed1b From a74fecdf795e1d219fcdb6470b6a0709ff7e3e76 Mon Sep 17 00:00:00 2001 From: Andreas Fenkart Date: Sat, 8 Nov 2014 15:33:10 +0100 Subject: mmc: omap_hsmmc: remove unused fields in platform_data platform data is built from omap2_hsmmc_info, remove all fields that are never set in omap_hsmmc_info, hence never copied to platform data. Note that the omap_hsmmc driver is not affected by this patch those fields were completely unused. Acked-by: Tony Lindgren Signed-off-by: Andreas Fenkart Signed-off-by: Ulf Hansson --- arch/arm/mach-omap2/hsmmc.c | 14 -------------- arch/arm/mach-omap2/hsmmc.h | 6 ------ include/linux/platform_data/hsmmc-omap.h | 19 ------------------- 3 files changed, 39 deletions(-) diff --git a/arch/arm/mach-omap2/hsmmc.c b/arch/arm/mach-omap2/hsmmc.c index 9edd7596d1e7..75b75b96040f 100644 --- a/arch/arm/mach-omap2/hsmmc.c +++ b/arch/arm/mach-omap2/hsmmc.c @@ -263,9 +263,7 @@ static int __init omap_hsmmc_pdata_init(struct omap2_hsmmc_info *c, mmc->slots[0].name = hc_name; mmc->nr_slots = 1; mmc->slots[0].caps = c->caps; - mmc->slots[0].pm_caps = c->pm_caps; mmc->slots[0].internal_clock = !c->ext_clock; - mmc->max_freq = c->max_freq; mmc->reg_offset = 0; mmc->get_context_loss_count = hsmmc_get_context_loss; @@ -281,18 +279,6 @@ static int __init omap_hsmmc_pdata_init(struct omap2_hsmmc_info *c, if (c->nonremovable) mmc->slots[0].nonremovable = 1; - if (c->power_saving) - mmc->slots[0].power_saving = 1; - - if (c->no_off) - mmc->slots[0].no_off = 1; - - if (c->no_off_init) - mmc->slots[0].no_regulator_off_init = c->no_off_init; - - if (c->vcc_aux_disable_is_sleep) - mmc->slots[0].vcc_aux_disable_is_sleep = 1; - /* * NOTE: MMC slots should have a Vcc regulator set up. * This may be from a TWL4030-family chip, another diff --git a/arch/arm/mach-omap2/hsmmc.h b/arch/arm/mach-omap2/hsmmc.h index 7f2e790e0929..bdc8870dde7e 100644 --- a/arch/arm/mach-omap2/hsmmc.h +++ b/arch/arm/mach-omap2/hsmmc.h @@ -12,23 +12,17 @@ struct omap2_hsmmc_info { u8 mmc; /* controller 1/2/3 */ u32 caps; /* 4/8 wires and any additional host * capabilities OR'd (ref. linux/mmc/host.h) */ - u32 pm_caps; /* PM capabilities */ bool transceiver; /* MMC-2 option */ bool ext_clock; /* use external pin for input clock */ bool cover_only; /* No card detect - just cover switch */ bool nonremovable; /* Nonremovable e.g. eMMC */ bool power_saving; /* Try to sleep or power off when possible */ - bool no_off; /* power_saving and power is not to go off */ - bool no_off_init; /* no power off when not in MMC sleep state */ - bool vcc_aux_disable_is_sleep; /* Regulator off remapped to sleep */ bool deferred; /* mmc needs a deferred probe */ int gpio_cd; /* or -EINVAL */ int gpio_wp; /* or -EINVAL */ char *name; /* or NULL for default */ struct platform_device *pdev; /* mmc controller instance */ int ocr_mask; /* temporary HACK */ - int max_freq; /* maximum clock, if constrained by external - * circuitry, or 0 for default */ /* Remux (pad configuration) when powering on/off */ void (*remux)(struct device *dev, int slot, int power_on); /* init some special card */ diff --git a/include/linux/platform_data/hsmmc-omap.h b/include/linux/platform_data/hsmmc-omap.h index 7dd42e54a587..11d7ed99603f 100644 --- a/include/linux/platform_data/hsmmc-omap.h +++ b/include/linux/platform_data/hsmmc-omap.h @@ -73,16 +73,9 @@ struct omap_hsmmc_platform_data { * 4/8 wires and any additional host capabilities * need to OR'd all capabilities (ref. linux/mmc/host.h) */ - u8 wires; /* Used for the MMC driver on omap1 and 2420 */ u32 caps; /* Used for the MMC driver on 2430 and later */ u32 pm_caps; /* PM capabilities of the mmc */ - /* - * nomux means "standard" muxing is wrong on this board, and - * that board-specific code handled it before common init logic. - */ - unsigned nomux:1; - /* switch pin can be for card detect (default) or card cover */ unsigned cover:1; @@ -92,18 +85,9 @@ struct omap_hsmmc_platform_data { /* nonremovable e.g. eMMC */ unsigned nonremovable:1; - /* Try to sleep or power off when possible */ - unsigned power_saving:1; - - /* If using power_saving and the MMC power is not to go off */ - unsigned no_off:1; - /* eMMC does not handle power off when not in sleep state */ unsigned no_regulator_off_init:1; - /* Regulator off remapped to sleep */ - unsigned vcc_aux_disable_is_sleep:1; - /* we can put the features above into this variable */ #define HSMMC_HAS_PBIAS (1 << 0) #define HSMMC_HAS_UPDATED_RESET (1 << 1) @@ -142,8 +126,5 @@ struct omap_hsmmc_platform_data { int card_detect_irq; int (*card_detect)(struct device *dev, int slot); - - unsigned int ban_openended:1; - } slots[OMAP_HSMMC_MAX_SLOTS]; }; -- cgit v1.2.3-59-g8ed1b From bb09d15114a55ae050f5315f2dfd6d1c989ecacd Mon Sep 17 00:00:00 2001 From: Andreas Fenkart Date: Sat, 8 Nov 2014 15:33:11 +0100 Subject: mmc: omap_hsmmc: remove un-initialized callbacks from platform data these callbacks are not set, probably legacy omap 1/2 features Acked-by: Tony Lindgren Signed-off-by: Andreas Fenkart Signed-off-by: Ulf Hansson --- drivers/mmc/host/omap_hsmmc.c | 15 +-------------- include/linux/platform_data/hsmmc-omap.h | 9 --------- 2 files changed, 1 insertion(+), 23 deletions(-) diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 4957c5fe555b..03e8e9aa3756 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -2204,18 +2204,10 @@ static int omap_hsmmc_probe(struct platform_device *pdev) goto err_irq; } - if (pdata->init != NULL) { - if (pdata->init(&pdev->dev) != 0) { - dev_err(mmc_dev(host->mmc), - "Unable to configure MMC IRQs\n"); - goto err_irq; - } - } - if (omap_hsmmc_have_reg() && !mmc_slot(host).set_power) { ret = omap_hsmmc_reg_get(host); if (ret) - goto err_reg; + goto err_irq; host->use_reg = 1; } @@ -2278,9 +2270,6 @@ err_slot_name: err_irq_cd: if (host->use_reg) omap_hsmmc_reg_put(host); -err_reg: - if (host->pdata->cleanup) - host->pdata->cleanup(&pdev->dev); err_irq: if (host->tx_chan) dma_release_channel(host->tx_chan); @@ -2306,8 +2295,6 @@ static int omap_hsmmc_remove(struct platform_device *pdev) mmc_remove_host(host->mmc); if (host->use_reg) omap_hsmmc_reg_put(host); - if (host->pdata->cleanup) - host->pdata->cleanup(&pdev->dev); if (host->tx_chan) dma_release_channel(host->tx_chan); diff --git a/include/linux/platform_data/hsmmc-omap.h b/include/linux/platform_data/hsmmc-omap.h index 11d7ed99603f..7e70e15154e4 100644 --- a/include/linux/platform_data/hsmmc-omap.h +++ b/include/linux/platform_data/hsmmc-omap.h @@ -47,14 +47,6 @@ struct omap_hsmmc_platform_data { * maximum frequency on the MMC bus */ unsigned int max_freq; - /* switch the bus to a new slot */ - int (*switch_slot)(struct device *dev, int slot); - /* initialize board-specific MMC functionality, can be NULL if - * not supported */ - int (*init)(struct device *dev); - void (*cleanup)(struct device *dev); - void (*shutdown)(struct device *dev); - /* To handle board related suspend/resume functionality for MMC */ int (*suspend)(struct device *dev, int slot); int (*resume)(struct device *dev, int slot); @@ -97,7 +89,6 @@ struct omap_hsmmc_platform_data { int switch_pin; /* gpio (card detect) */ int gpio_wp; /* gpio (write protect) */ - int (*set_bus_mode)(struct device *dev, int slot, int bus_mode); int (*set_power)(struct device *dev, int slot, int power_on, int vdd); int (*get_ro)(struct device *dev, int slot); -- cgit v1.2.3-59-g8ed1b From e5aafa27ab9ecf8918855cfe1244565138441e58 Mon Sep 17 00:00:00 2001 From: Andreas Fenkart Date: Sat, 8 Nov 2014 15:33:12 +0100 Subject: mmc: omap_hsmmc: remove never read power_saving field in omap2_hsmmc_info these fields are never read, probably an unimplemented feature or superseded by pm_runtime Acked-by: Tony Lindgren Signed-off-by: Andreas Fenkart Signed-off-by: Ulf Hansson --- arch/arm/mach-omap2/board-rx51-peripherals.c | 2 -- arch/arm/mach-omap2/hsmmc.h | 1 - 2 files changed, 3 deletions(-) diff --git a/arch/arm/mach-omap2/board-rx51-peripherals.c b/arch/arm/mach-omap2/board-rx51-peripherals.c index ddfc8df83c6a..0a8ac844b75b 100644 --- a/arch/arm/mach-omap2/board-rx51-peripherals.c +++ b/arch/arm/mach-omap2/board-rx51-peripherals.c @@ -500,7 +500,6 @@ static struct omap2_hsmmc_info mmc[] __initdata = { .cover_only = true, .gpio_cd = 160, .gpio_wp = -EINVAL, - .power_saving = true, }, { .name = "internal", @@ -510,7 +509,6 @@ static struct omap2_hsmmc_info mmc[] __initdata = { .gpio_cd = -EINVAL, .gpio_wp = -EINVAL, .nonremovable = true, - .power_saving = true, .remux = rx51_mmc2_remux, }, {} /* Terminator */ diff --git a/arch/arm/mach-omap2/hsmmc.h b/arch/arm/mach-omap2/hsmmc.h index bdc8870dde7e..30c78c17eb7e 100644 --- a/arch/arm/mach-omap2/hsmmc.h +++ b/arch/arm/mach-omap2/hsmmc.h @@ -16,7 +16,6 @@ struct omap2_hsmmc_info { bool ext_clock; /* use external pin for input clock */ bool cover_only; /* No card detect - just cover switch */ bool nonremovable; /* Nonremovable e.g. eMMC */ - bool power_saving; /* Try to sleep or power off when possible */ bool deferred; /* mmc needs a deferred probe */ int gpio_cd; /* or -EINVAL */ int gpio_wp; /* or -EINVAL */ -- cgit v1.2.3-59-g8ed1b From df206c313987bff595d2199f3bbf9b160e666b32 Mon Sep 17 00:00:00 2001 From: Andreas Fenkart Date: Sat, 8 Nov 2014 15:33:13 +0100 Subject: mmc: omap_hsmmc: remove unused get_context_loss_count callback trigger of this callback has been removed in 0a82e06e6183 Acked-by: Tony Lindgren Signed-off-by: Andreas Fenkart Signed-off-by: Ulf Hansson --- arch/arm/mach-omap2/hsmmc.c | 12 ------------ include/linux/platform_data/hsmmc-omap.h | 3 --- 2 files changed, 15 deletions(-) diff --git a/arch/arm/mach-omap2/hsmmc.c b/arch/arm/mach-omap2/hsmmc.c index 75b75b96040f..c65efc3cf81f 100644 --- a/arch/arm/mach-omap2/hsmmc.c +++ b/arch/arm/mach-omap2/hsmmc.c @@ -33,17 +33,6 @@ static u16 control_devconf1_offset; #define HSMMC_NAME_LEN 9 -#if defined(CONFIG_ARCH_OMAP3) && defined(CONFIG_PM) - -static int hsmmc_get_context_loss(struct device *dev) -{ - return omap_pm_get_dev_context_loss_count(dev); -} - -#else -#define hsmmc_get_context_loss NULL -#endif - static void omap_hsmmc1_before_set_reg(struct device *dev, int slot, int power_on, int vdd) { @@ -265,7 +254,6 @@ static int __init omap_hsmmc_pdata_init(struct omap2_hsmmc_info *c, mmc->slots[0].caps = c->caps; mmc->slots[0].internal_clock = !c->ext_clock; mmc->reg_offset = 0; - mmc->get_context_loss_count = hsmmc_get_context_loss; mmc->slots[0].switch_pin = c->gpio_cd; mmc->slots[0].gpio_wp = c->gpio_wp; diff --git a/include/linux/platform_data/hsmmc-omap.h b/include/linux/platform_data/hsmmc-omap.h index 7e70e15154e4..35d494f7d62f 100644 --- a/include/linux/platform_data/hsmmc-omap.h +++ b/include/linux/platform_data/hsmmc-omap.h @@ -51,9 +51,6 @@ struct omap_hsmmc_platform_data { int (*suspend)(struct device *dev, int slot); int (*resume)(struct device *dev, int slot); - /* Return context loss count due to PM states changing */ - int (*get_context_loss_count)(struct device *dev); - /* Integrating attributes from the omap_hwmod layer */ u8 controller_flags; -- cgit v1.2.3-59-g8ed1b From 326119c9923711d782e71e197429b1bab16125e1 Mon Sep 17 00:00:00 2001 From: Andreas Fenkart Date: Sat, 8 Nov 2014 15:33:14 +0100 Subject: mmc: omap_hsmmc: remove unnecessary omap_hsmmc_slot_data indirection omap_hsmmc supports only one slot per controller, see OMAP_MMC_MAX_SLOTS. This unnecessary indirection leads to confusion in the omap_hsmmc driver. For example the card_detect callback is not installed by platform code but from the driver probe function. So it should be a field of omap_hsmmc_host. But since it is declared under the platform slot while the drivers struct omap_hsmmc_host has no slot abstraction, this looks like a bug, especially when not familiar that this driver only supports 1 slot anyway. Either we should add a slot abstraction to omap_hsmmc_host or remove it from the platform data struct. Removed since slot multiplexing is an un-implemented feature Acked-by: Tony Lindgren Signed-off-by: Andreas Fenkart Signed-off-by: Ulf Hansson --- arch/arm/mach-omap2/hsmmc.c | 88 ++++++++-------- drivers/mmc/host/omap_hsmmc.c | 175 ++++++++++++++++--------------- include/linux/platform_data/hsmmc-omap.h | 100 +++++++++--------- 3 files changed, 181 insertions(+), 182 deletions(-) diff --git a/arch/arm/mach-omap2/hsmmc.c b/arch/arm/mach-omap2/hsmmc.c index c65efc3cf81f..4e2896ad0119 100644 --- a/arch/arm/mach-omap2/hsmmc.c +++ b/arch/arm/mach-omap2/hsmmc.c @@ -39,8 +39,8 @@ static void omap_hsmmc1_before_set_reg(struct device *dev, int slot, u32 reg, prog_io; struct omap_hsmmc_platform_data *mmc = dev->platform_data; - if (mmc->slots[0].remux) - mmc->slots[0].remux(dev, slot, power_on); + if (mmc->remux) + mmc->remux(dev, slot, power_on); /* * Assume we power both OMAP VMMC1 (for CMD, CLK, DAT0..3) and the @@ -62,7 +62,7 @@ static void omap_hsmmc1_before_set_reg(struct device *dev, int slot, omap_ctrl_writel(reg, OMAP243X_CONTROL_DEVCONF1); } - if (mmc->slots[0].internal_clock) { + if (mmc->internal_clock) { reg = omap_ctrl_readl(OMAP2_CONTROL_DEVCONF0); reg |= OMAP2_MMCSDIO1ADPCLKISEL; omap_ctrl_writel(reg, OMAP2_CONTROL_DEVCONF0); @@ -115,7 +115,7 @@ static void hsmmc2_select_input_clk_src(struct omap_hsmmc_platform_data *mmc) u32 reg; reg = omap_ctrl_readl(control_devconf1_offset); - if (mmc->slots[0].internal_clock) + if (mmc->internal_clock) reg |= OMAP2_MMCSDIO2ADPCLKISEL; else reg &= ~OMAP2_MMCSDIO2ADPCLKISEL; @@ -127,8 +127,8 @@ static void hsmmc2_before_set_reg(struct device *dev, int slot, { struct omap_hsmmc_platform_data *mmc = dev->platform_data; - if (mmc->slots[0].remux) - mmc->slots[0].remux(dev, slot, power_on); + if (mmc->remux) + mmc->remux(dev, slot, power_on); if (power_on) hsmmc2_select_input_clk_src(mmc); @@ -154,14 +154,14 @@ static int nop_mmc_set_power(struct device *dev, int slot, int power_on, static inline void omap_hsmmc_mux(struct omap_hsmmc_platform_data *mmc_controller, int controller_nr) { - if (gpio_is_valid(mmc_controller->slots[0].switch_pin) && - (mmc_controller->slots[0].switch_pin < OMAP_MAX_GPIO_LINES)) - omap_mux_init_gpio(mmc_controller->slots[0].switch_pin, - OMAP_PIN_INPUT_PULLUP); - if (gpio_is_valid(mmc_controller->slots[0].gpio_wp) && - (mmc_controller->slots[0].gpio_wp < OMAP_MAX_GPIO_LINES)) - omap_mux_init_gpio(mmc_controller->slots[0].gpio_wp, - OMAP_PIN_INPUT_PULLUP); + if (gpio_is_valid(mmc_controller->switch_pin) && + (mmc_controller->switch_pin < OMAP_MAX_GPIO_LINES)) + omap_mux_init_gpio(mmc_controller->switch_pin, + OMAP_PIN_INPUT_PULLUP); + if (gpio_is_valid(mmc_controller->gpio_wp) && + (mmc_controller->gpio_wp < OMAP_MAX_GPIO_LINES)) + omap_mux_init_gpio(mmc_controller->gpio_wp, + OMAP_PIN_INPUT_PULLUP); if (cpu_is_omap34xx()) { if (controller_nr == 0) { omap_mux_init_signal("sdmmc1_clk", @@ -170,7 +170,7 @@ static inline void omap_hsmmc_mux(struct omap_hsmmc_platform_data OMAP_PIN_INPUT_PULLUP); omap_mux_init_signal("sdmmc1_dat0", OMAP_PIN_INPUT_PULLUP); - if (mmc_controller->slots[0].caps & + if (mmc_controller->caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA)) { omap_mux_init_signal("sdmmc1_dat1", OMAP_PIN_INPUT_PULLUP); @@ -179,7 +179,7 @@ static inline void omap_hsmmc_mux(struct omap_hsmmc_platform_data omap_mux_init_signal("sdmmc1_dat3", OMAP_PIN_INPUT_PULLUP); } - if (mmc_controller->slots[0].caps & + if (mmc_controller->caps & MMC_CAP_8_BIT_DATA) { omap_mux_init_signal("sdmmc1_dat4", OMAP_PIN_INPUT_PULLUP); @@ -204,7 +204,7 @@ static inline void omap_hsmmc_mux(struct omap_hsmmc_platform_data * For 8 wire configurations, Lines DAT4, 5, 6 and 7 * need to be muxed in the board-*.c files */ - if (mmc_controller->slots[0].caps & + if (mmc_controller->caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA)) { omap_mux_init_signal("sdmmc2_dat1", OMAP_PIN_INPUT_PULLUP); @@ -213,7 +213,7 @@ static inline void omap_hsmmc_mux(struct omap_hsmmc_platform_data omap_mux_init_signal("sdmmc2_dat3", OMAP_PIN_INPUT_PULLUP); } - if (mmc_controller->slots[0].caps & + if (mmc_controller->caps & MMC_CAP_8_BIT_DATA) { omap_mux_init_signal("sdmmc2_dat4.sdmmc2_dat4", OMAP_PIN_INPUT_PULLUP); @@ -249,23 +249,23 @@ static int __init omap_hsmmc_pdata_init(struct omap2_hsmmc_info *c, else snprintf(hc_name, (HSMMC_NAME_LEN + 1), "mmc%islot%i", c->mmc, 1); - mmc->slots[0].name = hc_name; + mmc->name = hc_name; mmc->nr_slots = 1; - mmc->slots[0].caps = c->caps; - mmc->slots[0].internal_clock = !c->ext_clock; + mmc->caps = c->caps; + mmc->internal_clock = !c->ext_clock; mmc->reg_offset = 0; - mmc->slots[0].switch_pin = c->gpio_cd; - mmc->slots[0].gpio_wp = c->gpio_wp; + mmc->switch_pin = c->gpio_cd; + mmc->gpio_wp = c->gpio_wp; - mmc->slots[0].remux = c->remux; - mmc->slots[0].init_card = c->init_card; + mmc->remux = c->remux; + mmc->init_card = c->init_card; if (c->cover_only) - mmc->slots[0].cover = 1; + mmc->cover = 1; if (c->nonremovable) - mmc->slots[0].nonremovable = 1; + mmc->nonremovable = 1; /* * NOTE: MMC slots should have a Vcc regulator set up. @@ -275,42 +275,42 @@ static int __init omap_hsmmc_pdata_init(struct omap2_hsmmc_info *c, * temporary HACK: ocr_mask instead of fixed supply */ if (soc_is_am35xx()) - mmc->slots[0].ocr_mask = MMC_VDD_165_195 | + mmc->ocr_mask = MMC_VDD_165_195 | MMC_VDD_26_27 | MMC_VDD_27_28 | MMC_VDD_29_30 | MMC_VDD_30_31 | MMC_VDD_31_32; else - mmc->slots[0].ocr_mask = c->ocr_mask; + mmc->ocr_mask = c->ocr_mask; if (!soc_is_am35xx()) - mmc->slots[0].features |= HSMMC_HAS_PBIAS; + mmc->features |= HSMMC_HAS_PBIAS; switch (c->mmc) { case 1: - if (mmc->slots[0].features & HSMMC_HAS_PBIAS) { + if (mmc->features & HSMMC_HAS_PBIAS) { /* on-chip level shifting via PBIAS0/PBIAS1 */ - mmc->slots[0].before_set_reg = + mmc->before_set_reg = omap_hsmmc1_before_set_reg; - mmc->slots[0].after_set_reg = + mmc->after_set_reg = omap_hsmmc1_after_set_reg; } if (soc_is_am35xx()) - mmc->slots[0].set_power = nop_mmc_set_power; + mmc->set_power = nop_mmc_set_power; /* OMAP3630 HSMMC1 supports only 4-bit */ if (cpu_is_omap3630() && (c->caps & MMC_CAP_8_BIT_DATA)) { c->caps &= ~MMC_CAP_8_BIT_DATA; c->caps |= MMC_CAP_4_BIT_DATA; - mmc->slots[0].caps = c->caps; + mmc->caps = c->caps; } break; case 2: if (soc_is_am35xx()) - mmc->slots[0].set_power = am35x_hsmmc2_set_power; + mmc->set_power = am35x_hsmmc2_set_power; if (c->ext_clock) c->transceiver = 1; @@ -318,17 +318,17 @@ static int __init omap_hsmmc_pdata_init(struct omap2_hsmmc_info *c, c->caps &= ~MMC_CAP_8_BIT_DATA; c->caps |= MMC_CAP_4_BIT_DATA; } - if (mmc->slots[0].features & HSMMC_HAS_PBIAS) { + if (mmc->features & HSMMC_HAS_PBIAS) { /* off-chip level shifting, or none */ - mmc->slots[0].before_set_reg = hsmmc2_before_set_reg; - mmc->slots[0].after_set_reg = NULL; + mmc->before_set_reg = hsmmc2_before_set_reg; + mmc->after_set_reg = NULL; } break; case 3: case 4: case 5: - mmc->slots[0].before_set_reg = NULL; - mmc->slots[0].after_set_reg = NULL; + mmc->before_set_reg = NULL; + mmc->after_set_reg = NULL; break; default: pr_err("MMC%d configuration not supported!\n", c->mmc); @@ -363,8 +363,8 @@ void omap_hsmmc_late_init(struct omap2_hsmmc_info *c) if (!mmc_pdata) continue; - mmc_pdata->slots[0].switch_pin = c->gpio_cd; - mmc_pdata->slots[0].gpio_wp = c->gpio_wp; + mmc_pdata->switch_pin = c->gpio_cd; + mmc_pdata->gpio_wp = c->gpio_wp; res = omap_device_register(pdev); if (res) @@ -464,7 +464,7 @@ put_pdev: platform_device_put(pdev); free_name: - kfree(mmc_data->slots[0].name); + kfree(mmc_data->name); free_mmc: kfree(mmc_data); diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 03e8e9aa3756..291b9e125d46 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -155,7 +155,7 @@ * omap.c controller driver. Luckily this is not currently done on any known * omap_hsmmc.c device. */ -#define mmc_slot(host) (host->pdata->slots[host->slot_id]) +#define mmc_pdata(host) host->pdata /* * MMC Host controller read/write API's @@ -236,7 +236,7 @@ static int omap_hsmmc_card_detect(struct device *dev, int slot) struct omap_hsmmc_platform_data *mmc = host->pdata; /* NOTE: assumes card detect signal is active-low */ - return !gpio_get_value_cansleep(mmc->slots[0].switch_pin); + return !gpio_get_value_cansleep(mmc->switch_pin); } static int omap_hsmmc_get_wp(struct device *dev, int slot) @@ -245,7 +245,7 @@ static int omap_hsmmc_get_wp(struct device *dev, int slot) struct omap_hsmmc_platform_data *mmc = host->pdata; /* NOTE: assumes write protect signal is active-high */ - return gpio_get_value_cansleep(mmc->slots[0].gpio_wp); + return gpio_get_value_cansleep(mmc->gpio_wp); } static int omap_hsmmc_get_cover_state(struct device *dev, int slot) @@ -254,7 +254,7 @@ static int omap_hsmmc_get_cover_state(struct device *dev, int slot) struct omap_hsmmc_platform_data *mmc = host->pdata; /* NOTE: assumes card detect signal is active-low */ - return !gpio_get_value_cansleep(mmc->slots[0].switch_pin); + return !gpio_get_value_cansleep(mmc->switch_pin); } #ifdef CONFIG_PM @@ -264,7 +264,7 @@ static int omap_hsmmc_suspend_cdirq(struct device *dev, int slot) struct omap_hsmmc_host *host = dev_get_drvdata(dev); struct omap_hsmmc_platform_data *mmc = host->pdata; - disable_irq(mmc->slots[0].card_detect_irq); + disable_irq(mmc->card_detect_irq); return 0; } @@ -273,7 +273,7 @@ static int omap_hsmmc_resume_cdirq(struct device *dev, int slot) struct omap_hsmmc_host *host = dev_get_drvdata(dev); struct omap_hsmmc_platform_data *mmc = host->pdata; - enable_irq(mmc->slots[0].card_detect_irq); + enable_irq(mmc->card_detect_irq); return 0; } @@ -300,8 +300,8 @@ static int omap_hsmmc_set_power(struct device *dev, int slot, int power_on, if (!host->vcc) return 0; - if (mmc_slot(host).before_set_reg) - mmc_slot(host).before_set_reg(dev, slot, power_on, vdd); + if (mmc_pdata(host)->before_set_reg) + mmc_pdata(host)->before_set_reg(dev, slot, power_on, vdd); if (host->pbias) { if (host->pbias_enabled == 1) { @@ -363,8 +363,8 @@ static int omap_hsmmc_set_power(struct device *dev, int slot, int power_on, } } - if (mmc_slot(host).after_set_reg) - mmc_slot(host).after_set_reg(dev, slot, power_on, vdd); + if (mmc_pdata(host)->after_set_reg) + mmc_pdata(host)->after_set_reg(dev, slot, power_on, vdd); error_set_power: return ret; @@ -383,18 +383,18 @@ static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host) } else { host->vcc = reg; ocr_value = mmc_regulator_get_ocrmask(reg); - if (!mmc_slot(host).ocr_mask) { - mmc_slot(host).ocr_mask = ocr_value; + if (!mmc_pdata(host)->ocr_mask) { + mmc_pdata(host)->ocr_mask = ocr_value; } else { - if (!(mmc_slot(host).ocr_mask & ocr_value)) { + if (!(mmc_pdata(host)->ocr_mask & ocr_value)) { dev_err(host->dev, "ocrmask %x is not supported\n", - mmc_slot(host).ocr_mask); - mmc_slot(host).ocr_mask = 0; + mmc_pdata(host)->ocr_mask); + mmc_pdata(host)->ocr_mask = 0; return -EINVAL; } } } - mmc_slot(host).set_power = omap_hsmmc_set_power; + mmc_pdata(host)->set_power = omap_hsmmc_set_power; /* Allow an aux regulator */ reg = devm_regulator_get_optional(host->dev, "vmmc_aux"); @@ -404,7 +404,7 @@ static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host) host->pbias = IS_ERR(reg) ? NULL : reg; /* For eMMC do not power off when not in sleep state */ - if (mmc_slot(host).no_regulator_off_init) + if (mmc_pdata(host)->no_regulator_off_init) return 0; /* * To disable boot_on regulator, enable regulator @@ -412,10 +412,10 @@ static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host) */ if ((host->vcc && regulator_is_enabled(host->vcc) > 0) || (host->vcc_aux && regulator_is_enabled(host->vcc_aux))) { - int vdd = ffs(mmc_slot(host).ocr_mask) - 1; + int vdd = ffs(mmc_pdata(host)->ocr_mask) - 1; - mmc_slot(host).set_power(host->dev, host->slot_id, 1, vdd); - mmc_slot(host).set_power(host->dev, host->slot_id, 0, 0); + mmc_pdata(host)->set_power(host->dev, host->slot_id, 1, vdd); + mmc_pdata(host)->set_power(host->dev, host->slot_id, 0, 0); } return 0; @@ -423,7 +423,7 @@ static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host) static void omap_hsmmc_reg_put(struct omap_hsmmc_host *host) { - mmc_slot(host).set_power = NULL; + mmc_pdata(host)->set_power = NULL; } static inline int omap_hsmmc_have_reg(void) @@ -453,51 +453,53 @@ static int omap_hsmmc_gpio_init(struct omap_hsmmc_platform_data *pdata) { int ret; - if (gpio_is_valid(pdata->slots[0].switch_pin)) { - if (pdata->slots[0].cover) - pdata->slots[0].get_cover_state = + if (gpio_is_valid(pdata->switch_pin)) { + if (pdata->cover) + pdata->get_cover_state = omap_hsmmc_get_cover_state; else - pdata->slots[0].card_detect = omap_hsmmc_card_detect; - pdata->slots[0].card_detect_irq = - gpio_to_irq(pdata->slots[0].switch_pin); - ret = gpio_request(pdata->slots[0].switch_pin, "mmc_cd"); + pdata->card_detect = omap_hsmmc_card_detect; + pdata->card_detect_irq = + gpio_to_irq(pdata->switch_pin); + ret = gpio_request(pdata->switch_pin, "mmc_cd"); if (ret) return ret; - ret = gpio_direction_input(pdata->slots[0].switch_pin); + ret = gpio_direction_input(pdata->switch_pin); if (ret) goto err_free_sp; - } else - pdata->slots[0].switch_pin = -EINVAL; + } else { + pdata->switch_pin = -EINVAL; + } - if (gpio_is_valid(pdata->slots[0].gpio_wp)) { - pdata->slots[0].get_ro = omap_hsmmc_get_wp; - ret = gpio_request(pdata->slots[0].gpio_wp, "mmc_wp"); + if (gpio_is_valid(pdata->gpio_wp)) { + pdata->get_ro = omap_hsmmc_get_wp; + ret = gpio_request(pdata->gpio_wp, "mmc_wp"); if (ret) goto err_free_cd; - ret = gpio_direction_input(pdata->slots[0].gpio_wp); + ret = gpio_direction_input(pdata->gpio_wp); if (ret) goto err_free_wp; - } else - pdata->slots[0].gpio_wp = -EINVAL; + } else { + pdata->gpio_wp = -EINVAL; + } return 0; err_free_wp: - gpio_free(pdata->slots[0].gpio_wp); + gpio_free(pdata->gpio_wp); err_free_cd: - if (gpio_is_valid(pdata->slots[0].switch_pin)) + if (gpio_is_valid(pdata->switch_pin)) err_free_sp: - gpio_free(pdata->slots[0].switch_pin); + gpio_free(pdata->switch_pin); return ret; } static void omap_hsmmc_gpio_free(struct omap_hsmmc_platform_data *pdata) { - if (gpio_is_valid(pdata->slots[0].gpio_wp)) - gpio_free(pdata->slots[0].gpio_wp); - if (gpio_is_valid(pdata->slots[0].switch_pin)) - gpio_free(pdata->slots[0].switch_pin); + if (gpio_is_valid(pdata->gpio_wp)) + gpio_free(pdata->gpio_wp); + if (gpio_is_valid(pdata->switch_pin)) + gpio_free(pdata->switch_pin); } /* @@ -607,7 +609,7 @@ static void omap_hsmmc_set_clock(struct omap_hsmmc_host *host) * in capabilities register * - MMC/SD clock coming out of controller > 25MHz */ - if ((mmc_slot(host).features & HSMMC_HAS_HSPE_SUPPORT) && + if ((mmc_pdata(host)->features & HSMMC_HAS_HSPE_SUPPORT) && (ios->timing != MMC_TIMING_MMC_DDR52) && ((OMAP_HSMMC_READ(host->base, CAPA) & HSS) == HSS)) { regval = OMAP_HSMMC_READ(host->base, HCTL); @@ -791,8 +793,8 @@ int omap_hsmmc_cover_is_closed(struct omap_hsmmc_host *host) { int r = 1; - if (mmc_slot(host).get_cover_state) - r = mmc_slot(host).get_cover_state(host->dev, host->slot_id); + if (mmc_pdata(host)->get_cover_state) + r = mmc_pdata(host)->get_cover_state(host->dev, host->slot_id); return r; } @@ -816,7 +818,7 @@ omap_hsmmc_show_slot_name(struct device *dev, struct device_attribute *attr, struct mmc_host *mmc = container_of(dev, struct mmc_host, class_dev); struct omap_hsmmc_host *host = mmc_priv(mmc); - return sprintf(buf, "%s\n", mmc_slot(host).name); + return sprintf(buf, "%s\n", mmc_pdata(host)->name); } static DEVICE_ATTR(slot_name, S_IRUGO, omap_hsmmc_show_slot_name, NULL); @@ -1061,7 +1063,7 @@ static inline void omap_hsmmc_reset_controller_fsm(struct omap_hsmmc_host *host, * OMAP4 ES2 and greater has an updated reset logic. * Monitor a 0->1 transition first */ - if (mmc_slot(host).features & HSMMC_HAS_UPDATED_RESET) { + if (mmc_pdata(host)->features & HSMMC_HAS_UPDATED_RESET) { while ((!(OMAP_HSMMC_READ(host->base, SYSCTL) & bit)) && (i++ < limit)) udelay(1); @@ -1210,12 +1212,12 @@ static int omap_hsmmc_switch_opcond(struct omap_hsmmc_host *host, int vdd) clk_disable_unprepare(host->dbclk); /* Turn the power off */ - ret = mmc_slot(host).set_power(host->dev, host->slot_id, 0, 0); + ret = mmc_pdata(host)->set_power(host->dev, host->slot_id, 0, 0); /* Turn the power ON with given VDD 1.8 or 3.0v */ if (!ret) - ret = mmc_slot(host).set_power(host->dev, host->slot_id, 1, - vdd); + ret = mmc_pdata(host)->set_power(host->dev, host->slot_id, 1, + vdd); pm_runtime_get_sync(host->dev); if (host->dbclk) clk_prepare_enable(host->dbclk); @@ -1259,11 +1261,11 @@ err: /* Protect the card while the cover is open */ static void omap_hsmmc_protect_card(struct omap_hsmmc_host *host) { - if (!mmc_slot(host).get_cover_state) + if (!mmc_pdata(host)->get_cover_state) return; host->reqs_blocked = 0; - if (mmc_slot(host).get_cover_state(host->dev, host->slot_id)) { + if (mmc_pdata(host)->get_cover_state(host->dev, host->slot_id)) { if (host->protect_card) { dev_info(host->dev, "%s: cover is closed, " "card is now accessible\n", @@ -1286,13 +1288,13 @@ static void omap_hsmmc_protect_card(struct omap_hsmmc_host *host) static irqreturn_t omap_hsmmc_detect(int irq, void *dev_id) { struct omap_hsmmc_host *host = dev_id; - struct omap_hsmmc_slot_data *slot = &mmc_slot(host); + struct omap_hsmmc_platform_data *pdata = host->pdata; int carddetect; sysfs_notify(&host->mmc->class_dev.kobj, NULL, "cover_switch"); - if (slot->card_detect) - carddetect = slot->card_detect(host->dev, host->slot_id); + if (pdata->card_detect) + carddetect = pdata->card_detect(host->dev, host->slot_id); else { omap_hsmmc_protect_card(host); carddetect = -ENOSYS; @@ -1618,12 +1620,12 @@ static void omap_hsmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) if (ios->power_mode != host->power_mode) { switch (ios->power_mode) { case MMC_POWER_OFF: - mmc_slot(host).set_power(host->dev, host->slot_id, - 0, 0); + mmc_pdata(host)->set_power(host->dev, host->slot_id, + 0, 0); break; case MMC_POWER_UP: - mmc_slot(host).set_power(host->dev, host->slot_id, - 1, ios->vdd); + mmc_pdata(host)->set_power(host->dev, host->slot_id, + 1, ios->vdd); break; case MMC_POWER_ON: do_send_init_stream = 1; @@ -1668,26 +1670,26 @@ static int omap_hsmmc_get_cd(struct mmc_host *mmc) { struct omap_hsmmc_host *host = mmc_priv(mmc); - if (!mmc_slot(host).card_detect) + if (!mmc_pdata(host)->card_detect) return -ENOSYS; - return mmc_slot(host).card_detect(host->dev, host->slot_id); + return mmc_pdata(host)->card_detect(host->dev, host->slot_id); } static int omap_hsmmc_get_ro(struct mmc_host *mmc) { struct omap_hsmmc_host *host = mmc_priv(mmc); - if (!mmc_slot(host).get_ro) + if (!mmc_pdata(host)->get_ro) return -ENOSYS; - return mmc_slot(host).get_ro(host->dev, 0); + return mmc_pdata(host)->get_ro(host->dev, 0); } static void omap_hsmmc_init_card(struct mmc_host *mmc, struct mmc_card *card) { struct omap_hsmmc_host *host = mmc_priv(mmc); - if (mmc_slot(host).init_card) - mmc_slot(host).init_card(card); + if (mmc_pdata(host)->init_card) + mmc_pdata(host)->init_card(card); } static void omap_hsmmc_enable_sdio_irq(struct mmc_host *mmc, int enable) @@ -1978,33 +1980,33 @@ static struct omap_hsmmc_platform_data *of_get_hsmmc_pdata(struct device *dev) /* This driver only supports 1 slot */ pdata->nr_slots = 1; - pdata->slots[0].switch_pin = cd_gpio; - pdata->slots[0].gpio_wp = wp_gpio; + pdata->switch_pin = cd_gpio; + pdata->gpio_wp = wp_gpio; if (of_find_property(np, "ti,non-removable", NULL)) { - pdata->slots[0].nonremovable = true; - pdata->slots[0].no_regulator_off_init = true; + pdata->nonremovable = true; + pdata->no_regulator_off_init = true; } of_property_read_u32(np, "bus-width", &bus_width); if (bus_width == 4) - pdata->slots[0].caps |= MMC_CAP_4_BIT_DATA; + pdata->caps |= MMC_CAP_4_BIT_DATA; else if (bus_width == 8) - pdata->slots[0].caps |= MMC_CAP_8_BIT_DATA; + pdata->caps |= MMC_CAP_8_BIT_DATA; if (of_find_property(np, "ti,needs-special-reset", NULL)) - pdata->slots[0].features |= HSMMC_HAS_UPDATED_RESET; + pdata->features |= HSMMC_HAS_UPDATED_RESET; if (!of_property_read_u32(np, "max-frequency", &max_freq)) pdata->max_freq = max_freq; if (of_find_property(np, "ti,needs-special-hs-handling", NULL)) - pdata->slots[0].features |= HSMMC_HAS_HSPE_SUPPORT; + pdata->features |= HSMMC_HAS_HSPE_SUPPORT; if (of_find_property(np, "keep-power-in-suspend", NULL)) - pdata->slots[0].pm_caps |= MMC_PM_KEEP_POWER; + pdata->pm_caps |= MMC_PM_KEEP_POWER; if (of_find_property(np, "enable-sdio-wakeup", NULL)) - pdata->slots[0].pm_caps |= MMC_PM_WAKE_SDIO_IRQ; + pdata->pm_caps |= MMC_PM_WAKE_SDIO_IRQ; return pdata; } @@ -2144,14 +2146,14 @@ static int omap_hsmmc_probe(struct platform_device *pdev) mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED | MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_ERASE; - mmc->caps |= mmc_slot(host).caps; + mmc->caps |= mmc_pdata(host)->caps; if (mmc->caps & MMC_CAP_8_BIT_DATA) mmc->caps |= MMC_CAP_4_BIT_DATA; - if (mmc_slot(host).nonremovable) + if (mmc_pdata(host)->nonremovable) mmc->caps |= MMC_CAP_NONREMOVABLE; - mmc->pm_caps = mmc_slot(host).pm_caps; + mmc->pm_caps = mmc_pdata(host)->pm_caps; omap_hsmmc_conf_bus_power(host); @@ -2204,19 +2206,19 @@ static int omap_hsmmc_probe(struct platform_device *pdev) goto err_irq; } - if (omap_hsmmc_have_reg() && !mmc_slot(host).set_power) { + if (omap_hsmmc_have_reg() && !mmc_pdata(host)->set_power) { ret = omap_hsmmc_reg_get(host); if (ret) goto err_irq; host->use_reg = 1; } - mmc->ocr_avail = mmc_slot(host).ocr_mask; + mmc->ocr_avail = mmc_pdata(host)->ocr_mask; /* Request IRQ for card detect */ - if ((mmc_slot(host).card_detect_irq)) { + if ((mmc_pdata(host)->card_detect_irq)) { ret = devm_request_threaded_irq(&pdev->dev, - mmc_slot(host).card_detect_irq, + mmc_pdata(host)->card_detect_irq, NULL, omap_hsmmc_detect, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, mmc_hostname(mmc), host); @@ -2247,12 +2249,13 @@ static int omap_hsmmc_probe(struct platform_device *pdev) mmc_add_host(mmc); - if (mmc_slot(host).name != NULL) { + if (mmc_pdata(host)->name != NULL) { ret = device_create_file(&mmc->class_dev, &dev_attr_slot_name); if (ret < 0) goto err_slot_name; } - if (mmc_slot(host).card_detect_irq && mmc_slot(host).get_cover_state) { + if (mmc_pdata(host)->card_detect_irq && + mmc_pdata(host)->get_cover_state) { ret = device_create_file(&mmc->class_dev, &dev_attr_cover_switch); if (ret < 0) diff --git a/include/linux/platform_data/hsmmc-omap.h b/include/linux/platform_data/hsmmc-omap.h index 35d494f7d62f..26912143adc0 100644 --- a/include/linux/platform_data/hsmmc-omap.h +++ b/include/linux/platform_data/hsmmc-omap.h @@ -8,8 +8,6 @@ * published by the Free Software Foundation. */ -#define OMAP_HSMMC_MAX_SLOTS 1 - /* * struct omap_hsmmc_dev_attr.flags possibilities * @@ -57,62 +55,60 @@ struct omap_hsmmc_platform_data { /* Register offset deviation */ u16 reg_offset; - struct omap_hsmmc_slot_data { - /* - * 4/8 wires and any additional host capabilities - * need to OR'd all capabilities (ref. linux/mmc/host.h) - */ - u32 caps; /* Used for the MMC driver on 2430 and later */ - u32 pm_caps; /* PM capabilities of the mmc */ + /* + * 4/8 wires and any additional host capabilities + * need to OR'd all capabilities (ref. linux/mmc/host.h) + */ + u32 caps; /* Used for the MMC driver on 2430 and later */ + u32 pm_caps; /* PM capabilities of the mmc */ - /* switch pin can be for card detect (default) or card cover */ - unsigned cover:1; + /* switch pin can be for card detect (default) or card cover */ + unsigned cover:1; - /* use the internal clock */ - unsigned internal_clock:1; + /* use the internal clock */ + unsigned internal_clock:1; - /* nonremovable e.g. eMMC */ - unsigned nonremovable:1; + /* nonremovable e.g. eMMC */ + unsigned nonremovable:1; - /* eMMC does not handle power off when not in sleep state */ - unsigned no_regulator_off_init:1; + /* eMMC does not handle power off when not in sleep state */ + unsigned no_regulator_off_init:1; - /* we can put the features above into this variable */ + /* we can put the features above into this variable */ #define HSMMC_HAS_PBIAS (1 << 0) #define HSMMC_HAS_UPDATED_RESET (1 << 1) #define HSMMC_HAS_HSPE_SUPPORT (1 << 2) - unsigned features; - - int switch_pin; /* gpio (card detect) */ - int gpio_wp; /* gpio (write protect) */ - - int (*set_power)(struct device *dev, int slot, - int power_on, int vdd); - int (*get_ro)(struct device *dev, int slot); - void (*remux)(struct device *dev, int slot, int power_on); - /* Call back before enabling / disabling regulators */ - void (*before_set_reg)(struct device *dev, int slot, - int power_on, int vdd); - /* Call back after enabling / disabling regulators */ - void (*after_set_reg)(struct device *dev, int slot, - int power_on, int vdd); - /* if we have special card, init it using this callback */ - void (*init_card)(struct mmc_card *card); - - /* return MMC cover switch state, can be NULL if not supported. - * - * possible return values: - * 0 - closed - * 1 - open - */ - int (*get_cover_state)(struct device *dev, int slot); - - const char *name; - u32 ocr_mask; - - /* Card detection IRQs */ - int card_detect_irq; - - int (*card_detect)(struct device *dev, int slot); - } slots[OMAP_HSMMC_MAX_SLOTS]; + unsigned features; + + int switch_pin; /* gpio (card detect) */ + int gpio_wp; /* gpio (write protect) */ + + int (*set_power)(struct device *dev, int slot, + int power_on, int vdd); + int (*get_ro)(struct device *dev, int slot); + void (*remux)(struct device *dev, int slot, int power_on); + /* Call back before enabling / disabling regulators */ + void (*before_set_reg)(struct device *dev, int slot, + int power_on, int vdd); + /* Call back after enabling / disabling regulators */ + void (*after_set_reg)(struct device *dev, int slot, + int power_on, int vdd); + /* if we have special card, init it using this callback */ + void (*init_card)(struct mmc_card *card); + + /* return MMC cover switch state, can be NULL if not supported. + * + * possible return values: + * 0 - closed + * 1 - open + */ + int (*get_cover_state)(struct device *dev, int slot); + + const char *name; + u32 ocr_mask; + + /* Card detection IRQs */ + int card_detect_irq; + + int (*card_detect)(struct device *dev, int slot); }; -- cgit v1.2.3-59-g8ed1b From 1e363e3b47bd9a0bddf1bfba8751240e0ecb3948 Mon Sep 17 00:00:00 2001 From: Andreas Fenkart Date: Sat, 8 Nov 2014 15:33:15 +0100 Subject: mmc: omap_hsmmc: pass mmc_priv struct to gpio init / free this is needed when installing callbacks in the host struct and not in the platform data, e.g. cover detect irq should be stored in omap_hsmmc_host and not platform data Acked-by: Tony Lindgren Signed-off-by: Andreas Fenkart Signed-off-by: Ulf Hansson --- drivers/mmc/host/omap_hsmmc.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 291b9e125d46..8a216c92c5a8 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -449,7 +449,8 @@ static inline int omap_hsmmc_have_reg(void) #endif -static int omap_hsmmc_gpio_init(struct omap_hsmmc_platform_data *pdata) +static int omap_hsmmc_gpio_init(struct omap_hsmmc_host *host, + struct omap_hsmmc_platform_data *pdata) { int ret; @@ -494,7 +495,8 @@ err_free_sp: return ret; } -static void omap_hsmmc_gpio_free(struct omap_hsmmc_platform_data *pdata) +static void omap_hsmmc_gpio_free(struct omap_hsmmc_host *host, + struct omap_hsmmc_platform_data *pdata) { if (gpio_is_valid(pdata->gpio_wp)) gpio_free(pdata->gpio_wp); @@ -2064,14 +2066,10 @@ static int omap_hsmmc_probe(struct platform_device *pdev) if (IS_ERR(base)) return PTR_ERR(base); - ret = omap_hsmmc_gpio_init(pdata); - if (ret) - goto err; - mmc = mmc_alloc_host(sizeof(struct omap_hsmmc_host), &pdev->dev); if (!mmc) { ret = -ENOMEM; - goto err_alloc; + goto err; } host = mmc_priv(mmc); @@ -2088,6 +2086,10 @@ static int omap_hsmmc_probe(struct platform_device *pdev) host->next_data.cookie = 1; host->pbias_enabled = 0; + ret = omap_hsmmc_gpio_init(host, pdata); + if (ret) + goto err_gpio; + platform_set_drvdata(pdev, host); if (pdev->dev.of_node) @@ -2283,9 +2285,9 @@ err_irq: if (host->dbclk) clk_disable_unprepare(host->dbclk); err1: + omap_hsmmc_gpio_free(host, pdata); +err_gpio: mmc_free_host(mmc); -err_alloc: - omap_hsmmc_gpio_free(pdata); err: return ret; } @@ -2309,7 +2311,7 @@ static int omap_hsmmc_remove(struct platform_device *pdev) if (host->dbclk) clk_disable_unprepare(host->dbclk); - omap_hsmmc_gpio_free(host->pdata); + omap_hsmmc_gpio_free(host, host->pdata); mmc_free_host(host->mmc); return 0; -- cgit v1.2.3-59-g8ed1b From b5cd43f062717b6c92f93bc0c593764e144ea331 Mon Sep 17 00:00:00 2001 From: Andreas Fenkart Date: Sat, 8 Nov 2014 15:33:16 +0100 Subject: mmc: omap_hsmmc: Remove unnecessary callbacks from platform data These callbacks are set during driver probe and not from the platform init, -- evtl. they had been for oamp 1/2 -- for omap3 they are local functions of the driver. These indirection could be dropped altogether in favor of regular function calls TODO Acked-by: Tony Lindgren Signed-off-by: Andreas Fenkart Signed-off-by: Ulf Hansson --- drivers/mmc/host/omap_hsmmc.c | 75 +++++++++++++++++++------------- include/linux/platform_data/hsmmc-omap.h | 18 -------- 2 files changed, 45 insertions(+), 48 deletions(-) diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 8a216c92c5a8..f4f1bcd632f3 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -221,6 +221,25 @@ struct omap_hsmmc_host { #define HSMMC_WAKE_IRQ_ENABLED (1 << 2) struct omap_hsmmc_next next_data; struct omap_hsmmc_platform_data *pdata; + + /* To handle board related suspend/resume functionality for MMC */ + int (*suspend)(struct device *dev, int slot); + int (*resume)(struct device *dev, int slot); + + /* return MMC cover switch state, can be NULL if not supported. + * + * possible return values: + * 0 - closed + * 1 - open + */ + int (*get_cover_state)(struct device *dev, int slot); + + /* Card detection IRQs */ + int card_detect_irq; + + int (*card_detect)(struct device *dev, int slot); + int (*get_ro)(struct device *dev, int slot); + }; struct omap_mmc_of_data { @@ -262,18 +281,16 @@ static int omap_hsmmc_get_cover_state(struct device *dev, int slot) static int omap_hsmmc_suspend_cdirq(struct device *dev, int slot) { struct omap_hsmmc_host *host = dev_get_drvdata(dev); - struct omap_hsmmc_platform_data *mmc = host->pdata; - disable_irq(mmc->card_detect_irq); + disable_irq(host->card_detect_irq); return 0; } static int omap_hsmmc_resume_cdirq(struct device *dev, int slot) { struct omap_hsmmc_host *host = dev_get_drvdata(dev); - struct omap_hsmmc_platform_data *mmc = host->pdata; - enable_irq(mmc->card_detect_irq); + enable_irq(host->card_detect_irq); return 0; } @@ -456,11 +473,11 @@ static int omap_hsmmc_gpio_init(struct omap_hsmmc_host *host, if (gpio_is_valid(pdata->switch_pin)) { if (pdata->cover) - pdata->get_cover_state = - omap_hsmmc_get_cover_state; + host->get_cover_state = + omap_hsmmc_get_cover_state; else - pdata->card_detect = omap_hsmmc_card_detect; - pdata->card_detect_irq = + host->card_detect = omap_hsmmc_card_detect; + host->card_detect_irq = gpio_to_irq(pdata->switch_pin); ret = gpio_request(pdata->switch_pin, "mmc_cd"); if (ret) @@ -473,7 +490,7 @@ static int omap_hsmmc_gpio_init(struct omap_hsmmc_host *host, } if (gpio_is_valid(pdata->gpio_wp)) { - pdata->get_ro = omap_hsmmc_get_wp; + host->get_ro = omap_hsmmc_get_wp; ret = gpio_request(pdata->gpio_wp, "mmc_wp"); if (ret) goto err_free_cd; @@ -795,8 +812,8 @@ int omap_hsmmc_cover_is_closed(struct omap_hsmmc_host *host) { int r = 1; - if (mmc_pdata(host)->get_cover_state) - r = mmc_pdata(host)->get_cover_state(host->dev, host->slot_id); + if (host->get_cover_state) + r = host->get_cover_state(host->dev, host->slot_id); return r; } @@ -1263,11 +1280,11 @@ err: /* Protect the card while the cover is open */ static void omap_hsmmc_protect_card(struct omap_hsmmc_host *host) { - if (!mmc_pdata(host)->get_cover_state) + if (!host->get_cover_state) return; host->reqs_blocked = 0; - if (mmc_pdata(host)->get_cover_state(host->dev, host->slot_id)) { + if (host->get_cover_state(host->dev, host->slot_id)) { if (host->protect_card) { dev_info(host->dev, "%s: cover is closed, " "card is now accessible\n", @@ -1290,13 +1307,12 @@ static void omap_hsmmc_protect_card(struct omap_hsmmc_host *host) static irqreturn_t omap_hsmmc_detect(int irq, void *dev_id) { struct omap_hsmmc_host *host = dev_id; - struct omap_hsmmc_platform_data *pdata = host->pdata; int carddetect; sysfs_notify(&host->mmc->class_dev.kobj, NULL, "cover_switch"); - if (pdata->card_detect) - carddetect = pdata->card_detect(host->dev, host->slot_id); + if (host->card_detect) + carddetect = host->card_detect(host->dev, host->slot_id); else { omap_hsmmc_protect_card(host); carddetect = -ENOSYS; @@ -1672,18 +1688,18 @@ static int omap_hsmmc_get_cd(struct mmc_host *mmc) { struct omap_hsmmc_host *host = mmc_priv(mmc); - if (!mmc_pdata(host)->card_detect) + if (!host->card_detect) return -ENOSYS; - return mmc_pdata(host)->card_detect(host->dev, host->slot_id); + return host->card_detect(host->dev, host->slot_id); } static int omap_hsmmc_get_ro(struct mmc_host *mmc) { struct omap_hsmmc_host *host = mmc_priv(mmc); - if (!mmc_pdata(host)->get_ro) + if (!host->get_ro) return -ENOSYS; - return mmc_pdata(host)->get_ro(host->dev, 0); + return host->get_ro(host->dev, 0); } static void omap_hsmmc_init_card(struct mmc_host *mmc, struct mmc_card *card) @@ -2218,9 +2234,9 @@ static int omap_hsmmc_probe(struct platform_device *pdev) mmc->ocr_avail = mmc_pdata(host)->ocr_mask; /* Request IRQ for card detect */ - if ((mmc_pdata(host)->card_detect_irq)) { + if (host->card_detect_irq) { ret = devm_request_threaded_irq(&pdev->dev, - mmc_pdata(host)->card_detect_irq, + host->card_detect_irq, NULL, omap_hsmmc_detect, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, mmc_hostname(mmc), host); @@ -2229,8 +2245,8 @@ static int omap_hsmmc_probe(struct platform_device *pdev) "Unable to grab MMC CD IRQ\n"); goto err_irq_cd; } - pdata->suspend = omap_hsmmc_suspend_cdirq; - pdata->resume = omap_hsmmc_resume_cdirq; + host->suspend = omap_hsmmc_suspend_cdirq; + host->resume = omap_hsmmc_resume_cdirq; } omap_hsmmc_disable_irq(host); @@ -2256,8 +2272,7 @@ static int omap_hsmmc_probe(struct platform_device *pdev) if (ret < 0) goto err_slot_name; } - if (mmc_pdata(host)->card_detect_irq && - mmc_pdata(host)->get_cover_state) { + if (host->card_detect_irq && host->get_cover_state) { ret = device_create_file(&mmc->class_dev, &dev_attr_cover_switch); if (ret < 0) @@ -2322,8 +2337,8 @@ static int omap_hsmmc_prepare(struct device *dev) { struct omap_hsmmc_host *host = dev_get_drvdata(dev); - if (host->pdata->suspend) - return host->pdata->suspend(dev, host->slot_id); + if (host->suspend) + return host->suspend(dev, host->slot_id); return 0; } @@ -2332,8 +2347,8 @@ static void omap_hsmmc_complete(struct device *dev) { struct omap_hsmmc_host *host = dev_get_drvdata(dev); - if (host->pdata->resume) - host->pdata->resume(dev, host->slot_id); + if (host->resume) + host->resume(dev, host->slot_id); } diff --git a/include/linux/platform_data/hsmmc-omap.h b/include/linux/platform_data/hsmmc-omap.h index 26912143adc0..68ffec14b56a 100644 --- a/include/linux/platform_data/hsmmc-omap.h +++ b/include/linux/platform_data/hsmmc-omap.h @@ -45,10 +45,6 @@ struct omap_hsmmc_platform_data { * maximum frequency on the MMC bus */ unsigned int max_freq; - /* To handle board related suspend/resume functionality for MMC */ - int (*suspend)(struct device *dev, int slot); - int (*resume)(struct device *dev, int slot); - /* Integrating attributes from the omap_hwmod layer */ u8 controller_flags; @@ -85,7 +81,6 @@ struct omap_hsmmc_platform_data { int (*set_power)(struct device *dev, int slot, int power_on, int vdd); - int (*get_ro)(struct device *dev, int slot); void (*remux)(struct device *dev, int slot, int power_on); /* Call back before enabling / disabling regulators */ void (*before_set_reg)(struct device *dev, int slot, @@ -96,19 +91,6 @@ struct omap_hsmmc_platform_data { /* if we have special card, init it using this callback */ void (*init_card)(struct mmc_card *card); - /* return MMC cover switch state, can be NULL if not supported. - * - * possible return values: - * 0 - closed - * 1 - open - */ - int (*get_cover_state)(struct device *dev, int slot); - const char *name; u32 ocr_mask; - - /* Card detection IRQs */ - int card_detect_irq; - - int (*card_detect)(struct device *dev, int slot); }; -- cgit v1.2.3-59-g8ed1b From 80412ca8abf087354891108d2f888ad3de56e73c Mon Sep 17 00:00:00 2001 From: Andreas Fenkart Date: Sat, 8 Nov 2014 15:33:17 +0100 Subject: mmc: omap_hsmmc: remove unused slot_id parameter omap_hsmmc only supports one slot. So slot id is always zero, and slot id was never used in the callbacks anyway Acked-by: Tony Lindgren Signed-off-by: Andreas Fenkart Signed-off-by: Ulf Hansson --- arch/arm/mach-omap2/board-rx51-peripherals.c | 2 +- arch/arm/mach-omap2/hsmmc.c | 21 ++++----- arch/arm/mach-omap2/hsmmc.h | 2 +- drivers/mmc/host/omap_hsmmc.c | 65 +++++++++++----------------- include/linux/platform_data/hsmmc-omap.h | 14 ++---- 5 files changed, 40 insertions(+), 64 deletions(-) diff --git a/arch/arm/mach-omap2/board-rx51-peripherals.c b/arch/arm/mach-omap2/board-rx51-peripherals.c index 0a8ac844b75b..3d5040f82e90 100644 --- a/arch/arm/mach-omap2/board-rx51-peripherals.c +++ b/arch/arm/mach-omap2/board-rx51-peripherals.c @@ -484,7 +484,7 @@ static struct omap_mux_partition *partition; * Current flows to eMMC when eMMC is off and the data lines are pulled up, * so pull them down. N.B. we pull 8 lines because we are using 8 lines. */ -static void rx51_mmc2_remux(struct device *dev, int slot, int power_on) +static void rx51_mmc2_remux(struct device *dev, int power_on) { if (power_on) omap_mux_write_array(partition, rx51_mmc2_on_mux); diff --git a/arch/arm/mach-omap2/hsmmc.c b/arch/arm/mach-omap2/hsmmc.c index 4e2896ad0119..dc6e79c4484a 100644 --- a/arch/arm/mach-omap2/hsmmc.c +++ b/arch/arm/mach-omap2/hsmmc.c @@ -33,14 +33,14 @@ static u16 control_devconf1_offset; #define HSMMC_NAME_LEN 9 -static void omap_hsmmc1_before_set_reg(struct device *dev, int slot, - int power_on, int vdd) +static void omap_hsmmc1_before_set_reg(struct device *dev, + int power_on, int vdd) { u32 reg, prog_io; struct omap_hsmmc_platform_data *mmc = dev->platform_data; if (mmc->remux) - mmc->remux(dev, slot, power_on); + mmc->remux(dev, power_on); /* * Assume we power both OMAP VMMC1 (for CMD, CLK, DAT0..3) and the @@ -86,8 +86,7 @@ static void omap_hsmmc1_before_set_reg(struct device *dev, int slot, } } -static void omap_hsmmc1_after_set_reg(struct device *dev, int slot, - int power_on, int vdd) +static void omap_hsmmc1_after_set_reg(struct device *dev, int power_on, int vdd) { u32 reg; @@ -122,20 +121,18 @@ static void hsmmc2_select_input_clk_src(struct omap_hsmmc_platform_data *mmc) omap_ctrl_writel(reg, control_devconf1_offset); } -static void hsmmc2_before_set_reg(struct device *dev, int slot, - int power_on, int vdd) +static void hsmmc2_before_set_reg(struct device *dev, int power_on, int vdd) { struct omap_hsmmc_platform_data *mmc = dev->platform_data; if (mmc->remux) - mmc->remux(dev, slot, power_on); + mmc->remux(dev, power_on); if (power_on) hsmmc2_select_input_clk_src(mmc); } -static int am35x_hsmmc2_set_power(struct device *dev, int slot, - int power_on, int vdd) +static int am35x_hsmmc2_set_power(struct device *dev, int power_on, int vdd) { struct omap_hsmmc_platform_data *mmc = dev->platform_data; @@ -145,8 +142,7 @@ static int am35x_hsmmc2_set_power(struct device *dev, int slot, return 0; } -static int nop_mmc_set_power(struct device *dev, int slot, int power_on, - int vdd) +static int nop_mmc_set_power(struct device *dev, int power_on, int vdd) { return 0; } @@ -250,7 +246,6 @@ static int __init omap_hsmmc_pdata_init(struct omap2_hsmmc_info *c, snprintf(hc_name, (HSMMC_NAME_LEN + 1), "mmc%islot%i", c->mmc, 1); mmc->name = hc_name; - mmc->nr_slots = 1; mmc->caps = c->caps; mmc->internal_clock = !c->ext_clock; mmc->reg_offset = 0; diff --git a/arch/arm/mach-omap2/hsmmc.h b/arch/arm/mach-omap2/hsmmc.h index 30c78c17eb7e..148cd9b15499 100644 --- a/arch/arm/mach-omap2/hsmmc.h +++ b/arch/arm/mach-omap2/hsmmc.h @@ -23,7 +23,7 @@ struct omap2_hsmmc_info { struct platform_device *pdev; /* mmc controller instance */ int ocr_mask; /* temporary HACK */ /* Remux (pad configuration) when powering on/off */ - void (*remux)(struct device *dev, int slot, int power_on); + void (*remux)(struct device *dev, int power_on); /* init some special card */ void (*init_card)(struct mmc_card *card); }; diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index f4f1bcd632f3..82b40b85293f 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -207,7 +207,6 @@ struct omap_hsmmc_host { int use_dma, dma_ch; struct dma_chan *tx_chan; struct dma_chan *rx_chan; - int slot_id; int response_busy; int context_loss; int protect_card; @@ -223,8 +222,8 @@ struct omap_hsmmc_host { struct omap_hsmmc_platform_data *pdata; /* To handle board related suspend/resume functionality for MMC */ - int (*suspend)(struct device *dev, int slot); - int (*resume)(struct device *dev, int slot); + int (*suspend)(struct device *dev); + int (*resume)(struct device *dev); /* return MMC cover switch state, can be NULL if not supported. * @@ -232,13 +231,13 @@ struct omap_hsmmc_host { * 0 - closed * 1 - open */ - int (*get_cover_state)(struct device *dev, int slot); + int (*get_cover_state)(struct device *dev); /* Card detection IRQs */ int card_detect_irq; - int (*card_detect)(struct device *dev, int slot); - int (*get_ro)(struct device *dev, int slot); + int (*card_detect)(struct device *dev); + int (*get_ro)(struct device *dev); }; @@ -249,7 +248,7 @@ struct omap_mmc_of_data { static void omap_hsmmc_start_dma_transfer(struct omap_hsmmc_host *host); -static int omap_hsmmc_card_detect(struct device *dev, int slot) +static int omap_hsmmc_card_detect(struct device *dev) { struct omap_hsmmc_host *host = dev_get_drvdata(dev); struct omap_hsmmc_platform_data *mmc = host->pdata; @@ -258,7 +257,7 @@ static int omap_hsmmc_card_detect(struct device *dev, int slot) return !gpio_get_value_cansleep(mmc->switch_pin); } -static int omap_hsmmc_get_wp(struct device *dev, int slot) +static int omap_hsmmc_get_wp(struct device *dev) { struct omap_hsmmc_host *host = dev_get_drvdata(dev); struct omap_hsmmc_platform_data *mmc = host->pdata; @@ -267,7 +266,7 @@ static int omap_hsmmc_get_wp(struct device *dev, int slot) return gpio_get_value_cansleep(mmc->gpio_wp); } -static int omap_hsmmc_get_cover_state(struct device *dev, int slot) +static int omap_hsmmc_get_cover_state(struct device *dev) { struct omap_hsmmc_host *host = dev_get_drvdata(dev); struct omap_hsmmc_platform_data *mmc = host->pdata; @@ -278,7 +277,7 @@ static int omap_hsmmc_get_cover_state(struct device *dev, int slot) #ifdef CONFIG_PM -static int omap_hsmmc_suspend_cdirq(struct device *dev, int slot) +static int omap_hsmmc_suspend_cdirq(struct device *dev) { struct omap_hsmmc_host *host = dev_get_drvdata(dev); @@ -286,7 +285,7 @@ static int omap_hsmmc_suspend_cdirq(struct device *dev, int slot) return 0; } -static int omap_hsmmc_resume_cdirq(struct device *dev, int slot) +static int omap_hsmmc_resume_cdirq(struct device *dev) { struct omap_hsmmc_host *host = dev_get_drvdata(dev); @@ -303,8 +302,7 @@ static int omap_hsmmc_resume_cdirq(struct device *dev, int slot) #ifdef CONFIG_REGULATOR -static int omap_hsmmc_set_power(struct device *dev, int slot, int power_on, - int vdd) +static int omap_hsmmc_set_power(struct device *dev, int power_on, int vdd) { struct omap_hsmmc_host *host = platform_get_drvdata(to_platform_device(dev)); @@ -318,7 +316,7 @@ static int omap_hsmmc_set_power(struct device *dev, int slot, int power_on, return 0; if (mmc_pdata(host)->before_set_reg) - mmc_pdata(host)->before_set_reg(dev, slot, power_on, vdd); + mmc_pdata(host)->before_set_reg(dev, power_on, vdd); if (host->pbias) { if (host->pbias_enabled == 1) { @@ -381,7 +379,7 @@ static int omap_hsmmc_set_power(struct device *dev, int slot, int power_on, } if (mmc_pdata(host)->after_set_reg) - mmc_pdata(host)->after_set_reg(dev, slot, power_on, vdd); + mmc_pdata(host)->after_set_reg(dev, power_on, vdd); error_set_power: return ret; @@ -431,8 +429,8 @@ static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host) (host->vcc_aux && regulator_is_enabled(host->vcc_aux))) { int vdd = ffs(mmc_pdata(host)->ocr_mask) - 1; - mmc_pdata(host)->set_power(host->dev, host->slot_id, 1, vdd); - mmc_pdata(host)->set_power(host->dev, host->slot_id, 0, 0); + mmc_pdata(host)->set_power(host->dev, 1, vdd); + mmc_pdata(host)->set_power(host->dev, 0, 0); } return 0; @@ -813,7 +811,7 @@ int omap_hsmmc_cover_is_closed(struct omap_hsmmc_host *host) int r = 1; if (host->get_cover_state) - r = host->get_cover_state(host->dev, host->slot_id); + r = host->get_cover_state(host->dev); return r; } @@ -1231,12 +1229,11 @@ static int omap_hsmmc_switch_opcond(struct omap_hsmmc_host *host, int vdd) clk_disable_unprepare(host->dbclk); /* Turn the power off */ - ret = mmc_pdata(host)->set_power(host->dev, host->slot_id, 0, 0); + ret = mmc_pdata(host)->set_power(host->dev, 0, 0); /* Turn the power ON with given VDD 1.8 or 3.0v */ if (!ret) - ret = mmc_pdata(host)->set_power(host->dev, host->slot_id, 1, - vdd); + ret = mmc_pdata(host)->set_power(host->dev, 1, vdd); pm_runtime_get_sync(host->dev); if (host->dbclk) clk_prepare_enable(host->dbclk); @@ -1284,7 +1281,7 @@ static void omap_hsmmc_protect_card(struct omap_hsmmc_host *host) return; host->reqs_blocked = 0; - if (host->get_cover_state(host->dev, host->slot_id)) { + if (host->get_cover_state(host->dev)) { if (host->protect_card) { dev_info(host->dev, "%s: cover is closed, " "card is now accessible\n", @@ -1312,7 +1309,7 @@ static irqreturn_t omap_hsmmc_detect(int irq, void *dev_id) sysfs_notify(&host->mmc->class_dev.kobj, NULL, "cover_switch"); if (host->card_detect) - carddetect = host->card_detect(host->dev, host->slot_id); + carddetect = host->card_detect(host->dev); else { omap_hsmmc_protect_card(host); carddetect = -ENOSYS; @@ -1638,12 +1635,10 @@ static void omap_hsmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) if (ios->power_mode != host->power_mode) { switch (ios->power_mode) { case MMC_POWER_OFF: - mmc_pdata(host)->set_power(host->dev, host->slot_id, - 0, 0); + mmc_pdata(host)->set_power(host->dev, 0, 0); break; case MMC_POWER_UP: - mmc_pdata(host)->set_power(host->dev, host->slot_id, - 1, ios->vdd); + mmc_pdata(host)->set_power(host->dev, 1, ios->vdd); break; case MMC_POWER_ON: do_send_init_stream = 1; @@ -1690,7 +1685,7 @@ static int omap_hsmmc_get_cd(struct mmc_host *mmc) if (!host->card_detect) return -ENOSYS; - return host->card_detect(host->dev, host->slot_id); + return host->card_detect(host->dev); } static int omap_hsmmc_get_ro(struct mmc_host *mmc) @@ -1699,7 +1694,7 @@ static int omap_hsmmc_get_ro(struct mmc_host *mmc) if (!host->get_ro) return -ENOSYS; - return host->get_ro(host->dev, 0); + return host->get_ro(host->dev); } static void omap_hsmmc_init_card(struct mmc_host *mmc, struct mmc_card *card) @@ -1996,8 +1991,6 @@ static struct omap_hsmmc_platform_data *of_get_hsmmc_pdata(struct device *dev) if (of_find_property(np, "ti,dual-volt", NULL)) pdata->controller_flags |= OMAP_HSMMC_SUPPORTS_DUAL_VOLT; - /* This driver only supports 1 slot */ - pdata->nr_slots = 1; pdata->switch_pin = cd_gpio; pdata->gpio_wp = wp_gpio; @@ -2068,11 +2061,6 @@ static int omap_hsmmc_probe(struct platform_device *pdev) return -ENXIO; } - if (pdata->nr_slots == 0) { - dev_err(&pdev->dev, "No Slots\n"); - return -ENXIO; - } - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); irq = platform_get_irq(pdev, 0); if (res == NULL || irq < 0) @@ -2095,7 +2083,6 @@ static int omap_hsmmc_probe(struct platform_device *pdev) host->use_dma = 1; host->dma_ch = -1; host->irq = irq; - host->slot_id = 0; host->mapbase = res->start + pdata->reg_offset; host->base = base + pdata->reg_offset; host->power_mode = MMC_POWER_OFF; @@ -2338,7 +2325,7 @@ static int omap_hsmmc_prepare(struct device *dev) struct omap_hsmmc_host *host = dev_get_drvdata(dev); if (host->suspend) - return host->suspend(dev, host->slot_id); + return host->suspend(dev); return 0; } @@ -2348,7 +2335,7 @@ static void omap_hsmmc_complete(struct device *dev) struct omap_hsmmc_host *host = dev_get_drvdata(dev); if (host->resume) - host->resume(dev, host->slot_id); + host->resume(dev); } diff --git a/include/linux/platform_data/hsmmc-omap.h b/include/linux/platform_data/hsmmc-omap.h index 68ffec14b56a..67bbcf0785f6 100644 --- a/include/linux/platform_data/hsmmc-omap.h +++ b/include/linux/platform_data/hsmmc-omap.h @@ -38,9 +38,6 @@ struct omap_hsmmc_platform_data { /* back-link to device */ struct device *dev; - /* number of slots per controller */ - unsigned nr_slots:2; - /* set if your board has components or wiring that limits the * maximum frequency on the MMC bus */ unsigned int max_freq; @@ -79,15 +76,12 @@ struct omap_hsmmc_platform_data { int switch_pin; /* gpio (card detect) */ int gpio_wp; /* gpio (write protect) */ - int (*set_power)(struct device *dev, int slot, - int power_on, int vdd); - void (*remux)(struct device *dev, int slot, int power_on); + int (*set_power)(struct device *dev, int power_on, int vdd); + void (*remux)(struct device *dev, int power_on); /* Call back before enabling / disabling regulators */ - void (*before_set_reg)(struct device *dev, int slot, - int power_on, int vdd); + void (*before_set_reg)(struct device *dev, int power_on, int vdd); /* Call back after enabling / disabling regulators */ - void (*after_set_reg)(struct device *dev, int slot, - int power_on, int vdd); + void (*after_set_reg)(struct device *dev, int power_on, int vdd); /* if we have special card, init it using this callback */ void (*init_card)(struct mmc_card *card); -- cgit v1.2.3-59-g8ed1b From 2d079c43bc5ade7b41610b356bf117e14037a584 Mon Sep 17 00:00:00 2001 From: Johan Rudholm Date: Thu, 6 Nov 2014 14:46:54 +0100 Subject: mmc: core: consistent handling of initial values mmc_do_hw_reset(), mmc_power_up() and mmc_power_off() all set similar initial values for bus_mode, bus_width, chip_select and timing. Let's make this handling simpler and more consistent by sticking them together in a common function. This will introduce small changes in behavior in the following places: mmc_power_off(): For SPI hosts, explicitly set bus_mode = MMC_BUSMODE_PUSHPULL and chip_select = MMC_CS_HIGH, before we left them as they were. For non-SPI hosts, set bus_mode = MMC_BUSMODE_PUSHPULL instead of MMC_BUSMODE_OPENDRAIN as before. These two changes should not be a problem since the device will be powered off anyway. mmc_do_hw_reset(): Always set bus_mode = MMC_BUSMODE_PUSHPULL, as required by SD/SDIO cards. MMC cards require MMC_BUSMODE_OPENDRAIN, but this is taken care of by mmc_init_card() and mmc_attach_mmc(). Signed-off-by: Johan Rudholm Signed-off-by: Ulf Hansson --- drivers/mmc/core/core.c | 47 ++++++++++++++++++++++------------------------- drivers/mmc/core/core.h | 1 + 2 files changed, 23 insertions(+), 25 deletions(-) diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index a32bea23e70c..5bda29bff8eb 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -1099,6 +1099,22 @@ void mmc_set_bus_width(struct mmc_host *host, unsigned int width) mmc_host_clk_release(host); } +/* + * Set initial state after a power cycle or a hw_reset. + */ +void mmc_set_initial_state(struct mmc_host *host) +{ + if (mmc_host_is_spi(host)) + host->ios.chip_select = MMC_CS_HIGH; + else + host->ios.chip_select = MMC_CS_DONTCARE; + host->ios.bus_mode = MMC_BUSMODE_PUSHPULL; + host->ios.bus_width = MMC_BUS_WIDTH_1; + host->ios.timing = MMC_TIMING_LEGACY; + + mmc_set_ios(host); +} + /** * mmc_vdd_to_ocrbitnum - Convert a voltage to the OCR bit number * @vdd: voltage (mV) @@ -1537,15 +1553,9 @@ void mmc_power_up(struct mmc_host *host, u32 ocr) mmc_host_clk_hold(host); host->ios.vdd = fls(ocr) - 1; - if (mmc_host_is_spi(host)) - host->ios.chip_select = MMC_CS_HIGH; - else - host->ios.chip_select = MMC_CS_DONTCARE; - host->ios.bus_mode = MMC_BUSMODE_PUSHPULL; host->ios.power_mode = MMC_POWER_UP; - host->ios.bus_width = MMC_BUS_WIDTH_1; - host->ios.timing = MMC_TIMING_LEGACY; - mmc_set_ios(host); + /* Set initial state and call mmc_set_ios */ + 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) @@ -1585,14 +1595,9 @@ void mmc_power_off(struct mmc_host *host) host->ios.clock = 0; host->ios.vdd = 0; - if (!mmc_host_is_spi(host)) { - host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN; - host->ios.chip_select = MMC_CS_DONTCARE; - } host->ios.power_mode = MMC_POWER_OFF; - host->ios.bus_width = MMC_BUS_WIDTH_1; - host->ios.timing = MMC_TIMING_LEGACY; - mmc_set_ios(host); + /* Set initial state and call mmc_set_ios */ + mmc_set_initial_state(host); /* * Some configurations, such as the 802.11 SDIO card in the OLPC @@ -2278,16 +2283,8 @@ static int mmc_do_hw_reset(struct mmc_host *host, int check) } } - if (mmc_host_is_spi(host)) { - host->ios.chip_select = MMC_CS_HIGH; - host->ios.bus_mode = MMC_BUSMODE_PUSHPULL; - } else { - host->ios.chip_select = MMC_CS_DONTCARE; - host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN; - } - host->ios.bus_width = MMC_BUS_WIDTH_1; - host->ios.timing = MMC_TIMING_LEGACY; - mmc_set_ios(host); + /* Set initial state and call mmc_set_ios */ + mmc_set_initial_state(host); mmc_host_clk_release(host); diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h index 443a584660f0..d76597c65e3a 100644 --- a/drivers/mmc/core/core.h +++ b/drivers/mmc/core/core.h @@ -49,6 +49,7 @@ void mmc_set_driver_type(struct mmc_host *host, unsigned int drv_type); void mmc_power_up(struct mmc_host *host, u32 ocr); void mmc_power_off(struct mmc_host *host); void mmc_power_cycle(struct mmc_host *host, u32 ocr); +void mmc_set_initial_state(struct mmc_host *host); static inline void mmc_delay(unsigned int ms) { -- cgit v1.2.3-59-g8ed1b From 89ad2be75a4287126f9f5473ecf167bd9b91093d Mon Sep 17 00:00:00 2001 From: Abhilash Kesavan Date: Thu, 28 Aug 2014 18:48:53 +0530 Subject: mmc: dw_mmc: exynos: Add support for exynos7 The Exynos7 has a DWMMC controller (v2.70a) which is different from prior versions. This patch adds new compatible strings for exynos7. This patch also fixes the CLKSEL register offset on exynos7. Signed-off-by: Abhilash Kesavan Signed-off-by: Yuvaraj Kumar C D Tested-by: Vivek Gautam Acked-by: Jaehoon Chung Signed-off-by: Ulf Hansson --- .../devicetree/bindings/mmc/exynos-dw-mshc.txt | 4 + drivers/mmc/host/dw_mmc-exynos.c | 91 ++++++++++++++++++---- 2 files changed, 82 insertions(+), 13 deletions(-) diff --git a/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt b/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt index 6cd3525d0e09..ee4fc0576c7d 100644 --- a/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt +++ b/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt @@ -18,6 +18,10 @@ Required Properties: specific extensions. - "samsung,exynos5420-dw-mshc": for controllers with Samsung Exynos5420 specific extensions. + - "samsung,exynos7-dw-mshc": for controllers with Samsung Exynos7 + specific extensions. + - "samsung,exynos7-dw-mshc-smu": for controllers with Samsung Exynos7 + specific extensions having an SMU. * samsung,dw-mshc-ciu-div: Specifies the divider value for the card interface unit (ciu) clock. This property is applicable only for Exynos5 SoC's and diff --git a/drivers/mmc/host/dw_mmc-exynos.c b/drivers/mmc/host/dw_mmc-exynos.c index 0fbc53ac7eae..509365cb22c6 100644 --- a/drivers/mmc/host/dw_mmc-exynos.c +++ b/drivers/mmc/host/dw_mmc-exynos.c @@ -25,6 +25,7 @@ #define NUM_PINS(x) (x + 2) #define SDMMC_CLKSEL 0x09C +#define SDMMC_CLKSEL64 0x0A8 #define SDMMC_CLKSEL_CCLK_SAMPLE(x) (((x) & 7) << 0) #define SDMMC_CLKSEL_CCLK_DRIVE(x) (((x) & 7) << 16) #define SDMMC_CLKSEL_CCLK_DIVIDER(x) (((x) & 7) << 24) @@ -65,6 +66,8 @@ enum dw_mci_exynos_type { DW_MCI_TYPE_EXYNOS5250, DW_MCI_TYPE_EXYNOS5420, DW_MCI_TYPE_EXYNOS5420_SMU, + DW_MCI_TYPE_EXYNOS7, + DW_MCI_TYPE_EXYNOS7_SMU, }; /* Exynos implementation specific driver private data */ @@ -95,6 +98,12 @@ static struct dw_mci_exynos_compatible { }, { .compatible = "samsung,exynos5420-dw-mshc-smu", .ctrl_type = DW_MCI_TYPE_EXYNOS5420_SMU, + }, { + .compatible = "samsung,exynos7-dw-mshc", + .ctrl_type = DW_MCI_TYPE_EXYNOS7, + }, { + .compatible = "samsung,exynos7-dw-mshc-smu", + .ctrl_type = DW_MCI_TYPE_EXYNOS7_SMU, }, }; @@ -102,7 +111,8 @@ static int dw_mci_exynos_priv_init(struct dw_mci *host) { struct dw_mci_exynos_priv_data *priv = host->priv; - if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS5420_SMU) { + if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS5420_SMU || + priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU) { mci_writel(host, MPSBEGIN0, 0); mci_writel(host, MPSEND0, DWMCI_BLOCK_NUM); mci_writel(host, MPSCTRL0, DWMCI_MPSCTRL_SECURE_WRITE_BIT | @@ -153,11 +163,22 @@ static int dw_mci_exynos_resume(struct device *dev) static int dw_mci_exynos_resume_noirq(struct device *dev) { struct dw_mci *host = dev_get_drvdata(dev); + struct dw_mci_exynos_priv_data *priv = host->priv; u32 clksel; - clksel = mci_readl(host, CLKSEL); - if (clksel & SDMMC_CLKSEL_WAKEUP_INT) - mci_writel(host, CLKSEL, clksel); + if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || + priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU) + clksel = mci_readl(host, CLKSEL64); + else + clksel = mci_readl(host, CLKSEL); + + if (clksel & SDMMC_CLKSEL_WAKEUP_INT) { + if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || + priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU) + mci_writel(host, CLKSEL64, clksel); + else + mci_writel(host, CLKSEL, clksel); + } return 0; } @@ -169,6 +190,7 @@ static int dw_mci_exynos_resume_noirq(struct device *dev) static void dw_mci_exynos_prepare_command(struct dw_mci *host, u32 *cmdr) { + struct dw_mci_exynos_priv_data *priv = host->priv; /* * Exynos4412 and Exynos5250 extends the use of CMD register with the * use of bit 29 (which is reserved on standard MSHC controllers) for @@ -176,8 +198,14 @@ static void dw_mci_exynos_prepare_command(struct dw_mci *host, u32 *cmdr) * HOLD register should be bypassed in case there is no phase shift * applied on CMD/DATA that is sent to the card. */ - if (SDMMC_CLKSEL_GET_DRV_WD3(mci_readl(host, CLKSEL))) - *cmdr |= SDMMC_CMD_USE_HOLD_REG; + if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || + priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU) { + if (SDMMC_CLKSEL_GET_DRV_WD3(mci_readl(host, CLKSEL64))) + *cmdr |= SDMMC_CMD_USE_HOLD_REG; + } else { + if (SDMMC_CLKSEL_GET_DRV_WD3(mci_readl(host, CLKSEL))) + *cmdr |= SDMMC_CMD_USE_HOLD_REG; + } } static void dw_mci_exynos_set_ios(struct dw_mci *host, struct mmc_ios *ios) @@ -188,12 +216,20 @@ static void dw_mci_exynos_set_ios(struct dw_mci *host, struct mmc_ios *ios) u8 div = priv->ciu_div + 1; if (ios->timing == MMC_TIMING_MMC_DDR52) { - mci_writel(host, CLKSEL, priv->ddr_timing); + if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || + priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU) + mci_writel(host, CLKSEL64, priv->ddr_timing); + else + mci_writel(host, CLKSEL, priv->ddr_timing); /* Should be double rate for DDR mode */ if (ios->bus_width == MMC_BUS_WIDTH_8) wanted <<= 1; } else { - mci_writel(host, CLKSEL, priv->sdr_timing); + if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || + priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU) + mci_writel(host, CLKSEL64, priv->sdr_timing); + else + mci_writel(host, CLKSEL, priv->sdr_timing); } /* Don't care if wanted clock is zero */ @@ -265,26 +301,51 @@ static int dw_mci_exynos_parse_dt(struct dw_mci *host) static inline u8 dw_mci_exynos_get_clksmpl(struct dw_mci *host) { - return SDMMC_CLKSEL_CCLK_SAMPLE(mci_readl(host, CLKSEL)); + struct dw_mci_exynos_priv_data *priv = host->priv; + + if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || + priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU) + return SDMMC_CLKSEL_CCLK_SAMPLE(mci_readl(host, CLKSEL64)); + else + return SDMMC_CLKSEL_CCLK_SAMPLE(mci_readl(host, CLKSEL)); } static inline void dw_mci_exynos_set_clksmpl(struct dw_mci *host, u8 sample) { u32 clksel; - clksel = mci_readl(host, CLKSEL); + struct dw_mci_exynos_priv_data *priv = host->priv; + + if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || + priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU) + clksel = mci_readl(host, CLKSEL64); + else + clksel = mci_readl(host, CLKSEL); clksel = (clksel & ~0x7) | SDMMC_CLKSEL_CCLK_SAMPLE(sample); - mci_writel(host, CLKSEL, clksel); + if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || + priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU) + mci_writel(host, CLKSEL64, clksel); + else + mci_writel(host, CLKSEL, clksel); } static inline u8 dw_mci_exynos_move_next_clksmpl(struct dw_mci *host) { + struct dw_mci_exynos_priv_data *priv = host->priv; u32 clksel; u8 sample; - clksel = mci_readl(host, CLKSEL); + if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || + priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU) + clksel = mci_readl(host, CLKSEL64); + else + clksel = mci_readl(host, CLKSEL); sample = (clksel + 1) & 0x7; clksel = (clksel & ~0x7) | sample; - mci_writel(host, CLKSEL, clksel); + if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || + priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU) + mci_writel(host, CLKSEL64, clksel); + else + mci_writel(host, CLKSEL, clksel); return sample; } @@ -411,6 +472,10 @@ static const struct of_device_id dw_mci_exynos_match[] = { .data = &exynos_drv_data, }, { .compatible = "samsung,exynos5420-dw-mshc-smu", .data = &exynos_drv_data, }, + { .compatible = "samsung,exynos7-dw-mshc", + .data = &exynos_drv_data, }, + { .compatible = "samsung,exynos7-dw-mshc-smu", + .data = &exynos_drv_data, }, {}, }; MODULE_DEVICE_TABLE(of, dw_mci_exynos_match); -- cgit v1.2.3-59-g8ed1b From a5eb8bbd66ccf9f169419f9652544aec771b7c57 Mon Sep 17 00:00:00 2001 From: Ondrej Zary Date: Tue, 11 Nov 2014 17:54:55 +0100 Subject: mmc: add Toshiba PCI SD controller driver This patch resurrects an old never-finished driver for Toshiba PCI SD controllers found in some older Toshiba laptops (such as Portege R100): 02:0d.0 System peripheral [0880]: Toshiba America Info Systems SD TypA Controller [1179:0805] (rev 05) The code is fixed, cleaned up and successfully tested with SD, SDHC, SDXC and MMC cards on Portege R100. (MMC cards don't even work in Windows!) SDIO probably does not work (don't have any SDIO card). The hardware is slow (around 2 MB/s - same in Windows) because it does not support bus mastering (busmaster enable bit cannot be set in PCI control reg). Also the card clock is limited to 16MHz (33MHz PCI clock divided by 2). Signed-off-by: Ondrej Zary Signed-off-by: Ulf Hansson --- drivers/mmc/host/Kconfig | 5 + drivers/mmc/host/Makefile | 1 + drivers/mmc/host/toshsd.c | 717 ++++++++++++++++++++++++++++++++++++++++++++++ drivers/mmc/host/toshsd.h | 176 ++++++++++++ 4 files changed, 899 insertions(+) create mode 100644 drivers/mmc/host/toshsd.c create mode 100644 drivers/mmc/host/toshsd.h diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index 13860656104b..882bfe53fa38 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -748,3 +748,8 @@ config MMC_SUNXI help This selects support for the SD/MMC Host Controller on Allwinner sunxi SoCs. + +config MMC_TOSHIBA_PCI + tristate "Toshiba Type A SD/MMC Card Interface Driver" + depends on PCI + help diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile index b09ecfb88269..f7b0a77cf419 100644 --- a/drivers/mmc/host/Makefile +++ b/drivers/mmc/host/Makefile @@ -55,6 +55,7 @@ obj-$(CONFIG_MMC_WMT) += wmt-sdmmc.o obj-$(CONFIG_MMC_MOXART) += moxart-mmc.o obj-$(CONFIG_MMC_SUNXI) += sunxi-mmc.o obj-$(CONFIG_MMC_USDHI6ROL0) += usdhi6rol0.o +obj-$(CONFIG_MMC_TOSHIBA_PCI) += toshsd.o obj-$(CONFIG_MMC_REALTEK_PCI) += rtsx_pci_sdmmc.o obj-$(CONFIG_MMC_REALTEK_USB) += rtsx_usb_sdmmc.o diff --git a/drivers/mmc/host/toshsd.c b/drivers/mmc/host/toshsd.c new file mode 100644 index 000000000000..edb06d67c2f5 --- /dev/null +++ b/drivers/mmc/host/toshsd.c @@ -0,0 +1,717 @@ +/* + * Toshiba PCI Secure Digital Host Controller Interface driver + * + * Copyright (C) 2014 Ondrej Zary + * Copyright (C) 2007 Richard Betts, All Rights Reserved. + * + * Based on asic3_mmc.c, copyright (c) 2005 SDG Systems, LLC and, + * sdhci.c, copyright (C) 2005-2006 Pierre Ossman + * + * 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 "toshsd.h" + +#define DRIVER_NAME "toshsd" + +static const struct pci_device_id pci_ids[] = { + { PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA, 0x0805) }, + { /* end: all zeroes */ }, +}; + +MODULE_DEVICE_TABLE(pci, pci_ids); + +static void toshsd_init(struct toshsd_host *host) +{ + /* enable clock */ + pci_write_config_byte(host->pdev, SD_PCICFG_CLKSTOP, + SD_PCICFG_CLKSTOP_ENABLE_ALL); + pci_write_config_byte(host->pdev, SD_PCICFG_CARDDETECT, 2); + + /* reset */ + iowrite16(0, host->ioaddr + SD_SOFTWARERESET); /* assert */ + mdelay(2); + iowrite16(1, host->ioaddr + SD_SOFTWARERESET); /* deassert */ + mdelay(2); + + /* Clear card registers */ + iowrite16(0, host->ioaddr + SD_CARDCLOCKCTRL); + iowrite32(0, host->ioaddr + SD_CARDSTATUS); + iowrite32(0, host->ioaddr + SD_ERRORSTATUS0); + iowrite16(0, host->ioaddr + SD_STOPINTERNAL); + + /* SDIO clock? */ + iowrite16(0x100, host->ioaddr + SDIO_BASE + SDIO_CLOCKNWAITCTRL); + + /* enable LED */ + pci_write_config_byte(host->pdev, SD_PCICFG_SDLED_ENABLE1, + SD_PCICFG_LED_ENABLE1_START); + pci_write_config_byte(host->pdev, SD_PCICFG_SDLED_ENABLE2, + SD_PCICFG_LED_ENABLE2_START); + + /* set interrupt masks */ + iowrite32(~(u32)(SD_CARD_RESP_END | SD_CARD_RW_END + | SD_CARD_CARD_REMOVED_0 | SD_CARD_CARD_INSERTED_0 + | SD_BUF_READ_ENABLE | SD_BUF_WRITE_ENABLE + | SD_BUF_CMD_TIMEOUT), + host->ioaddr + SD_INTMASKCARD); + + iowrite16(0x1000, host->ioaddr + SD_TRANSACTIONCTRL); +} + +/* Set MMC clock / power. + * Note: This controller uses a simple divider scheme therefore it cannot run + * SD/MMC cards at full speed (24/20MHz). HCLK (=33MHz PCI clock?) is too high + * and the next slowest is 16MHz (div=2). + */ +static void __toshsd_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) +{ + struct toshsd_host *host = mmc_priv(mmc); + + if (ios->clock) { + u16 clk; + int div = 1; + + while (ios->clock < HCLK / div) + div *= 2; + + clk = div >> 2; + + if (div == 1) { /* disable the divider */ + pci_write_config_byte(host->pdev, SD_PCICFG_CLKMODE, + SD_PCICFG_CLKMODE_DIV_DISABLE); + clk |= SD_CARDCLK_DIV_DISABLE; + } else + pci_write_config_byte(host->pdev, SD_PCICFG_CLKMODE, 0); + + clk |= SD_CARDCLK_ENABLE_CLOCK; + iowrite16(clk, host->ioaddr + SD_CARDCLOCKCTRL); + + mdelay(10); + } else + iowrite16(0, host->ioaddr + SD_CARDCLOCKCTRL); + + switch (ios->power_mode) { + case MMC_POWER_OFF: + pci_write_config_byte(host->pdev, SD_PCICFG_POWER1, + SD_PCICFG_PWR1_OFF); + mdelay(1); + break; + case MMC_POWER_UP: + break; + case MMC_POWER_ON: + pci_write_config_byte(host->pdev, SD_PCICFG_POWER1, + SD_PCICFG_PWR1_33V); + pci_write_config_byte(host->pdev, SD_PCICFG_POWER2, + SD_PCICFG_PWR2_AUTO); + mdelay(20); + break; + } + + switch (ios->bus_width) { + case MMC_BUS_WIDTH_1: + iowrite16(SD_CARDOPT_REQUIRED | SD_CARDOPT_DATA_RESP_TIMEOUT(14) + | SD_CARDOPT_C2_MODULE_ABSENT + | SD_CARDOPT_DATA_XFR_WIDTH_1, + host->ioaddr + SD_CARDOPTIONSETUP); + break; + case MMC_BUS_WIDTH_4: + iowrite16(SD_CARDOPT_REQUIRED | SD_CARDOPT_DATA_RESP_TIMEOUT(14) + | SD_CARDOPT_C2_MODULE_ABSENT + | SD_CARDOPT_DATA_XFR_WIDTH_4, + host->ioaddr + SD_CARDOPTIONSETUP); + break; + } +} + +static void toshsd_set_led(struct toshsd_host *host, unsigned char state) +{ + iowrite16(state, host->ioaddr + SDIO_BASE + SDIO_LEDCTRL); +} + +static void toshsd_finish_request(struct toshsd_host *host) +{ + struct mmc_request *mrq = host->mrq; + + /* Write something to end the command */ + host->mrq = NULL; + host->cmd = NULL; + host->data = NULL; + + toshsd_set_led(host, 0); + mmc_request_done(host->mmc, mrq); +} + +static irqreturn_t toshsd_thread_irq(int irq, void *dev_id) +{ + struct toshsd_host *host = dev_id; + struct mmc_data *data = host->data; + struct sg_mapping_iter *sg_miter = &host->sg_miter; + unsigned short *buf; + int count; + unsigned long flags; + + if (!data) { + dev_warn(&host->pdev->dev, "Spurious Data IRQ\n"); + if (host->cmd) { + host->cmd->error = -EIO; + toshsd_finish_request(host); + } + return IRQ_NONE; + } + spin_lock_irqsave(&host->lock, flags); + + if (!sg_miter_next(sg_miter)) + return IRQ_HANDLED; + buf = sg_miter->addr; + + /* Ensure we dont read more than one block. The chip will interrupt us + * When the next block is available. + */ + count = sg_miter->length; + if (count > data->blksz) + count = data->blksz; + + dev_dbg(&host->pdev->dev, "count: %08x, flags %08x\n", count, + data->flags); + + /* Transfer the data */ + if (data->flags & MMC_DATA_READ) + ioread32_rep(host->ioaddr + SD_DATAPORT, buf, count >> 2); + else + iowrite32_rep(host->ioaddr + SD_DATAPORT, buf, count >> 2); + + sg_miter->consumed = count; + sg_miter_stop(sg_miter); + + spin_unlock_irqrestore(&host->lock, flags); + + return IRQ_HANDLED; +} + +static void toshsd_cmd_irq(struct toshsd_host *host) +{ + struct mmc_command *cmd = host->cmd; + u8 *buf = (u8 *) cmd->resp; + u16 data; + + if (!host->cmd) { + dev_warn(&host->pdev->dev, "Spurious CMD irq\n"); + return; + } + + host->cmd = NULL; + + if (cmd->flags & MMC_RSP_PRESENT && cmd->flags & MMC_RSP_136) { + /* R2 */ + buf[12] = 0xff; + data = ioread16(host->ioaddr + SD_RESPONSE0); + buf[13] = data & 0xff; + buf[14] = data >> 8; + data = ioread16(host->ioaddr + SD_RESPONSE1); + buf[15] = data & 0xff; + buf[8] = data >> 8; + data = ioread16(host->ioaddr + SD_RESPONSE2); + buf[9] = data & 0xff; + buf[10] = data >> 8; + data = ioread16(host->ioaddr + SD_RESPONSE3); + buf[11] = data & 0xff; + buf[4] = data >> 8; + data = ioread16(host->ioaddr + SD_RESPONSE4); + buf[5] = data & 0xff; + buf[6] = data >> 8; + data = ioread16(host->ioaddr + SD_RESPONSE5); + buf[7] = data & 0xff; + buf[0] = data >> 8; + data = ioread16(host->ioaddr + SD_RESPONSE6); + buf[1] = data & 0xff; + buf[2] = data >> 8; + data = ioread16(host->ioaddr + SD_RESPONSE7); + buf[3] = data & 0xff; + } else if (cmd->flags & MMC_RSP_PRESENT) { + /* R1, R1B, R3, R6, R7 */ + data = ioread16(host->ioaddr + SD_RESPONSE0); + buf[0] = data & 0xff; + buf[1] = data >> 8; + data = ioread16(host->ioaddr + SD_RESPONSE1); + buf[2] = data & 0xff; + buf[3] = data >> 8; + } + + dev_dbg(&host->pdev->dev, "Command IRQ complete %d %d %x\n", + cmd->opcode, cmd->error, cmd->flags); + + /* If there is data to handle we will + * finish the request in the mmc_data_end_irq handler.*/ + if (host->data) + return; + + toshsd_finish_request(host); +} + +static void toshsd_data_end_irq(struct toshsd_host *host) +{ + struct mmc_data *data = host->data; + + host->data = NULL; + + if (!data) { + dev_warn(&host->pdev->dev, "Spurious data end IRQ\n"); + return; + } + + if (data->error == 0) + data->bytes_xfered = data->blocks * data->blksz; + else + data->bytes_xfered = 0; + + dev_dbg(&host->pdev->dev, "Completed data request xfr=%d\n", + data->bytes_xfered); + + iowrite16(0, host->ioaddr + SD_STOPINTERNAL); + + toshsd_finish_request(host); +} + +static irqreturn_t toshsd_irq(int irq, void *dev_id) +{ + struct toshsd_host *host = dev_id; + u32 int_reg, int_mask, int_status, detail; + int error = 0, ret = IRQ_HANDLED; + + spin_lock(&host->lock); + int_status = ioread32(host->ioaddr + SD_CARDSTATUS); + int_mask = ioread32(host->ioaddr + SD_INTMASKCARD); + int_reg = int_status & ~int_mask & ~IRQ_DONT_CARE_BITS; + + dev_dbg(&host->pdev->dev, "IRQ status:%x mask:%x\n", + int_status, int_mask); + + /* nothing to do: it's not our IRQ */ + if (!int_reg) { + ret = IRQ_NONE; + goto irq_end; + } + + if (int_reg & SD_BUF_CMD_TIMEOUT) { + error = -ETIMEDOUT; + dev_dbg(&host->pdev->dev, "Timeout\n"); + } else if (int_reg & SD_BUF_CRC_ERR) { + error = -EILSEQ; + dev_err(&host->pdev->dev, "BadCRC\n"); + } else if (int_reg & (SD_BUF_ILLEGAL_ACCESS + | SD_BUF_CMD_INDEX_ERR + | SD_BUF_STOP_BIT_END_ERR + | SD_BUF_OVERFLOW + | SD_BUF_UNDERFLOW + | SD_BUF_DATA_TIMEOUT)) { + dev_err(&host->pdev->dev, "Buffer status error: { %s%s%s%s%s%s}\n", + int_reg & SD_BUF_ILLEGAL_ACCESS ? "ILLEGAL_ACC " : "", + int_reg & SD_BUF_CMD_INDEX_ERR ? "CMD_INDEX " : "", + int_reg & SD_BUF_STOP_BIT_END_ERR ? "STOPBIT_END " : "", + int_reg & SD_BUF_OVERFLOW ? "OVERFLOW " : "", + int_reg & SD_BUF_UNDERFLOW ? "UNDERFLOW " : "", + int_reg & SD_BUF_DATA_TIMEOUT ? "DATA_TIMEOUT " : ""); + + detail = ioread32(host->ioaddr + SD_ERRORSTATUS0); + dev_err(&host->pdev->dev, "detail error status { %s%s%s%s%s%s%s%s%s%s%s%s%s}\n", + detail & SD_ERR0_RESP_CMD_ERR ? "RESP_CMD " : "", + detail & SD_ERR0_RESP_NON_CMD12_END_BIT_ERR ? "RESP_END_BIT " : "", + detail & SD_ERR0_RESP_CMD12_END_BIT_ERR ? "RESP_END_BIT " : "", + detail & SD_ERR0_READ_DATA_END_BIT_ERR ? "READ_DATA_END_BIT " : "", + detail & SD_ERR0_WRITE_CRC_STATUS_END_BIT_ERR ? "WRITE_CMD_END_BIT " : "", + detail & SD_ERR0_RESP_NON_CMD12_CRC_ERR ? "RESP_CRC " : "", + detail & SD_ERR0_RESP_CMD12_CRC_ERR ? "RESP_CRC " : "", + detail & SD_ERR0_READ_DATA_CRC_ERR ? "READ_DATA_CRC " : "", + detail & SD_ERR0_WRITE_CMD_CRC_ERR ? "WRITE_CMD_CRC " : "", + detail & SD_ERR1_NO_CMD_RESP ? "NO_CMD_RESP " : "", + detail & SD_ERR1_TIMEOUT_READ_DATA ? "READ_DATA_TIMEOUT " : "", + detail & SD_ERR1_TIMEOUT_CRS_STATUS ? "CRS_STATUS_TIMEOUT " : "", + detail & SD_ERR1_TIMEOUT_CRC_BUSY ? "CRC_BUSY_TIMEOUT " : ""); + error = -EIO; + } + + if (error) { + if (host->cmd) + host->cmd->error = error; + + if (error == -ETIMEDOUT) { + iowrite32(int_status & + ~(SD_BUF_CMD_TIMEOUT | SD_CARD_RESP_END), + host->ioaddr + SD_CARDSTATUS); + } else { + toshsd_init(host); + __toshsd_set_ios(host->mmc, &host->mmc->ios); + goto irq_end; + } + } + + /* Card insert/remove. The mmc controlling code is stateless. */ + if (int_reg & (SD_CARD_CARD_INSERTED_0 | SD_CARD_CARD_REMOVED_0)) { + iowrite32(int_status & + ~(SD_CARD_CARD_REMOVED_0 | SD_CARD_CARD_INSERTED_0), + host->ioaddr + SD_CARDSTATUS); + + if (int_reg & SD_CARD_CARD_INSERTED_0) + toshsd_init(host); + + mmc_detect_change(host->mmc, 1); + } + + /* Data transfer */ + if (int_reg & (SD_BUF_READ_ENABLE | SD_BUF_WRITE_ENABLE)) { + iowrite32(int_status & + ~(SD_BUF_WRITE_ENABLE | SD_BUF_READ_ENABLE), + host->ioaddr + SD_CARDSTATUS); + + ret = IRQ_WAKE_THREAD; + goto irq_end; + } + + /* Command completion */ + if (int_reg & SD_CARD_RESP_END) { + iowrite32(int_status & ~(SD_CARD_RESP_END), + host->ioaddr + SD_CARDSTATUS); + toshsd_cmd_irq(host); + } + + /* Data transfer completion */ + if (int_reg & SD_CARD_RW_END) { + iowrite32(int_status & ~(SD_CARD_RW_END), + host->ioaddr + SD_CARDSTATUS); + toshsd_data_end_irq(host); + } +irq_end: + spin_unlock(&host->lock); + return ret; +} + +static void toshsd_start_cmd(struct toshsd_host *host, struct mmc_command *cmd) +{ + struct mmc_data *data = host->data; + int c = cmd->opcode; + + dev_dbg(&host->pdev->dev, "Command opcode: %d\n", cmd->opcode); + + if (cmd->opcode == MMC_STOP_TRANSMISSION) { + iowrite16(SD_STOPINT_ISSUE_CMD12, + host->ioaddr + SD_STOPINTERNAL); + + cmd->resp[0] = cmd->opcode; + cmd->resp[1] = 0; + cmd->resp[2] = 0; + cmd->resp[3] = 0; + + toshsd_finish_request(host); + return; + } + + switch (mmc_resp_type(cmd)) { + case MMC_RSP_NONE: + c |= SD_CMD_RESP_TYPE_NONE; + break; + + case MMC_RSP_R1: + c |= SD_CMD_RESP_TYPE_EXT_R1; + break; + case MMC_RSP_R1B: + c |= SD_CMD_RESP_TYPE_EXT_R1B; + break; + case MMC_RSP_R2: + c |= SD_CMD_RESP_TYPE_EXT_R2; + break; + case MMC_RSP_R3: + c |= SD_CMD_RESP_TYPE_EXT_R3; + break; + + default: + dev_err(&host->pdev->dev, "Unknown response type %d\n", + mmc_resp_type(cmd)); + break; + } + + host->cmd = cmd; + + if (cmd->opcode == MMC_APP_CMD) + c |= SD_CMD_TYPE_ACMD; + + if (cmd->opcode == MMC_GO_IDLE_STATE) + c |= (3 << 8); /* removed from ipaq-asic3.h for some reason */ + + if (data) { + c |= SD_CMD_DATA_PRESENT; + + if (data->blocks > 1) { + iowrite16(SD_STOPINT_AUTO_ISSUE_CMD12, + host->ioaddr + SD_STOPINTERNAL); + c |= SD_CMD_MULTI_BLOCK; + } + + if (data->flags & MMC_DATA_READ) + c |= SD_CMD_TRANSFER_READ; + + /* MMC_DATA_WRITE does not require a bit to be set */ + } + + /* Send the command */ + iowrite32(cmd->arg, host->ioaddr + SD_ARG0); + iowrite16(c, host->ioaddr + SD_CMD); +} + +static void toshsd_start_data(struct toshsd_host *host, struct mmc_data *data) +{ + unsigned int flags = SG_MITER_ATOMIC; + + dev_dbg(&host->pdev->dev, "setup data transfer: blocksize %08x nr_blocks %d, offset: %08x\n", + data->blksz, data->blocks, data->sg->offset); + + host->data = data; + + if (data->flags & MMC_DATA_READ) + flags |= SG_MITER_TO_SG; + else + flags |= SG_MITER_FROM_SG; + + sg_miter_start(&host->sg_miter, data->sg, data->sg_len, flags); + + /* Set transfer length and blocksize */ + iowrite16(data->blocks, host->ioaddr + SD_BLOCKCOUNT); + iowrite16(data->blksz, host->ioaddr + SD_CARDXFERDATALEN); +} + +/* Process requests from the MMC layer */ +static void toshsd_request(struct mmc_host *mmc, struct mmc_request *mrq) +{ + struct toshsd_host *host = mmc_priv(mmc); + unsigned long flags; + + /* abort if card not present */ + if (!(ioread16(host->ioaddr + SD_CARDSTATUS) & SD_CARD_PRESENT_0)) { + mrq->cmd->error = -ENOMEDIUM; + mmc_request_done(mmc, mrq); + return; + } + + spin_lock_irqsave(&host->lock, flags); + + WARN_ON(host->mrq != NULL); + + host->mrq = mrq; + + if (mrq->data) + toshsd_start_data(host, mrq->data); + + toshsd_set_led(host, 1); + + toshsd_start_cmd(host, mrq->cmd); + + spin_unlock_irqrestore(&host->lock, flags); +} + +static void toshsd_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) +{ + struct toshsd_host *host = mmc_priv(mmc); + unsigned long flags; + + spin_lock_irqsave(&host->lock, flags); + __toshsd_set_ios(mmc, ios); + spin_unlock_irqrestore(&host->lock, flags); +} + +static int toshsd_get_ro(struct mmc_host *mmc) +{ + struct toshsd_host *host = mmc_priv(mmc); + + /* active low */ + return !(ioread16(host->ioaddr + SD_CARDSTATUS) & SD_CARD_WRITE_PROTECT); +} + +static int toshsd_get_cd(struct mmc_host *mmc) +{ + struct toshsd_host *host = mmc_priv(mmc); + + return !!(ioread16(host->ioaddr + SD_CARDSTATUS) & SD_CARD_PRESENT_0); +} + +static struct mmc_host_ops toshsd_ops = { + .request = toshsd_request, + .set_ios = toshsd_set_ios, + .get_ro = toshsd_get_ro, + .get_cd = toshsd_get_cd, +}; + + +static void toshsd_powerdown(struct toshsd_host *host) +{ + /* mask all interrupts */ + iowrite32(0xffffffff, host->ioaddr + SD_INTMASKCARD); + /* disable card clock */ + iowrite16(0x000, host->ioaddr + SDIO_BASE + SDIO_CLOCKNWAITCTRL); + iowrite16(0, host->ioaddr + SD_CARDCLOCKCTRL); + /* power down card */ + pci_write_config_byte(host->pdev, SD_PCICFG_POWER1, SD_PCICFG_PWR1_OFF); + /* disable clock */ + pci_write_config_byte(host->pdev, SD_PCICFG_CLKSTOP, 0); +} + +#ifdef CONFIG_PM_SLEEP +static int toshsd_pm_suspend(struct device *dev) +{ + struct pci_dev *pdev = to_pci_dev(dev); + struct toshsd_host *host = pci_get_drvdata(pdev); + + toshsd_powerdown(host); + + pci_save_state(pdev); + pci_enable_wake(pdev, PCI_D3hot, 0); + pci_disable_device(pdev); + pci_set_power_state(pdev, PCI_D3hot); + + return 0; +} + +static int toshsd_pm_resume(struct device *dev) +{ + struct pci_dev *pdev = to_pci_dev(dev); + struct toshsd_host *host = pci_get_drvdata(pdev); + int ret; + + pci_set_power_state(pdev, PCI_D0); + pci_restore_state(pdev); + ret = pci_enable_device(pdev); + if (ret) + return ret; + + toshsd_init(host); + + return 0; +} +#endif /* CONFIG_PM_SLEEP */ + +static int toshsd_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + int ret; + struct toshsd_host *host; + struct mmc_host *mmc; + resource_size_t base; + + ret = pci_enable_device(pdev); + if (ret) + return ret; + + mmc = mmc_alloc_host(sizeof(struct toshsd_host), &pdev->dev); + if (!mmc) { + ret = -ENOMEM; + goto err; + } + + host = mmc_priv(mmc); + host->mmc = mmc; + + host->pdev = pdev; + pci_set_drvdata(pdev, host); + + ret = pci_request_regions(pdev, DRIVER_NAME); + if (ret) + goto free; + + host->ioaddr = pci_iomap(pdev, 0, 0); + if (!host->ioaddr) { + ret = -ENOMEM; + goto release; + } + + /* Set MMC host parameters */ + mmc->ops = &toshsd_ops; + mmc->caps = MMC_CAP_4_BIT_DATA; + mmc->ocr_avail = MMC_VDD_32_33; + + mmc->f_min = HCLK / 512; + mmc->f_max = HCLK; + + spin_lock_init(&host->lock); + + toshsd_init(host); + + ret = request_threaded_irq(pdev->irq, toshsd_irq, toshsd_thread_irq, + IRQF_SHARED, DRIVER_NAME, host); + if (ret) + goto unmap; + + mmc_add_host(mmc); + + base = pci_resource_start(pdev, 0); + dev_dbg(&pdev->dev, "MMIO %pa, IRQ %d\n", &base, pdev->irq); + + pm_suspend_ignore_children(&pdev->dev, 1); + + return 0; + +unmap: + pci_iounmap(pdev, host->ioaddr); +release: + pci_release_regions(pdev); +free: + mmc_free_host(mmc); + pci_set_drvdata(pdev, NULL); +err: + pci_disable_device(pdev); + return ret; +} + +static void toshsd_remove(struct pci_dev *pdev) +{ + struct toshsd_host *host = pci_get_drvdata(pdev); + + mmc_remove_host(host->mmc); + toshsd_powerdown(host); + free_irq(pdev->irq, host); + pci_iounmap(pdev, host->ioaddr); + pci_release_regions(pdev); + mmc_free_host(host->mmc); + pci_set_drvdata(pdev, NULL); + pci_disable_device(pdev); +} + +static const struct dev_pm_ops toshsd_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(toshsd_pm_suspend, toshsd_pm_resume) +}; + +static struct pci_driver toshsd_driver = { + .name = DRIVER_NAME, + .id_table = pci_ids, + .probe = toshsd_probe, + .remove = toshsd_remove, + .driver.pm = &toshsd_pm_ops, +}; + +static int __init toshsd_drv_init(void) +{ + return pci_register_driver(&toshsd_driver); +} + +static void __exit toshsd_drv_exit(void) +{ + pci_unregister_driver(&toshsd_driver); +} + +module_init(toshsd_drv_init); +module_exit(toshsd_drv_exit); + +MODULE_AUTHOR("Ondrej Zary, Richard Betts"); +MODULE_DESCRIPTION("Toshiba PCI Secure Digital Host Controller Interface driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/mmc/host/toshsd.h b/drivers/mmc/host/toshsd.h new file mode 100644 index 000000000000..b6c0d89e53a6 --- /dev/null +++ b/drivers/mmc/host/toshsd.h @@ -0,0 +1,176 @@ +/* + * Toshiba PCI Secure Digital Host Controller Interface driver + * + * Copyright (C) 2014 Ondrej Zary + * Copyright (C) 2007 Richard Betts, All Rights Reserved. + * + * Based on asic3_mmc.c Copyright (c) 2005 SDG Systems, LLC + * + * 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. + */ + +#define HCLK 33000000 /* 33 MHz (PCI clock) */ + +#define SD_PCICFG_CLKSTOP 0x40 /* 0x1f = clock controller, 0 = stop */ +#define SD_PCICFG_GATEDCLK 0x41 /* Gated clock */ +#define SD_PCICFG_CLKMODE 0x42 /* Control clock of SD controller */ +#define SD_PCICFG_PINSTATUS 0x44 /* R/O: read status of SD pins */ +#define SD_PCICFG_POWER1 0x48 +#define SD_PCICFG_POWER2 0x49 +#define SD_PCICFG_POWER3 0x4a +#define SD_PCICFG_CARDDETECT 0x4c +#define SD_PCICFG_SLOTS 0x50 /* R/O: define support slot number */ +#define SD_PCICFG_EXTGATECLK1 0xf0 /* Could be used for gated clock */ +#define SD_PCICFG_EXTGATECLK2 0xf1 /* Could be used for gated clock */ +#define SD_PCICFG_EXTGATECLK3 0xf9 /* Bit 1: double buffer/single buffer */ +#define SD_PCICFG_SDLED_ENABLE1 0xfa +#define SD_PCICFG_SDLED_ENABLE2 0xfe + +#define SD_PCICFG_CLKMODE_DIV_DISABLE BIT(0) +#define SD_PCICFG_CLKSTOP_ENABLE_ALL 0x1f +#define SD_PCICFG_LED_ENABLE1_START 0x12 +#define SD_PCICFG_LED_ENABLE2_START 0x80 + +#define SD_PCICFG_PWR1_33V 0x08 /* Set for 3.3 volts */ +#define SD_PCICFG_PWR1_OFF 0x00 /* Turn off power */ +#define SD_PCICFG_PWR2_AUTO 0x02 + +#define SD_CMD 0x00 /* also for SDIO */ +#define SD_ARG0 0x04 /* also for SDIO */ +#define SD_ARG1 0x06 /* also for SDIO */ +#define SD_STOPINTERNAL 0x08 +#define SD_BLOCKCOUNT 0x0a /* also for SDIO */ +#define SD_RESPONSE0 0x0c /* also for SDIO */ +#define SD_RESPONSE1 0x0e /* also for SDIO */ +#define SD_RESPONSE2 0x10 /* also for SDIO */ +#define SD_RESPONSE3 0x12 /* also for SDIO */ +#define SD_RESPONSE4 0x14 /* also for SDIO */ +#define SD_RESPONSE5 0x16 /* also for SDIO */ +#define SD_RESPONSE6 0x18 /* also for SDIO */ +#define SD_RESPONSE7 0x1a /* also for SDIO */ +#define SD_CARDSTATUS 0x1c /* also for SDIO */ +#define SD_BUFFERCTRL 0x1e /* also for SDIO */ +#define SD_INTMASKCARD 0x20 /* also for SDIO */ +#define SD_INTMASKBUFFER 0x22 /* also for SDIO */ +#define SD_CARDCLOCKCTRL 0x24 +#define SD_CARDXFERDATALEN 0x26 /* also for SDIO */ +#define SD_CARDOPTIONSETUP 0x28 /* also for SDIO */ +#define SD_ERRORSTATUS0 0x2c /* also for SDIO */ +#define SD_ERRORSTATUS1 0x2e /* also for SDIO */ +#define SD_DATAPORT 0x30 /* also for SDIO */ +#define SD_TRANSACTIONCTRL 0x34 /* also for SDIO */ +#define SD_SOFTWARERESET 0xe0 /* also for SDIO */ + +/* registers above marked "also for SDIO" and all SDIO registers below can be + * accessed at SDIO_BASE + reg address */ +#define SDIO_BASE 0x100 + +#define SDIO_CARDPORTSEL 0x02 +#define SDIO_CARDINTCTRL 0x36 +#define SDIO_CLOCKNWAITCTRL 0x38 +#define SDIO_HOSTINFORMATION 0x3a +#define SDIO_ERRORCTRL 0x3c +#define SDIO_LEDCTRL 0x3e + +#define SD_TRANSCTL_SET BIT(8) + +#define SD_CARDCLK_DIV_DISABLE BIT(15) +#define SD_CARDCLK_ENABLE_CLOCK BIT(8) +#define SD_CARDCLK_CLK_DIV_512 BIT(7) +#define SD_CARDCLK_CLK_DIV_256 BIT(6) +#define SD_CARDCLK_CLK_DIV_128 BIT(5) +#define SD_CARDCLK_CLK_DIV_64 BIT(4) +#define SD_CARDCLK_CLK_DIV_32 BIT(3) +#define SD_CARDCLK_CLK_DIV_16 BIT(2) +#define SD_CARDCLK_CLK_DIV_8 BIT(1) +#define SD_CARDCLK_CLK_DIV_4 BIT(0) +#define SD_CARDCLK_CLK_DIV_2 0 + +#define SD_CARDOPT_REQUIRED 0x000e +#define SD_CARDOPT_DATA_RESP_TIMEOUT(x) (((x) & 0x0f) << 4) /* 4 bits */ +#define SD_CARDOPT_C2_MODULE_ABSENT BIT(14) +#define SD_CARDOPT_DATA_XFR_WIDTH_1 (1 << 15) +#define SD_CARDOPT_DATA_XFR_WIDTH_4 (0 << 15) + +#define SD_CMD_TYPE_CMD (0 << 6) +#define SD_CMD_TYPE_ACMD (1 << 6) +#define SD_CMD_TYPE_AUTHEN (2 << 6) +#define SD_CMD_RESP_TYPE_NONE (3 << 8) +#define SD_CMD_RESP_TYPE_EXT_R1 (4 << 8) +#define SD_CMD_RESP_TYPE_EXT_R1B (5 << 8) +#define SD_CMD_RESP_TYPE_EXT_R2 (6 << 8) +#define SD_CMD_RESP_TYPE_EXT_R3 (7 << 8) +#define SD_CMD_RESP_TYPE_EXT_R6 (4 << 8) +#define SD_CMD_RESP_TYPE_EXT_R7 (4 << 8) +#define SD_CMD_DATA_PRESENT BIT(11) +#define SD_CMD_TRANSFER_READ BIT(12) +#define SD_CMD_MULTI_BLOCK BIT(13) +#define SD_CMD_SECURITY_CMD BIT(14) + +#define SD_STOPINT_ISSUE_CMD12 BIT(0) +#define SD_STOPINT_AUTO_ISSUE_CMD12 BIT(8) + +#define SD_CARD_RESP_END BIT(0) +#define SD_CARD_RW_END BIT(2) +#define SD_CARD_CARD_REMOVED_0 BIT(3) +#define SD_CARD_CARD_INSERTED_0 BIT(4) +#define SD_CARD_PRESENT_0 BIT(5) +#define SD_CARD_UNK6 BIT(6) +#define SD_CARD_WRITE_PROTECT BIT(7) +#define SD_CARD_CARD_REMOVED_3 BIT(8) +#define SD_CARD_CARD_INSERTED_3 BIT(9) +#define SD_CARD_PRESENT_3 BIT(10) + +#define SD_BUF_CMD_INDEX_ERR BIT(16) +#define SD_BUF_CRC_ERR BIT(17) +#define SD_BUF_STOP_BIT_END_ERR BIT(18) +#define SD_BUF_DATA_TIMEOUT BIT(19) +#define SD_BUF_OVERFLOW BIT(20) +#define SD_BUF_UNDERFLOW BIT(21) +#define SD_BUF_CMD_TIMEOUT BIT(22) +#define SD_BUF_UNK7 BIT(23) +#define SD_BUF_READ_ENABLE BIT(24) +#define SD_BUF_WRITE_ENABLE BIT(25) +#define SD_BUF_ILLEGAL_FUNCTION BIT(29) +#define SD_BUF_CMD_BUSY BIT(30) +#define SD_BUF_ILLEGAL_ACCESS BIT(31) + +#define SD_ERR0_RESP_CMD_ERR BIT(0) +#define SD_ERR0_RESP_NON_CMD12_END_BIT_ERR BIT(2) +#define SD_ERR0_RESP_CMD12_END_BIT_ERR BIT(3) +#define SD_ERR0_READ_DATA_END_BIT_ERR BIT(4) +#define SD_ERR0_WRITE_CRC_STATUS_END_BIT_ERR BIT(5) +#define SD_ERR0_RESP_NON_CMD12_CRC_ERR BIT(8) +#define SD_ERR0_RESP_CMD12_CRC_ERR BIT(9) +#define SD_ERR0_READ_DATA_CRC_ERR BIT(10) +#define SD_ERR0_WRITE_CMD_CRC_ERR BIT(11) + +#define SD_ERR1_NO_CMD_RESP BIT(16) +#define SD_ERR1_TIMEOUT_READ_DATA BIT(20) +#define SD_ERR1_TIMEOUT_CRS_STATUS BIT(21) +#define SD_ERR1_TIMEOUT_CRC_BUSY BIT(22) + +#define IRQ_DONT_CARE_BITS (SD_CARD_PRESENT_3 \ + | SD_CARD_WRITE_PROTECT \ + | SD_CARD_UNK6 \ + | SD_CARD_PRESENT_0 \ + | SD_BUF_UNK7 \ + | SD_BUF_CMD_BUSY) + +struct toshsd_host { + struct pci_dev *pdev; + struct mmc_host *mmc; + + spinlock_t lock; + + struct mmc_request *mrq;/* Current request */ + struct mmc_command *cmd;/* Current command */ + struct mmc_data *data; /* Current data request */ + + struct sg_mapping_iter sg_miter; /* for PIO */ + + void __iomem *ioaddr; /* mapped address */ +}; -- cgit v1.2.3-59-g8ed1b From 59b6c9e0ad9f2578ff8b2ef8c718bcb8b895fefb Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Wed, 12 Nov 2014 14:55:19 +1100 Subject: mmc: core: use card->ocr when negotiating voltage setting in mmc_sdio_power_restore As we are restoring power to a known card, it makes sense to use the 'ocr' value known for the card rather than the generic one for the host interface. This matches the use of card->ocr passed to mmc_power_up in mmc_sdio_runtime_resume (just before mmc_sdio_power_restore is called), and the value passed to mmc_sdio_init_card() a little later in mmc_sdio_power_restore(). Suggested-by: Ulf Hansson Signed-off-by: NeilBrown Signed-off-by: Ulf Hansson --- drivers/mmc/core/sdio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index 2439e717655b..f0ddb0d28536 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -1035,7 +1035,7 @@ static int mmc_sdio_power_restore(struct mmc_host *host) sdio_reset(host); mmc_go_idle(host); - mmc_send_if_cond(host, host->ocr_avail); + mmc_send_if_cond(host, host->card->ocr); ret = mmc_send_io_op_cond(host, 0, NULL); if (ret) -- cgit v1.2.3-59-g8ed1b From 006fc51cb3ab42960fa4f246c772ad12e45a3a9b Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Wed, 12 Nov 2014 14:55:19 +1100 Subject: mmc: core: reset sdio card properly on resume. mmc_sdio_power_restore() calls mmc_send_if_cond(host, host->card->ocr); ret = mmc_send_io_op_cond(host, 0, NULL); between mmc_go_idle() and mmc_sdio_init_card(). mmc_sdio_resume() needs to as well, else my libertas sdio wifi device doesn't resume properly from suspend. Signed-off-by: NeilBrown Signed-off-by: Ulf Hansson --- drivers/mmc/core/sdio.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index f0ddb0d28536..fd0750b5a634 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -980,8 +980,12 @@ static int mmc_sdio_resume(struct mmc_host *host) if (mmc_card_is_removable(host) || !mmc_card_keep_power(host)) { sdio_reset(host); mmc_go_idle(host); - err = mmc_sdio_init_card(host, host->card->ocr, host->card, - mmc_card_keep_power(host)); + mmc_send_if_cond(host, host->card->ocr); + err = mmc_send_io_op_cond(host, 0, NULL); + if (!err) + err = mmc_sdio_init_card(host, host->card->ocr, + host->card, + mmc_card_keep_power(host)); } else if (mmc_card_keep_power(host) && mmc_card_wake_sdio_irq(host)) { /* We may have switched to 1-bit mode during suspend */ err = sdio_enable_4bit_bus(host->card); -- cgit v1.2.3-59-g8ed1b From c34346b200757834fffdf231b6034258b01ba550 Mon Sep 17 00:00:00 2001 From: Alim Akhtar Date: Fri, 29 Aug 2014 15:54:51 +0530 Subject: mmc: dw_mmc: add support for ARM64 There are upcoming ARM64 SoCs with dw_mmc host controller. Signed-off-by: Alim Akhtar Signed-off-by: Ulf Hansson --- drivers/mmc/host/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index 882bfe53fa38..2d6fbdd11803 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -580,7 +580,7 @@ config SDH_BFIN_MISSING_CMD_PULLUP_WORKAROUND config MMC_DW tristate "Synopsys DesignWare Memory Card Interface" depends on HAS_DMA - depends on ARC || ARM || MIPS || COMPILE_TEST + depends on ARC || ARM || ARM64 || MIPS || COMPILE_TEST help This selects support for the Synopsys DesignWare Mobile Storage IP block, this provides host support for SD and MMC interfaces, in both -- cgit v1.2.3-59-g8ed1b From a26eba614afff0e39594101bcb73014a9a22fb33 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Thu, 6 Nov 2014 03:35:09 +0000 Subject: mmc: block: Increase max_devices Currently the driver imposes a limit of 256 total minor numbers, apparently based on the historic Unix/Linux limit. This is quite restrictive, particularly if we raise the maximum number of partitions per card to 256 to match sd. In order to make the full minor number space available we would have to replace the static dev_use and name_use arrays with struct ida. But we can at least allow use of 256 cards rather than just 256 minors, with only a small change. Signed-off-by: Ben Hutchings Signed-off-by: Ulf Hansson --- drivers/mmc/card/block.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index 0c41ee043e36..4409d79ed650 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -78,13 +78,16 @@ static int perdev_minors = CONFIG_MMC_BLOCK_MINORS; /* * We've only got one major, so number of mmcblk devices is - * limited to 256 / number of minors per device. + * limited to (1 << 20) / number of minors per device. It is also + * currently limited by the size of the static bitmaps below. */ static int max_devices; -/* 256 minors, so at most 256 separate devices */ -static DECLARE_BITMAP(dev_use, 256); -static DECLARE_BITMAP(name_use, 256); +#define MAX_DEVICES 256 + +/* TODO: Replace these with struct ida */ +static DECLARE_BITMAP(dev_use, MAX_DEVICES); +static DECLARE_BITMAP(name_use, MAX_DEVICES); /* * There is one mmc_blk_data per slot. @@ -2555,7 +2558,7 @@ static int __init mmc_blk_init(void) if (perdev_minors != CONFIG_MMC_BLOCK_MINORS) pr_info("mmcblk: using %d minors per device\n", perdev_minors); - max_devices = 256 / perdev_minors; + max_devices = min(MAX_DEVICES, (1 << MINORBITS) / perdev_minors); res = register_blkdev(MMC_BLOCK_MAJOR, "mmc"); if (res) -- cgit v1.2.3-59-g8ed1b From 3c583f70a8e2feda03db77d2c8e9a41d302ac657 Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Wed, 12 Nov 2014 23:10:08 +0100 Subject: mmc: mvsdio: Work around broken TX DMA In order to use the mvsdio driver for sdio, it has been necessary to use a module parameter to disable DMA so to force PIO is used. It is then possible to use wireless LAN devices like mwifiex found on topkick and mirabox. However, accessing an MMC SD card does work with DMA. Investigation has shown that MMC block device accesses are always aligned to 64 byte boundaries, where as transfers from mwifiex are rarely more than word aligned. It has also been determined that card to host transfers work with DMA for SDIO devices, but host to card transfers with DMA have problems. This patch extends the current checks for buffers which are not word aligned or multiple of words. All host to card transfers which are not 64 byte aligned are now also performed via PIO. This should not affect the performance of SD cards, but allow sdio devices to work out of the box, and they are likely to be more efficient since DMA will be used for card to host transfers. Tested on mirabox for wifi via mwifiex Tested on 370 RD for file systems on an SD card. Signed-off-by: Andrew Lunn Signed-off-by: Ulf Hansson --- drivers/mmc/host/mvsdio.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/host/mvsdio.c b/drivers/mmc/host/mvsdio.c index 6b4c5ad3b393..4f8618f4522d 100644 --- a/drivers/mmc/host/mvsdio.c +++ b/drivers/mmc/host/mvsdio.c @@ -111,10 +111,15 @@ static int mvsd_setup_data(struct mvsd_host *host, struct mmc_data *data) mvsd_write(MVSD_BLK_COUNT, data->blocks); mvsd_write(MVSD_BLK_SIZE, data->blksz); - if (nodma || (data->blksz | data->sg->offset) & 3) { + if (nodma || (data->blksz | data->sg->offset) & 3 || + ((!(data->flags & MMC_DATA_READ) && data->sg->offset & 0x3f))) { /* * We cannot do DMA on a buffer which offset or size * is not aligned on a 4-byte boundary. + * + * It also appears the host to card DMA can corrupt + * data when the buffer is not aligned on a 64 byte + * boundary. */ host->pio_size = data->blocks * data->blksz; host->pio_ptr = sg_virt(data->sg); -- cgit v1.2.3-59-g8ed1b From 767562348b72cb2612f5991ad35a5c0448254939 Mon Sep 17 00:00:00 2001 From: Addy Ke Date: Tue, 4 Nov 2014 22:03:09 +0800 Subject: mmc: dw_mmc: add support for the other bit of sdio interrupt The bit of sdio interrupt is 16 in designware implementation, but it is 24 on Rockchip SoCs.This patch add sdio_id0 for the number of slot0 in the SDIO interrupt registers. Signed-off-by: Addy Ke Reviewed-by: Doug Anderson Acked-by: Jaehoon Chung Signed-off-by: Ulf Hansson --- drivers/mmc/host/dw_mmc-rockchip.c | 10 ++++++++++ drivers/mmc/host/dw_mmc.c | 12 +++++++----- drivers/mmc/host/dw_mmc.h | 2 ++ include/linux/mmc/dw_mmc.h | 3 +++ 4 files changed, 22 insertions(+), 5 deletions(-) diff --git a/drivers/mmc/host/dw_mmc-rockchip.c b/drivers/mmc/host/dw_mmc-rockchip.c index bbb4ec386e56..5650ac488cf3 100644 --- a/drivers/mmc/host/dw_mmc-rockchip.c +++ b/drivers/mmc/host/dw_mmc-rockchip.c @@ -68,14 +68,24 @@ static void dw_mci_rk3288_set_ios(struct dw_mci *host, struct mmc_ios *ios) } } +static int dw_mci_rockchip_init(struct dw_mci *host) +{ + /* It is slot 8 on Rockchip SoCs */ + host->sdio_id0 = 8; + + return 0; +} + static const struct dw_mci_drv_data rk2928_drv_data = { .prepare_command = dw_mci_rockchip_prepare_command, + .init = dw_mci_rockchip_init, }; static const struct dw_mci_drv_data rk3288_drv_data = { .prepare_command = dw_mci_rockchip_prepare_command, .set_ios = dw_mci_rk3288_set_ios, .setup_clock = dw_mci_rk3288_setup_clock, + .init = dw_mci_rockchip_init, }; static const struct of_device_id dw_mci_rockchip_match[] = { diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 5a37c33879a1..b4c30448566e 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -919,7 +919,7 @@ static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool force_clkinit) /* enable clock; only low power if no SDIO */ clk_en_a = SDMMC_CLKEN_ENABLE << slot->id; - if (!(mci_readl(host, INTMASK) & SDMMC_INT_SDIO(slot->id))) + if (!(mci_readl(host, INTMASK) & SDMMC_INT_SDIO(slot->sdio_id))) clk_en_a |= SDMMC_CLKEN_LOW_PWR << slot->id; mci_writel(host, CLKENA, clk_en_a); @@ -1280,10 +1280,10 @@ static void dw_mci_enable_sdio_irq(struct mmc_host *mmc, int enb) dw_mci_disable_low_power(slot); mci_writel(host, INTMASK, - (int_mask | SDMMC_INT_SDIO(slot->id))); + (int_mask | SDMMC_INT_SDIO(slot->sdio_id))); } else { mci_writel(host, INTMASK, - (int_mask & ~SDMMC_INT_SDIO(slot->id))); + (int_mask & ~SDMMC_INT_SDIO(slot->sdio_id))); } } @@ -2152,8 +2152,9 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id) /* Handle SDIO Interrupts */ for (i = 0; i < host->num_slots; i++) { struct dw_mci_slot *slot = host->slot[i]; - if (pending & SDMMC_INT_SDIO(i)) { - mci_writel(host, RINTSTS, SDMMC_INT_SDIO(i)); + if (pending & SDMMC_INT_SDIO(slot->sdio_id)) { + mci_writel(host, RINTSTS, + SDMMC_INT_SDIO(slot->sdio_id)); mmc_signal_sdio_irq(slot->mmc); } } @@ -2252,6 +2253,7 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id) slot = mmc_priv(mmc); slot->id = id; + slot->sdio_id = host->sdio_id0 + id; slot->mmc = mmc; slot->host = host; host->slot[id] = slot; diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h index 58d8a54d644b..0d0f7a271d63 100644 --- a/drivers/mmc/host/dw_mmc.h +++ b/drivers/mmc/host/dw_mmc.h @@ -225,6 +225,7 @@ extern int dw_mci_resume(struct dw_mci *host); * with CONFIG_MMC_CLKGATE. * @flags: Random state bits associated with the slot. * @id: Number of this slot. + * @sdio_id: Number of this slot in the SDIO interrupt registers. */ struct dw_mci_slot { struct mmc_host *mmc; @@ -244,6 +245,7 @@ struct dw_mci_slot { #define DW_MMC_CARD_PRESENT 0 #define DW_MMC_CARD_NEED_INIT 1 int id; + int sdio_id; }; struct dw_mci_tuning_data { diff --git a/include/linux/mmc/dw_mmc.h b/include/linux/mmc/dw_mmc.h index 0a551152d600..42b724e8d503 100644 --- a/include/linux/mmc/dw_mmc.h +++ b/include/linux/mmc/dw_mmc.h @@ -97,6 +97,7 @@ struct mmc_data; * @quirks: Set of quirks that apply to specific versions of the IP. * @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. * * Locking * ======= @@ -193,6 +194,8 @@ struct dw_mci { bool vqmmc_enabled; unsigned long irq_flags; /* IRQ flags */ int irq; + + int sdio_id0; }; /* DMA ops for Internal/External DMAC interface */ -- cgit v1.2.3-59-g8ed1b From ecb89f2f5f3e771108a5595b0b4d1a1a974cc926 Mon Sep 17 00:00:00 2001 From: "ludovic.desroches@atmel.com" Date: Fri, 14 Nov 2014 15:36:24 +0100 Subject: mmc: atmel-mci: remove compat for non DT board when requesting dma chan All boards with a dma controller have DT support so using dma_request_slave_channel_compat is no more needed. Signed-off-by: Ludovic Desroches Acked-by: Nicolas Ferre Signed-off-by: Ulf Hansson --- drivers/mmc/host/atmel-mci.c | 20 +------------------- 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c index a7b59ba399a1..de2287c5bf3a 100644 --- a/drivers/mmc/host/atmel-mci.c +++ b/drivers/mmc/host/atmel-mci.c @@ -2272,23 +2272,6 @@ static void atmci_cleanup_slot(struct atmel_mci_slot *slot, mmc_free_host(slot->mmc); } -static bool atmci_filter(struct dma_chan *chan, void *pdata) -{ - struct mci_platform_data *sl_pdata = pdata; - struct mci_dma_data *sl; - - if (!sl_pdata) - return false; - - sl = sl_pdata->dma_slave; - if (sl && find_slave_dev(sl) == chan->device->dev) { - chan->private = slave_data_ptr(sl); - return true; - } else { - return false; - } -} - static bool atmci_configure_dma(struct atmel_mci *host) { struct mci_platform_data *pdata; @@ -2302,8 +2285,7 @@ static bool atmci_configure_dma(struct atmel_mci *host) dma_cap_zero(mask); dma_cap_set(DMA_SLAVE, mask); - host->dma.chan = dma_request_slave_channel_compat(mask, atmci_filter, pdata, - &host->pdev->dev, "rxtx"); + host->dma.chan = dma_request_slave_channel(&host->pdev->dev, "rxtx"); if (!host->dma.chan) { dev_warn(&host->pdev->dev, "no DMA channel available\n"); return false; -- cgit v1.2.3-59-g8ed1b From 9e2a0c96efab30c85367176d1fc2c04906676458 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sat, 15 Nov 2014 21:56:41 +0300 Subject: mmc: toshsd: move dereference below check for NULL We check for NULL pointers after dereferencing so it's too late. Oddly enough, Smatch misses this code but complains about the caller passing NULL pointers to this function: drivers/mmc/host/toshsd.c:389 toshsd_irq() error: we previously assumed 'host->cmd' could be null (see line 349) Signed-off-by: Dan Carpenter Signed-off-by: Ulf Hansson --- drivers/mmc/host/toshsd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/toshsd.c b/drivers/mmc/host/toshsd.c index edb06d67c2f5..4666262edaca 100644 --- a/drivers/mmc/host/toshsd.c +++ b/drivers/mmc/host/toshsd.c @@ -206,14 +206,14 @@ static irqreturn_t toshsd_thread_irq(int irq, void *dev_id) static void toshsd_cmd_irq(struct toshsd_host *host) { struct mmc_command *cmd = host->cmd; - u8 *buf = (u8 *) cmd->resp; + u8 *buf; u16 data; if (!host->cmd) { dev_warn(&host->pdev->dev, "Spurious CMD irq\n"); return; } - + buf = (u8 *)cmd->resp; host->cmd = NULL; if (cmd->flags & MMC_RSP_PRESENT && cmd->flags & MMC_RSP_136) { -- cgit v1.2.3-59-g8ed1b From 66dfd10173159cafa9cb0d39936b8daeaab8e3e0 Mon Sep 17 00:00:00 2001 From: James Hogan Date: Mon, 17 Nov 2014 17:49:05 +0000 Subject: mmc: dw_mmc: avoid write to CDTHRCTL on older versions Commit f1d2736c8156 (mmc: dw_mmc: control card read threshold) added dw_mci_ctrl_rd_thld() with an unconditional write to the CDTHRCTL register at offset 0x100. However before version 240a, the FIFO region started at 0x100, so the write messes with the FIFO and completely breaks the driver. If the version id < 240A, return early from dw_mci_ctl_rd_thld() so as not to hit this problem. Fixes: f1d2736c8156 (mmc: dw_mmc: control card read threshold) Signed-off-by: James Hogan Cc: # v3.13+ Acked-by: Jaehoon Chung Signed-off-by: Ulf Hansson --- drivers/mmc/host/dw_mmc.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index b4c30448566e..67c04518ec4c 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -726,6 +726,13 @@ static void dw_mci_ctrl_rd_thld(struct dw_mci *host, struct mmc_data *data) WARN_ON(!(data->flags & MMC_DATA_READ)); + /* + * CDTHRCTL doesn't exist prior to 240A (in fact that register offset is + * in the FIFO region, so we really shouldn't access it). + */ + if (host->verid < DW_MMC_240A) + return; + if (host->timing != MMC_TIMING_MMC_HS200 && host->timing != MMC_TIMING_UHS_SDR104) goto disable; -- cgit v1.2.3-59-g8ed1b From cc87a358c5759b23866d656417db2d6d7e0a4657 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Tue, 18 Nov 2014 00:37:12 -0200 Subject: mmc: mxs-mmc: Register the irq with the device name Instead of registering the irq name with the driver's name, it's better to pass the device name so that we have a more explicit indication as to what mmc instance the irq is related: $ cat /proc/interrupts CPU0 ... 26: 6 - 96 80010000.ssp Signed-off-by: Fabio Estevam Signed-off-by: Ulf Hansson --- drivers/mmc/host/mxs-mmc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mmc/host/mxs-mmc.c b/drivers/mmc/host/mxs-mmc.c index cd74e5143c36..339059a9a648 100644 --- a/drivers/mmc/host/mxs-mmc.c +++ b/drivers/mmc/host/mxs-mmc.c @@ -660,7 +660,7 @@ static int mxs_mmc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, mmc); ret = devm_request_irq(&pdev->dev, irq_err, mxs_mmc_irq_handler, 0, - DRIVER_NAME, host); + dev_name(&pdev->dev), host); if (ret) goto out_free_dma; -- cgit v1.2.3-59-g8ed1b From d13552908b2f3bdf917d0f4a308f69608c92c7e7 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Tue, 18 Nov 2014 00:43:39 -0200 Subject: mmc: mxs-mmc: Simplify PM hooks By using SIMPLE_DEV_PM_OPS we can make the code smaller and cleaner. Signed-off-by: Fabio Estevam Signed-off-by: Ulf Hansson --- drivers/mmc/host/mxs-mmc.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/drivers/mmc/host/mxs-mmc.c b/drivers/mmc/host/mxs-mmc.c index 339059a9a648..c049ac75a36a 100644 --- a/drivers/mmc/host/mxs-mmc.c +++ b/drivers/mmc/host/mxs-mmc.c @@ -702,7 +702,7 @@ static int mxs_mmc_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP static int mxs_mmc_suspend(struct device *dev) { struct mmc_host *mmc = dev_get_drvdata(dev); @@ -722,22 +722,17 @@ static int mxs_mmc_resume(struct device *dev) clk_prepare_enable(ssp->clk); return 0; } - -static const struct dev_pm_ops mxs_mmc_pm_ops = { - .suspend = mxs_mmc_suspend, - .resume = mxs_mmc_resume, -}; #endif +static SIMPLE_DEV_PM_OPS(mxs_mmc_pm_ops, mxs_mmc_suspend, mxs_mmc_resume); + static struct platform_driver mxs_mmc_driver = { .probe = mxs_mmc_probe, .remove = mxs_mmc_remove, .id_table = mxs_ssp_ids, .driver = { .name = DRIVER_NAME, -#ifdef CONFIG_PM .pm = &mxs_mmc_pm_ops, -#endif .of_match_table = mxs_mmc_dt_ids, }, }; -- cgit v1.2.3-59-g8ed1b From 4d7c07cd6c0379228e65c52776f22250e8f4a962 Mon Sep 17 00:00:00 2001 From: Andrew Bresticker Date: Thu, 13 Nov 2014 10:50:21 -0800 Subject: mmc: dw_mmc: Add support for IMG Pistachio Add support for the DW MMC host found on the Imagination Pistachio SoC. Like the DW MMC hosts found on SOCFPGA and Rockchip SoCs, the DW MMC host on Pistachio requires the use of SDMMC_CMD_USE_HOLD_REG. Signed-off-by: Andrew Bresticker Reviewed-by: Doug Anderson Acked-by: Jaehoon Chung Signed-off-by: Ulf Hansson --- .../devicetree/bindings/mmc/img-dw-mshc.txt | 29 ++++++++++++++++++++++ drivers/mmc/host/dw_mmc-pltfm.c | 6 +++++ 2 files changed, 35 insertions(+) create mode 100644 Documentation/devicetree/bindings/mmc/img-dw-mshc.txt diff --git a/Documentation/devicetree/bindings/mmc/img-dw-mshc.txt b/Documentation/devicetree/bindings/mmc/img-dw-mshc.txt new file mode 100644 index 000000000000..85de99fcaa2f --- /dev/null +++ b/Documentation/devicetree/bindings/mmc/img-dw-mshc.txt @@ -0,0 +1,29 @@ +* Imagination 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 Imagination specific +extensions to the Synopsys Designware Mobile Storage Host Controller. + +Required Properties: + +* compatible: should be + - "img,pistachio-dw-mshc": for Pistachio SoCs + +Example: + + mmc@18142000 { + compatible = "img,pistachio-dw-mshc"; + reg = <0x18142000 0x400>; + interrupts = ; + + clocks = <&system_clk>, <&sdhost_clk>; + clock-names = "biu", "ciu"; + + fifo-depth = <0x20>; + bus-width = <4>; + num-slots = <1>; + disable-wp; + }; diff --git a/drivers/mmc/host/dw_mmc-pltfm.c b/drivers/mmc/host/dw_mmc-pltfm.c index 8b6572162ed9..ec6dbcdec693 100644 --- a/drivers/mmc/host/dw_mmc-pltfm.c +++ b/drivers/mmc/host/dw_mmc-pltfm.c @@ -35,6 +35,10 @@ static const struct dw_mci_drv_data socfpga_drv_data = { .prepare_command = dw_mci_pltfm_prepare_command, }; +static const struct dw_mci_drv_data pistachio_drv_data = { + .prepare_command = dw_mci_pltfm_prepare_command, +}; + int dw_mci_pltfm_register(struct platform_device *pdev, const struct dw_mci_drv_data *drv_data) { @@ -90,6 +94,8 @@ static const struct of_device_id dw_mci_pltfm_match[] = { { .compatible = "snps,dw-mshc", }, { .compatible = "altr,socfpga-dw-mshc", .data = &socfpga_drv_data }, + { .compatible = "img,pistachio-dw-mshc", + .data = &pistachio_drv_data }, {}, }; MODULE_DEVICE_TABLE(of, dw_mci_pltfm_match); -- cgit v1.2.3-59-g8ed1b From c3cd5c076c3ab6a088d73e260b516bcda1dc9da4 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Wed, 19 Nov 2014 11:16:57 -0200 Subject: mmc: mxs-mmc: No need to do NULL check on 'iores' devm_ioremap_resource() already checks if 'iores' is NULL or not, so we can skip this manual check. While at it, move platform_get_resource() closer to devm_ioremap_resource() for better readability. Signed-off-by: Fabio Estevam Signed-off-by: Ulf Hansson --- drivers/mmc/host/mxs-mmc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/mxs-mmc.c b/drivers/mmc/host/mxs-mmc.c index c049ac75a36a..0d307303ebb9 100644 --- a/drivers/mmc/host/mxs-mmc.c +++ b/drivers/mmc/host/mxs-mmc.c @@ -581,9 +581,8 @@ static int mxs_mmc_probe(struct platform_device *pdev) struct regulator *reg_vmmc; struct mxs_ssp *ssp; - iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); irq_err = platform_get_irq(pdev, 0); - if (!iores || irq_err < 0) + if (irq_err < 0) return -EINVAL; mmc = mmc_alloc_host(sizeof(struct mxs_mmc_host), &pdev->dev); @@ -593,6 +592,7 @@ static int mxs_mmc_probe(struct platform_device *pdev) host = mmc_priv(mmc); ssp = &host->ssp; ssp->dev = &pdev->dev; + iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); ssp->base = devm_ioremap_resource(&pdev->dev, iores); if (IS_ERR(ssp->base)) { ret = PTR_ERR(ssp->base); -- cgit v1.2.3-59-g8ed1b From 5654d90064bda87a9738fd6fcfcfca5537754259 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Wed, 19 Nov 2014 11:16:58 -0200 Subject: mmc: mxs-mmc: Propagate the real error If platform_get_irq() fails, it is better to propagate the real error value instead of a 'fake' one. Signed-off-by: Fabio Estevam Signed-off-by: Ulf Hansson --- drivers/mmc/host/mxs-mmc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mmc/host/mxs-mmc.c b/drivers/mmc/host/mxs-mmc.c index 0d307303ebb9..f2c49e0e213d 100644 --- a/drivers/mmc/host/mxs-mmc.c +++ b/drivers/mmc/host/mxs-mmc.c @@ -583,7 +583,7 @@ static int mxs_mmc_probe(struct platform_device *pdev) irq_err = platform_get_irq(pdev, 0); if (irq_err < 0) - return -EINVAL; + return irq_err; mmc = mmc_alloc_host(sizeof(struct mxs_mmc_host), &pdev->dev); if (!mmc) -- cgit v1.2.3-59-g8ed1b From e34d467c515f5f64e12c28fb2b15035c9b38f332 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Wed, 19 Nov 2014 11:16:59 -0200 Subject: mmc: mxs-mmc: Check for clk_prepare_enable() error clk_prepare_enable() may fail and in this case we should propagate the error. Signed-off-by: Fabio Estevam Signed-off-by: Ulf Hansson --- drivers/mmc/host/mxs-mmc.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/mmc/host/mxs-mmc.c b/drivers/mmc/host/mxs-mmc.c index f2c49e0e213d..60c4ca97a727 100644 --- a/drivers/mmc/host/mxs-mmc.c +++ b/drivers/mmc/host/mxs-mmc.c @@ -619,7 +619,9 @@ static int mxs_mmc_probe(struct platform_device *pdev) ret = PTR_ERR(ssp->clk); goto out_mmc_free; } - clk_prepare_enable(ssp->clk); + ret = clk_prepare_enable(ssp->clk); + if (ret) + goto out_mmc_free; ret = mxs_mmc_reset(host); if (ret) { @@ -719,8 +721,7 @@ static int mxs_mmc_resume(struct device *dev) struct mxs_mmc_host *host = mmc_priv(mmc); struct mxs_ssp *ssp = &host->ssp; - clk_prepare_enable(ssp->clk); - return 0; + return clk_prepare_enable(ssp->clk); } #endif -- cgit v1.2.3-59-g8ed1b From c6eb588028f8f23dae8e26312cf192f365c85b95 Mon Sep 17 00:00:00 2001 From: Vincent Yang Date: Fri, 21 Nov 2014 08:51:40 +0800 Subject: mmc: core: hold SD Clock before CMD11 during Signal Voltage Switch Procedure This patch is to fix an issue found on mb86s7x platforms. [symptom] There are some UHS-1 SD memory cards sometimes cannot be detected correctly, e.g., Transcend 600x SDXC 64GB UHS-1 memory card. During Signal Voltage Switch Procedure, failure to switch is indicated by the card holding DAT[3:0] low. [analysis] According to SD Host Controller Simplified Specification Version 3.00 chapter 3.6.1, the Signal Voltage Switch Procedure should be: (1) Check S18A; (2) Issue CMD11; (3) Check CMD 11 response; (4) Stop providing SD clock; (5) Check DAT[3:0] should be 0000b; (6) Set 1.8V Signal Enable; (7) Wait 5ms; (8) Check 1.8V Signal Enable; (9) Provide SD Clock; (10) Wait 1ms; (11) Check DAT[3:0] should be 1111b; (12) error handling With CONFIG_MMC_CLKGATE=y, sometimes there is one more gating/un-gating SD clock between (2) and (3). In this case, some UHS-1 SD cards will hold DAT[3:0] 0000b at (11) and thus fails Signal Voltage Switch Procedure. [solution] By mmc_host_clk_hold() before CMD11, the additional gating/un-gating SD clock between (2) and (3) can be prevented and thus no failure at (11). It has been verified with many UHS-1 SD cards on mb86s7x platforms and works correctly. Signed-off-by: Vincent Yang Reviewed-by: Johan Rudholm Signed-off-by: Ulf Hansson --- drivers/mmc/core/core.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 5bda29bff8eb..9584bffa8b22 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -1447,18 +1447,20 @@ int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage, u32 ocr) pr_warn("%s: cannot verify signal voltage switch\n", mmc_hostname(host)); + mmc_host_clk_hold(host); + cmd.opcode = SD_SWITCH_VOLTAGE; cmd.arg = 0; cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; err = mmc_wait_for_cmd(host, &cmd, 0); if (err) - return err; - - if (!mmc_host_is_spi(host) && (cmd.resp[0] & R1_ERROR)) - return -EIO; + goto err_command; - mmc_host_clk_hold(host); + if (!mmc_host_is_spi(host) && (cmd.resp[0] & R1_ERROR)) { + err = -EIO; + goto err_command; + } /* * The card should drive cmd and dat[0:3] low immediately * after the response of cmd11, but wait 1 ms to be sure @@ -1507,6 +1509,7 @@ power_cycle: mmc_power_cycle(host, ocr); } +err_command: mmc_host_clk_release(host); return err; -- cgit v1.2.3-59-g8ed1b From 996903de92f0c7a32d8c83f37d7ebcea0def8660 Mon Sep 17 00:00:00 2001 From: Minda Chen Date: Wed, 26 Nov 2014 13:05:33 +0800 Subject: mmc: core: add core-level function for sending tuning commands According to the SD card spec, Add a manual tuning command function for SDR104/HS200. Sending command 19 or command 21 to read data and compare with the tunning block pattern. This patch will help to decrease some platform private codes in SDHCI platform_execute_tuning() callbacks. Signed-off-by: Minda Chen Signed-off-by: Barry Song Signed-off-by: Ulf Hansson --- drivers/mmc/core/mmc_ops.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++ include/linux/mmc/core.h | 1 + 2 files changed, 71 insertions(+) diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c index 23aa3a380f27..12b2a32df346 100644 --- a/drivers/mmc/core/mmc_ops.c +++ b/drivers/mmc/core/mmc_ops.c @@ -547,6 +547,76 @@ int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value, } EXPORT_SYMBOL_GPL(mmc_switch); +int mmc_send_tuning(struct mmc_card *card) +{ + struct mmc_request mrq = {NULL}; + struct mmc_command cmd = {0}; + struct mmc_data data = {0}; + struct scatterlist sg; + struct mmc_host *mmc = card->host; + struct mmc_ios *ios = &mmc->ios; + const u8 *tuning_block_pattern; + int size, err = 0; + u8 *data_buf; + u32 opcode; + + if (ios->bus_width == MMC_BUS_WIDTH_8) { + tuning_block_pattern = tuning_blk_pattern_8bit; + size = sizeof(tuning_blk_pattern_8bit); + opcode = MMC_SEND_TUNING_BLOCK_HS200; + } else if (ios->bus_width == MMC_BUS_WIDTH_4) { + tuning_block_pattern = tuning_blk_pattern_4bit; + size = sizeof(tuning_blk_pattern_4bit); + opcode = MMC_SEND_TUNING_BLOCK; + } else + return -EINVAL; + + data_buf = kzalloc(size, GFP_KERNEL); + if (!data_buf) + return -ENOMEM; + + mrq.cmd = &cmd; + mrq.data = &data; + + cmd.opcode = opcode; + cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; + + data.blksz = size; + data.blocks = 1; + data.flags = MMC_DATA_READ; + + /* + * According to the tuning specs, Tuning process + * is normally shorter 40 executions of CMD19, + * and timeout value should be shorter than 150 ms + */ + data.timeout_ns = 150 * NSEC_PER_MSEC; + + data.sg = &sg; + data.sg_len = 1; + sg_init_one(&sg, data_buf, size); + + mmc_wait_for_req(mmc, &mrq); + + if (cmd.error) { + err = cmd.error; + goto out; + } + + if (data.error) { + err = data.error; + goto out; + } + + if (memcmp(data_buf, tuning_block_pattern, size)) + err = -EIO; + +out: + kfree(data_buf); + return err; +} +EXPORT_SYMBOL_GPL(mmc_send_tuning); + static int mmc_send_bus_test(struct mmc_card *card, struct mmc_host *host, u8 opcode, u8 len) diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h index b11e43c10631..c4bdaa128693 100644 --- a/include/linux/mmc/core.h +++ b/include/linux/mmc/core.h @@ -154,6 +154,7 @@ extern void mmc_start_bkops(struct mmc_card *card, bool from_exception); extern int __mmc_switch(struct mmc_card *, u8, u8, u8, unsigned int, bool, bool, bool); extern int mmc_switch(struct mmc_card *, u8, u8, u8, unsigned int); +extern int mmc_send_tuning(struct mmc_card *card); extern int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd); #define MMC_ERASE_ARG 0x00000000 -- cgit v1.2.3-59-g8ed1b From 903101a83949d6fc77c092cef07e9c1e10c07e46 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Tue, 25 Nov 2014 13:05:13 +0100 Subject: mmc: omap_hsmmc: Fix UHS card with DDR50 support The commit, mmc: omap: clarify DDR timing mode between SD-UHS and eMMC, switched omap_hsmmc to support MMC DDR mode instead of UHS DDR50 mode. Add UHS DDR50 mode again and this time let's also keep the MMC DDR mode. Fixes: 5438ad95a57c (mmc: omap: clarify DDR timing mode between SD-UHS and eMMC) Reported-by: Kishon Vijay Abraham I Signed-off-by: Ulf Hansson --- drivers/mmc/host/omap_hsmmc.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 82b40b85293f..7c71dcdcba8b 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -628,6 +628,7 @@ static void omap_hsmmc_set_clock(struct omap_hsmmc_host *host) */ if ((mmc_pdata(host)->features & HSMMC_HAS_HSPE_SUPPORT) && (ios->timing != MMC_TIMING_MMC_DDR52) && + (ios->timing != MMC_TIMING_UHS_DDR50) && ((OMAP_HSMMC_READ(host->base, CAPA) & HSS) == HSS)) { regval = OMAP_HSMMC_READ(host->base, HCTL); if (clkdiv && (clk_get_rate(host->fclk)/clkdiv) > 25000000) @@ -647,7 +648,8 @@ static void omap_hsmmc_set_bus_width(struct omap_hsmmc_host *host) u32 con; con = OMAP_HSMMC_READ(host->base, CON); - if (ios->timing == MMC_TIMING_MMC_DDR52) + if (ios->timing == MMC_TIMING_MMC_DDR52 || + ios->timing == MMC_TIMING_UHS_DDR50) con |= DDR; /* configure in DDR mode */ else con &= ~DDR; -- cgit v1.2.3-59-g8ed1b From 1c7615b90cbcfb10ef5da291b85774cb2ab2cc76 Mon Sep 17 00:00:00 2001 From: "ludovic.desroches@atmel.com" Date: Mon, 1 Dec 2014 15:35:06 +0100 Subject: mmc: atmel-mci: remove useless DMA stuff for non-dt devices All devices with a DMA controller are DT compliant and legacy support has been removed. For those reasons, some DMA stuff is useless. Signed-off-by: Ludovic Desroches Signed-off-by: Ulf Hansson --- drivers/mmc/host/atmel-mci.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c index de2287c5bf3a..f187e75d449c 100644 --- a/drivers/mmc/host/atmel-mci.c +++ b/drivers/mmc/host/atmel-mci.c @@ -2274,17 +2274,9 @@ static void atmci_cleanup_slot(struct atmel_mci_slot *slot, static bool atmci_configure_dma(struct atmel_mci *host) { - struct mci_platform_data *pdata; - dma_cap_mask_t mask; - if (host == NULL) return false; - pdata = host->pdev->dev.platform_data; - - dma_cap_zero(mask); - dma_cap_set(DMA_SLAVE, mask); - host->dma.chan = dma_request_slave_channel(&host->pdev->dev, "rxtx"); if (!host->dma.chan) { dev_warn(&host->pdev->dev, "no DMA channel available\n"); -- cgit v1.2.3-59-g8ed1b From ab050b9269aa545161821cef168976b3bde28d1c Mon Sep 17 00:00:00 2001 From: "ludovic.desroches@atmel.com" Date: Mon, 1 Dec 2014 15:35:07 +0100 Subject: mmc: atmel-mci: remove __init/__exit attributes Using __init/__exit attributes can cause several breakages so remove them. Signed-off-by: Ludovic Desroches Signed-off-by: Ulf Hansson --- drivers/mmc/host/atmel-mci.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c index f187e75d449c..f16d019edb51 100644 --- a/drivers/mmc/host/atmel-mci.c +++ b/drivers/mmc/host/atmel-mci.c @@ -2140,7 +2140,7 @@ static irqreturn_t atmci_detect_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -static int __init atmci_init_slot(struct atmel_mci *host, +static int atmci_init_slot(struct atmel_mci *host, struct mci_slot_pdata *slot_data, unsigned int id, u32 sdc_reg, u32 sdio_irq) { @@ -2302,7 +2302,7 @@ static bool atmci_configure_dma(struct atmel_mci *host) * HSMCI provides DMA support and a new config register but no more supports * PDC. */ -static void __init atmci_get_cap(struct atmel_mci *host) +static void atmci_get_cap(struct atmel_mci *host) { unsigned int version; @@ -2351,7 +2351,7 @@ static void __init atmci_get_cap(struct atmel_mci *host) } } -static int __init atmci_probe(struct platform_device *pdev) +static int atmci_probe(struct platform_device *pdev) { struct mci_platform_data *pdata; struct atmel_mci *host; @@ -2502,7 +2502,7 @@ err_init_slot: return ret; } -static int __exit atmci_remove(struct platform_device *pdev) +static int atmci_remove(struct platform_device *pdev) { struct atmel_mci *host = platform_get_drvdata(pdev); unsigned int i; @@ -2565,7 +2565,7 @@ static const struct dev_pm_ops atmci_dev_pm_ops = { }; static struct platform_driver atmci_driver = { - .remove = __exit_p(atmci_remove), + .remove = atmci_remove, .driver = { .name = "atmel_mci", .of_match_table = of_match_ptr(atmci_dt_ids), -- cgit v1.2.3-59-g8ed1b From 5e0fe89740657116cacf9c40c93a3676536d31fb Mon Sep 17 00:00:00 2001 From: "ludovic.desroches@atmel.com" Date: Mon, 1 Dec 2014 15:35:08 +0100 Subject: mmc: atmel-mci: stop using specific initcall No more use late initcall to manage probing order. Use probe deferring if needed. Signed-off-by: Ludovic Desroches Signed-off-by: Ulf Hansson --- drivers/mmc/host/atmel-mci.c | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c index f16d019edb51..00f60886c1e5 100644 --- a/drivers/mmc/host/atmel-mci.c +++ b/drivers/mmc/host/atmel-mci.c @@ -2565,6 +2565,7 @@ static const struct dev_pm_ops atmci_dev_pm_ops = { }; static struct platform_driver atmci_driver = { + .probe = atmci_probe, .remove = atmci_remove, .driver = { .name = "atmel_mci", @@ -2572,19 +2573,7 @@ static struct platform_driver atmci_driver = { .pm = &atmci_dev_pm_ops, }, }; - -static int __init atmci_init(void) -{ - return platform_driver_probe(&atmci_driver, atmci_probe); -} - -static void __exit atmci_exit(void) -{ - platform_driver_unregister(&atmci_driver); -} - -late_initcall(atmci_init); /* try to load after dma driver when built-in */ -module_exit(atmci_exit); +module_platform_driver(atmci_driver); MODULE_DESCRIPTION("Atmel Multimedia Card Interface driver"); MODULE_AUTHOR("Haavard Skinnemoen (Atmel)"); -- cgit v1.2.3-59-g8ed1b From 467e081d23e67f6216cbe0df911bd5017f1f0b55 Mon Sep 17 00:00:00 2001 From: "ludovic.desroches@atmel.com" Date: Mon, 1 Dec 2014 15:35:09 +0100 Subject: mmc: atmel-mci: use probe deferring if dma controller is not ready yet Return probe defer if requesting a dma channel without a dma controller probed. Signed-off-by: Ludovic Desroches Signed-off-by: Ulf Hansson --- drivers/mmc/host/atmel-mci.c | 48 ++++++++++++++++++++++---------------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c index 00f60886c1e5..62aba9af19f4 100644 --- a/drivers/mmc/host/atmel-mci.c +++ b/drivers/mmc/host/atmel-mci.c @@ -2272,29 +2272,25 @@ static void atmci_cleanup_slot(struct atmel_mci_slot *slot, mmc_free_host(slot->mmc); } -static bool atmci_configure_dma(struct atmel_mci *host) +static int atmci_configure_dma(struct atmel_mci *host) { - if (host == NULL) - return false; + host->dma.chan = dma_request_slave_channel_reason(&host->pdev->dev, + "rxtx"); + if (IS_ERR(host->dma.chan)) + return PTR_ERR(host->dma.chan); + + dev_info(&host->pdev->dev, "using %s for DMA transfers\n", + dma_chan_name(host->dma.chan)); + + host->dma_conf.src_addr = host->mapbase + ATMCI_RDR; + host->dma_conf.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + host->dma_conf.src_maxburst = 1; + host->dma_conf.dst_addr = host->mapbase + ATMCI_TDR; + host->dma_conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + host->dma_conf.dst_maxburst = 1; + host->dma_conf.device_fc = false; - host->dma.chan = dma_request_slave_channel(&host->pdev->dev, "rxtx"); - if (!host->dma.chan) { - dev_warn(&host->pdev->dev, "no DMA channel available\n"); - return false; - } else { - dev_info(&host->pdev->dev, - "using %s for DMA transfers\n", - dma_chan_name(host->dma.chan)); - - host->dma_conf.src_addr = host->mapbase + ATMCI_RDR; - host->dma_conf.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; - host->dma_conf.src_maxburst = 1; - host->dma_conf.dst_addr = host->mapbase + ATMCI_TDR; - host->dma_conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; - host->dma_conf.dst_maxburst = 1; - host->dma_conf.device_fc = false; - return true; - } + return 0; } /* @@ -2411,7 +2407,10 @@ static int atmci_probe(struct platform_device *pdev) /* Get MCI capabilities and set operations according to it */ atmci_get_cap(host); - if (atmci_configure_dma(host)) { + ret = atmci_configure_dma(host); + if (ret == -EPROBE_DEFER) + goto err_dma_probe_defer; + if (ret == 0) { host->prepare_data = &atmci_prepare_data_dma; host->submit_data = &atmci_submit_data_dma; host->stop_transfer = &atmci_stop_transfer_dma; @@ -2496,8 +2495,9 @@ err_init_slot: pm_runtime_put_noidle(&pdev->dev); del_timer_sync(&host->timer); - if (host->dma.chan) + if (!IS_ERR(host->dma.chan)) dma_release_channel(host->dma.chan); +err_dma_probe_defer: free_irq(irq, host); return ret; } @@ -2523,7 +2523,7 @@ static int atmci_remove(struct platform_device *pdev) atmci_readl(host, ATMCI_SR); del_timer_sync(&host->timer); - if (host->dma.chan) + if (!IS_ERR(host->dma.chan)) dma_release_channel(host->dma.chan); free_irq(platform_get_irq(pdev, 0), host); -- cgit v1.2.3-59-g8ed1b From db6e8cdfcde84be556baa6d6b2424668ca21a36c Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Mon, 1 Dec 2014 15:51:16 +0200 Subject: mmc: sdhci-pci: Add SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC to BYT SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC actually causes standard-compliant behaviour by causing the flagging of the last DMA transfer descriptor as the end instead of there being an additional nop descriptor which is flagged as the end. Consequently, it is better to have the quirk. Add it for BYT. Signed-off-by: Adrian Hunter Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-pci.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c index c1ecd204c194..632e9d966e5b 100644 --- a/drivers/mmc/host/sdhci-pci.c +++ b/drivers/mmc/host/sdhci-pci.c @@ -294,11 +294,13 @@ static int byt_sd_probe_slot(struct sdhci_pci_slot *slot) static const struct sdhci_pci_fixes sdhci_intel_byt_emmc = { .allow_runtime_pm = true, .probe_slot = byt_emmc_probe_slot, + .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | SDHCI_QUIRK2_STOP_WITH_TC, }; static const struct sdhci_pci_fixes sdhci_intel_byt_sdio = { + .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, .quirks2 = SDHCI_QUIRK2_HOST_OFF_CARD_ON | SDHCI_QUIRK2_PRESET_VALUE_BROKEN, .allow_runtime_pm = true, @@ -306,6 +308,7 @@ static const struct sdhci_pci_fixes sdhci_intel_byt_sdio = { }; static const struct sdhci_pci_fixes sdhci_intel_byt_sd = { + .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, .quirks2 = SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON | SDHCI_QUIRK2_PRESET_VALUE_BROKEN | SDHCI_QUIRK2_STOP_WITH_TC, -- cgit v1.2.3-59-g8ed1b From e1f5633ad4ddcef37a6dc9a5a64159978c0f7a22 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Mon, 1 Dec 2014 15:51:17 +0200 Subject: mmc: sdhci-acpi: Add SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC actually causes standard-compliant behaviour by causing the flagging of the last DMA transfer descriptor as the end instead of there being an additional nop descriptor which is flagged as the end. Consequently, it is better to have the quirk. Signed-off-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 310976307954..de67ae60d1b3 100644 --- a/drivers/mmc/host/sdhci-acpi.c +++ b/drivers/mmc/host/sdhci-acpi.c @@ -206,12 +206,14 @@ static const struct sdhci_acpi_slot sdhci_acpi_slot_int_emmc = { MMC_CAP_HW_RESET | MMC_CAP_1_8V_DDR, .caps2 = MMC_CAP2_HC_ERASE_SZ, .flags = SDHCI_ACPI_RUNTIME_PM, + .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | SDHCI_QUIRK2_STOP_WITH_TC, .probe_slot = sdhci_acpi_emmc_probe_slot, }; static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sdio = { - .quirks = SDHCI_QUIRK_BROKEN_CARD_DETECTION, + .quirks = SDHCI_QUIRK_BROKEN_CARD_DETECTION | + SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, .quirks2 = SDHCI_QUIRK2_HOST_OFF_CARD_ON, .caps = MMC_CAP_NONREMOVABLE | MMC_CAP_POWER_OFF_CARD, .flags = SDHCI_ACPI_RUNTIME_PM, @@ -222,6 +224,7 @@ static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sdio = { static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sd = { .flags = SDHCI_ACPI_SD_CD | SDHCI_ACPI_SD_CD_OVERRIDE_LEVEL | SDHCI_ACPI_RUNTIME_PM, + .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, .quirks2 = SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON | SDHCI_QUIRK2_STOP_WITH_TC, .probe_slot = sdhci_acpi_sd_probe_slot, -- cgit v1.2.3-59-g8ed1b From 6aab23a8f79667e500883adb3bee76ceec9fceb6 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Mon, 1 Dec 2014 15:51:18 +0200 Subject: mmc: sdhci-pci: Add two host capabilities for BYT BYT host controllers are capable of doing the bus width test and of waiting while busy, so add the capability flags. Signed-off-by: Adrian Hunter Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-pci.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c index 632e9d966e5b..95f73007fccf 100644 --- a/drivers/mmc/host/sdhci-pci.c +++ b/drivers/mmc/host/sdhci-pci.c @@ -269,7 +269,9 @@ static void sdhci_pci_int_hw_reset(struct sdhci_host *host) static int byt_emmc_probe_slot(struct sdhci_pci_slot *slot) { slot->host->mmc->caps |= MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE | - MMC_CAP_HW_RESET | MMC_CAP_1_8V_DDR; + MMC_CAP_HW_RESET | MMC_CAP_1_8V_DDR | + MMC_CAP_BUS_WIDTH_TEST | + MMC_CAP_WAIT_WHILE_BUSY; slot->host->mmc->caps2 |= MMC_CAP2_HC_ERASE_SZ; slot->hw_reset = sdhci_pci_int_hw_reset; if (slot->chip->pdev->device == PCI_DEVICE_ID_INTEL_BSW_EMMC) @@ -279,12 +281,16 @@ static int byt_emmc_probe_slot(struct sdhci_pci_slot *slot) static int byt_sdio_probe_slot(struct sdhci_pci_slot *slot) { - slot->host->mmc->caps |= MMC_CAP_POWER_OFF_CARD | MMC_CAP_NONREMOVABLE; + slot->host->mmc->caps |= MMC_CAP_POWER_OFF_CARD | MMC_CAP_NONREMOVABLE | + MMC_CAP_BUS_WIDTH_TEST | + MMC_CAP_WAIT_WHILE_BUSY; return 0; } static int byt_sd_probe_slot(struct sdhci_pci_slot *slot) { + slot->host->mmc->caps |= MMC_CAP_BUS_WIDTH_TEST | + MMC_CAP_WAIT_WHILE_BUSY; slot->cd_con_id = NULL; slot->cd_idx = 0; slot->cd_override_level = true; -- cgit v1.2.3-59-g8ed1b From 9d65cb88e5979d43f47c899601353ca61973ba90 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Mon, 1 Dec 2014 15:51:19 +0200 Subject: mmc: sdhci-acpi: Add two host capabilities for Intel Intel host controllers are capable of doing the bus width test and of waiting while busy, so add the capability flags. Signed-off-by: Adrian Hunter Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-acpi.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/sdhci-acpi.c b/drivers/mmc/host/sdhci-acpi.c index de67ae60d1b3..daba49ac1242 100644 --- a/drivers/mmc/host/sdhci-acpi.c +++ b/drivers/mmc/host/sdhci-acpi.c @@ -203,7 +203,8 @@ static int sdhci_acpi_sd_probe_slot(struct platform_device *pdev, static const struct sdhci_acpi_slot sdhci_acpi_slot_int_emmc = { .chip = &sdhci_acpi_chip_int, .caps = MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE | - MMC_CAP_HW_RESET | MMC_CAP_1_8V_DDR, + MMC_CAP_HW_RESET | MMC_CAP_1_8V_DDR | + MMC_CAP_BUS_WIDTH_TEST | MMC_CAP_WAIT_WHILE_BUSY, .caps2 = MMC_CAP2_HC_ERASE_SZ, .flags = SDHCI_ACPI_RUNTIME_PM, .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, @@ -215,7 +216,8 @@ static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sdio = { .quirks = SDHCI_QUIRK_BROKEN_CARD_DETECTION | SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, .quirks2 = SDHCI_QUIRK2_HOST_OFF_CARD_ON, - .caps = MMC_CAP_NONREMOVABLE | MMC_CAP_POWER_OFF_CARD, + .caps = MMC_CAP_NONREMOVABLE | MMC_CAP_POWER_OFF_CARD | + MMC_CAP_BUS_WIDTH_TEST | MMC_CAP_WAIT_WHILE_BUSY, .flags = SDHCI_ACPI_RUNTIME_PM, .pm_caps = MMC_PM_KEEP_POWER, .probe_slot = sdhci_acpi_sdio_probe_slot, @@ -227,6 +229,7 @@ static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sd = { .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, .quirks2 = SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON | SDHCI_QUIRK2_STOP_WITH_TC, + .caps = MMC_CAP_BUS_WIDTH_TEST | MMC_CAP_WAIT_WHILE_BUSY, .probe_slot = sdhci_acpi_sd_probe_slot, }; -- cgit v1.2.3-59-g8ed1b From fdb409f636cd6fc3ac4e2f9c880402860e738554 Mon Sep 17 00:00:00 2001 From: Bhuvanesh Surachari Date: Mon, 1 Dec 2014 02:23:02 -0500 Subject: mmc: queue: Improve error handling during allocation of bounce buffers Allocation of previous bounce buffer in mmc_init_queue when the current bounce buffer allocation fails was leading to a crash later in __blk_segment_map_sg. Error handling is improved by allocating previous bounce buffer only if the current bounce buffer allocation succeeds. Signed-off-by: Bhuvanesh Surachari Signed-off-by: Harish Jenny K N Signed-off-by: Ulf Hansson --- drivers/mmc/card/queue.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c index cfa6110632c3..236d194c2883 100644 --- a/drivers/mmc/card/queue.c +++ b/drivers/mmc/card/queue.c @@ -232,13 +232,15 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, if (!mqrq_cur->bounce_buf) { pr_warn("%s: unable to allocate bounce cur buffer\n", mmc_card_name(card)); - } - mqrq_prev->bounce_buf = kmalloc(bouncesz, GFP_KERNEL); - if (!mqrq_prev->bounce_buf) { - pr_warn("%s: unable to allocate bounce prev buffer\n", - mmc_card_name(card)); - kfree(mqrq_cur->bounce_buf); - mqrq_cur->bounce_buf = NULL; + } else { + mqrq_prev->bounce_buf = + kmalloc(bouncesz, GFP_KERNEL); + if (!mqrq_prev->bounce_buf) { + pr_warn("%s: unable to allocate bounce prev buffer\n", + mmc_card_name(card)); + kfree(mqrq_cur->bounce_buf); + mqrq_cur->bounce_buf = NULL; + } } } -- cgit v1.2.3-59-g8ed1b From fe5afb13d46e76b07ab7e732f2b694dcafef4d9d Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Fri, 5 Dec 2014 11:31:22 +0100 Subject: mmc: core: Let mmc_send_tuning() to take struct mmc_host* as parameter To be able to use mmc_send_tuning() prior the struct mmc_card has been allocated, let's convert it to take the struct mmc_host* as parameter instead. Suggested-by: Stephen Boyd Signed-off-by: Ulf Hansson Acked-by: Dong Aisheng Reviewed-by: Stephen Boyd --- drivers/mmc/core/mmc_ops.c | 7 +++---- include/linux/mmc/core.h | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c index 12b2a32df346..3b044c5b029c 100644 --- a/drivers/mmc/core/mmc_ops.c +++ b/drivers/mmc/core/mmc_ops.c @@ -547,14 +547,13 @@ int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value, } EXPORT_SYMBOL_GPL(mmc_switch); -int mmc_send_tuning(struct mmc_card *card) +int mmc_send_tuning(struct mmc_host *host) { struct mmc_request mrq = {NULL}; struct mmc_command cmd = {0}; struct mmc_data data = {0}; struct scatterlist sg; - struct mmc_host *mmc = card->host; - struct mmc_ios *ios = &mmc->ios; + struct mmc_ios *ios = &host->ios; const u8 *tuning_block_pattern; int size, err = 0; u8 *data_buf; @@ -596,7 +595,7 @@ int mmc_send_tuning(struct mmc_card *card) data.sg_len = 1; sg_init_one(&sg, data_buf, size); - mmc_wait_for_req(mmc, &mrq); + mmc_wait_for_req(host, &mrq); if (cmd.error) { err = cmd.error; diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h index c4bdaa128693..cb2b0400d284 100644 --- a/include/linux/mmc/core.h +++ b/include/linux/mmc/core.h @@ -154,7 +154,7 @@ extern void mmc_start_bkops(struct mmc_card *card, bool from_exception); extern int __mmc_switch(struct mmc_card *, u8, u8, u8, unsigned int, bool, bool, bool); extern int mmc_switch(struct mmc_card *, u8, u8, u8, unsigned int); -extern int mmc_send_tuning(struct mmc_card *card); +extern int mmc_send_tuning(struct mmc_host *host); extern int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd); #define MMC_ERASE_ARG 0x00000000 -- cgit v1.2.3-59-g8ed1b From d1785326891c2f9919163be5dae8f2538cfcae58 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Fri, 5 Dec 2014 12:59:40 +0100 Subject: mmc: sdhci-esdhc-imx: Convert to mmc_send_tuning() Instead of having a local function taking care of sending the tuning command, let's use the common mmc_send_tuning() API provided by the mmc core. In this way the request will be handled as any other request by sdhci core. As an effect of this change, the pm_runtime_get_sync() call at esdhc_prepare_tuning() isn't needed any more. This patch will also introduce another change in behavior, since before the response pattern to the tuning command wasn't verified by sdhci-esdhc-imx. The mmc_send_tuning() does that. Signed-off-by: Ulf Hansson Tested-by: Dong Aisheng Acked-by: Dong Aisheng --- drivers/mmc/host/sdhci-esdhc-imx.c | 68 ++------------------------------------ 1 file changed, 3 insertions(+), 65 deletions(-) diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c index 0135f00f826f..12711ab51aed 100644 --- a/drivers/mmc/host/sdhci-esdhc-imx.c +++ b/drivers/mmc/host/sdhci-esdhc-imx.c @@ -65,8 +65,6 @@ /* NOTE: the minimum valid tuning start tap for mx6sl is 1 */ #define ESDHC_TUNING_START_TAP 0x1 -#define ESDHC_TUNING_BLOCK_PATTERN_LEN 64 - /* pinctrl state */ #define ESDHC_PINCTRL_STATE_100MHZ "state_100mhz" #define ESDHC_PINCTRL_STATE_200MHZ "state_200mhz" @@ -692,8 +690,6 @@ static void esdhc_prepare_tuning(struct sdhci_host *host, u32 val) /* FIXME: delay a bit for card to be ready for next tuning due to errors */ mdelay(1); - /* This is balanced by the runtime put in sdhci_tasklet_finish */ - pm_runtime_get_sync(host->mmc->parent); reg = readl(host->ioaddr + ESDHC_MIX_CTRL); reg |= ESDHC_MIX_CTRL_EXE_TUNE | ESDHC_MIX_CTRL_SMPCLK_SEL | ESDHC_MIX_CTRL_FBCLK_SEL; @@ -704,54 +700,6 @@ static void esdhc_prepare_tuning(struct sdhci_host *host, u32 val) val, readl(host->ioaddr + ESDHC_TUNE_CTRL_STATUS)); } -static void esdhc_request_done(struct mmc_request *mrq) -{ - complete(&mrq->completion); -} - -static int esdhc_send_tuning_cmd(struct sdhci_host *host, u32 opcode, - struct scatterlist *sg) -{ - struct mmc_command cmd = {0}; - struct mmc_request mrq = {NULL}; - struct mmc_data data = {0}; - - cmd.opcode = opcode; - cmd.arg = 0; - cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; - - data.blksz = ESDHC_TUNING_BLOCK_PATTERN_LEN; - data.blocks = 1; - data.flags = MMC_DATA_READ; - data.sg = sg; - data.sg_len = 1; - - mrq.cmd = &cmd; - mrq.cmd->mrq = &mrq; - mrq.data = &data; - mrq.data->mrq = &mrq; - mrq.cmd->data = mrq.data; - - mrq.done = esdhc_request_done; - init_completion(&(mrq.completion)); - - spin_lock_irq(&host->lock); - host->mrq = &mrq; - - sdhci_send_command(host, mrq.cmd); - - spin_unlock_irq(&host->lock); - - wait_for_completion(&mrq.completion); - - if (cmd.error) - return cmd.error; - if (data.error) - return data.error; - - return 0; -} - static void esdhc_post_tuning(struct sdhci_host *host) { u32 reg; @@ -763,21 +711,13 @@ static void esdhc_post_tuning(struct sdhci_host *host) static int esdhc_executing_tuning(struct sdhci_host *host, u32 opcode) { - struct scatterlist sg; - char *tuning_pattern; int min, max, avg, ret; - tuning_pattern = kmalloc(ESDHC_TUNING_BLOCK_PATTERN_LEN, GFP_KERNEL); - if (!tuning_pattern) - return -ENOMEM; - - sg_init_one(&sg, tuning_pattern, ESDHC_TUNING_BLOCK_PATTERN_LEN); - /* find the mininum delay first which can pass tuning */ min = ESDHC_TUNE_CTRL_MIN; while (min < ESDHC_TUNE_CTRL_MAX) { esdhc_prepare_tuning(host, min); - if (!esdhc_send_tuning_cmd(host, opcode, &sg)) + if (!mmc_send_tuning(host->mmc)) break; min += ESDHC_TUNE_CTRL_STEP; } @@ -786,7 +726,7 @@ static int esdhc_executing_tuning(struct sdhci_host *host, u32 opcode) max = min + ESDHC_TUNE_CTRL_STEP; while (max < ESDHC_TUNE_CTRL_MAX) { esdhc_prepare_tuning(host, max); - if (esdhc_send_tuning_cmd(host, opcode, &sg)) { + if (mmc_send_tuning(host->mmc)) { max -= ESDHC_TUNE_CTRL_STEP; break; } @@ -796,11 +736,9 @@ static int esdhc_executing_tuning(struct sdhci_host *host, u32 opcode) /* use average delay to get the best timing */ avg = (min + max) / 2; esdhc_prepare_tuning(host, avg); - ret = esdhc_send_tuning_cmd(host, opcode, &sg); + ret = mmc_send_tuning(host->mmc); esdhc_post_tuning(host); - kfree(tuning_pattern); - dev_dbg(mmc_dev(host->mmc), "tunning %s at 0x%x ret %d\n", ret ? "failed" : "passed", avg, ret); -- cgit v1.2.3-59-g8ed1b From 33d73935e4abb2c75f263dd31a314db09ccf41be Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Fri, 5 Dec 2014 12:59:41 +0100 Subject: mmc: sdhci-msm: Convert to mmc_send_tuning() Instead of having a local hack taking care of sending the tuning command and as well to verify the response pattern, let's convert to the common mmc_send_tuning() API instead. Signed-off-by: Ulf Hansson Tested-by: Georgi Djakov Acked-by: Georgi Djakov Reviewed-by: Stephen Boyd --- drivers/mmc/host/sdhci-msm.c | 50 +++++++------------------------------------- 1 file changed, 7 insertions(+), 43 deletions(-) diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index 30804385af6d..3d32ce896b09 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -339,9 +339,7 @@ static int msm_init_cm_dll(struct sdhci_host *host) static int sdhci_msm_execute_tuning(struct sdhci_host *host, u32 opcode) { int tuning_seq_cnt = 3; - u8 phase, *data_buf, tuned_phases[16], tuned_phase_cnt = 0; - const u8 *tuning_block_pattern = tuning_blk_pattern_4bit; - int size = sizeof(tuning_blk_pattern_4bit); + u8 phase, tuned_phases[16], tuned_phase_cnt = 0; int rc; struct mmc_host *mmc = host->mmc; struct mmc_ios ios = host->mmc->ios; @@ -355,53 +353,21 @@ static int sdhci_msm_execute_tuning(struct sdhci_host *host, u32 opcode) (ios.timing == MMC_TIMING_UHS_SDR104))) return 0; - if ((opcode == MMC_SEND_TUNING_BLOCK_HS200) && - (mmc->ios.bus_width == MMC_BUS_WIDTH_8)) { - tuning_block_pattern = tuning_blk_pattern_8bit; - size = sizeof(tuning_blk_pattern_8bit); - } - - data_buf = kmalloc(size, GFP_KERNEL); - if (!data_buf) - return -ENOMEM; - retry: /* First of all reset the tuning block */ rc = msm_init_cm_dll(host); if (rc) - goto out; + return rc; phase = 0; do { - struct mmc_command cmd = { 0 }; - struct mmc_data data = { 0 }; - struct mmc_request mrq = { - .cmd = &cmd, - .data = &data - }; - struct scatterlist sg; - /* Set the phase in delay line hw block */ rc = msm_config_cm_dll_phase(host, phase); if (rc) - goto out; + return rc; - cmd.opcode = opcode; - cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; - - data.blksz = size; - data.blocks = 1; - data.flags = MMC_DATA_READ; - data.timeout_ns = NSEC_PER_SEC; /* 1 second */ - - data.sg = &sg; - data.sg_len = 1; - sg_init_one(&sg, data_buf, size); - memset(data_buf, 0, size); - mmc_wait_for_req(mmc, &mrq); - - if (!cmd.error && !data.error && - !memcmp(data_buf, tuning_block_pattern, size)) { + rc = mmc_send_tuning(mmc); + if (!rc) { /* Tuning is successful at this tuning point */ tuned_phases[tuned_phase_cnt++] = phase; dev_dbg(mmc_dev(mmc), "%s: Found good phase = %d\n", @@ -413,7 +379,7 @@ retry: rc = msm_find_most_appropriate_phase(host, tuned_phases, tuned_phase_cnt); if (rc < 0) - goto out; + return rc; else phase = rc; @@ -423,7 +389,7 @@ retry: */ rc = msm_config_cm_dll_phase(host, phase); if (rc) - goto out; + return rc; dev_dbg(mmc_dev(mmc), "%s: Setting the tuning phase to %d\n", mmc_hostname(mmc), phase); } else { @@ -435,8 +401,6 @@ retry: rc = -EIO; } -out: - kfree(data_buf); return rc; } -- cgit v1.2.3-59-g8ed1b