From c48c5d580e2aa6c22759836759b3c01e4ee9e8c0 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Tue, 29 Dec 2015 21:11:45 +0100 Subject: mmc: sdricoh_cs: Delete unnecessary variable initialisations These variables will eventually be set to an appropriate value a bit later. * host * iobase * result Thus let us omit the explicit initialisation at the beginning. Signed-off-by: Markus Elfring Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sdricoh_cs.c b/drivers/mmc/host/sdricoh_cs.c index b7e3057..5e57d9f 100644 --- a/drivers/mmc/host/sdricoh_cs.c +++ b/drivers/mmc/host/sdricoh_cs.c @@ -398,10 +398,10 @@ static struct mmc_host_ops sdricoh_ops = { static int sdricoh_init_mmc(struct pci_dev *pci_dev, struct pcmcia_device *pcmcia_dev) { - int result = 0; - void __iomem *iobase = NULL; + int result; + void __iomem *iobase; struct mmc_host *mmc = NULL; - struct sdricoh_host *host = NULL; + struct sdricoh_host *host; struct device *dev = &pcmcia_dev->dev; /* map iomem */ if (pci_resource_len(pci_dev, SDRICOH_PCI_REGION) != -- cgit v0.10.2 From 1856de3d3e6cd6c2fe2f53f29f6b572795e3257a Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Tue, 29 Dec 2015 21:45:34 +0100 Subject: mmc: sdricoh_cs: Less checks in sdricoh_init_mmc() after, error detection This issue was detected by using the Coccinelle software. Two pointer checks could be repeated by the sdricoh_init_mmc() function during error handling even if the relevant properties can be determined for the involved variables before by source code analysis. * This implementation detail could be improved by adjustments for jump targets according to the Linux coding style convention. * Drop an unnecessary initialisation for the variable "mmc" then. Signed-off-by: Markus Elfring Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sdricoh_cs.c b/drivers/mmc/host/sdricoh_cs.c index 5e57d9f..5ff26ab 100644 --- a/drivers/mmc/host/sdricoh_cs.c +++ b/drivers/mmc/host/sdricoh_cs.c @@ -400,7 +400,7 @@ static int sdricoh_init_mmc(struct pci_dev *pci_dev, { int result; void __iomem *iobase; - struct mmc_host *mmc = NULL; + struct mmc_host *mmc; struct sdricoh_host *host; struct device *dev = &pcmcia_dev->dev; /* map iomem */ @@ -419,7 +419,7 @@ static int sdricoh_init_mmc(struct pci_dev *pci_dev, if (readl(iobase + R104_VERSION) != 0x4000) { dev_dbg(dev, "no supported mmc controller found\n"); result = -ENODEV; - goto err; + goto unmap_io; } /* allocate privdata */ mmc = pcmcia_dev->priv = @@ -427,7 +427,7 @@ static int sdricoh_init_mmc(struct pci_dev *pci_dev, if (!mmc) { dev_err(dev, "mmc_alloc_host failed\n"); result = -ENOMEM; - goto err; + goto unmap_io; } host = mmc_priv(mmc); @@ -451,8 +451,7 @@ static int sdricoh_init_mmc(struct pci_dev *pci_dev, if (sdricoh_reset(host)) { dev_dbg(dev, "could not reset\n"); result = -EIO; - goto err; - + goto free_host; } result = mmc_add_host(mmc); @@ -461,13 +460,10 @@ static int sdricoh_init_mmc(struct pci_dev *pci_dev, dev_dbg(dev, "mmc host registered\n"); return 0; } - -err: - if (iobase) - pci_iounmap(pci_dev, iobase); - if (mmc) - mmc_free_host(mmc); - +free_host: + mmc_free_host(mmc); +unmap_io: + pci_iounmap(pci_dev, iobase); return result; } -- cgit v0.10.2 From 1046a811511d2cb5a59ead53f528d693a5c7fdd2 Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Fri, 1 Jan 2016 22:59:09 +0800 Subject: mmc: sh_mmcif: use to_delayed_work Use to_delayed_work() instead of open-coding it. Signed-off-by: Geliang Tang Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c index 6234eab3..8d870ce 100644 --- a/drivers/mmc/host/sh_mmcif.c +++ b/drivers/mmc/host/sh_mmcif.c @@ -1395,7 +1395,7 @@ static irqreturn_t sh_mmcif_intr(int irq, void *dev_id) static void sh_mmcif_timeout_work(struct work_struct *work) { - struct delayed_work *d = container_of(work, struct delayed_work, work); + struct delayed_work *d = to_delayed_work(work); struct sh_mmcif_host *host = container_of(d, struct sh_mmcif_host, timeout_work); struct mmc_request *mrq = host->mrq; struct device *dev = sh_mmcif_host_to_dev(host); -- cgit v0.10.2 From 238fc95e836917d290931b9700ab2f711b879629 Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Fri, 1 Jan 2016 22:59:10 +0800 Subject: mmc: usdhi6rol0: use to_delayed_work Use to_delayed_work() instead of open-coding it. Signed-off-by: Geliang Tang Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/usdhi6rol0.c b/drivers/mmc/host/usdhi6rol0.c index b47122d..b2752fe 100644 --- a/drivers/mmc/host/usdhi6rol0.c +++ b/drivers/mmc/host/usdhi6rol0.c @@ -1630,7 +1630,7 @@ static irqreturn_t usdhi6_cd(int irq, void *dev_id) */ static void usdhi6_timeout_work(struct work_struct *work) { - struct delayed_work *d = container_of(work, struct delayed_work, work); + struct delayed_work *d = to_delayed_work(work); struct usdhi6_host *host = container_of(d, struct usdhi6_host, timeout_work); struct mmc_request *mrq = host->mrq; struct mmc_data *data = mrq ? mrq->data : NULL; -- cgit v0.10.2 From 62c03ca3ffa1ddf55a66411be02f7e4678771fce Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Wed, 6 Jan 2016 11:34:10 +0800 Subject: mmc: core: pwrseq_simple: remove unused header file Signed-off-by: Peter Chen Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/core/pwrseq_simple.c b/drivers/mmc/core/pwrseq_simple.c index aba786d..bc173e1 100644 --- a/drivers/mmc/core/pwrseq_simple.c +++ b/drivers/mmc/core/pwrseq_simple.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include -- cgit v0.10.2 From 0899e741938758e20cbca055f66b0f5558da7a49 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 8 Jan 2016 11:15:25 +0900 Subject: mmc: remove unnecessary assignment statements before return Variable assignment just before return is redundant. Signed-off-by: Masahiro Yamada Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c index 2c90635..62355bd 100644 --- a/drivers/mmc/core/mmc_ops.c +++ b/drivers/mmc/core/mmc_ops.c @@ -90,7 +90,6 @@ int mmc_send_status(struct mmc_card *card, u32 *status) static int _mmc_select_card(struct mmc_host *host, struct mmc_card *card) { - int err; struct mmc_command cmd = {0}; BUG_ON(!host); @@ -105,11 +104,7 @@ static int _mmc_select_card(struct mmc_host *host, struct mmc_card *card) cmd.flags = MMC_RSP_NONE | MMC_CMD_AC; } - err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES); - if (err) - return err; - - return 0; + return mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES); } int mmc_select_card(struct mmc_card *card) @@ -244,7 +239,6 @@ int mmc_all_send_cid(struct mmc_host *host, u32 *cid) int mmc_set_relative_addr(struct mmc_card *card) { - int err; struct mmc_command cmd = {0}; BUG_ON(!card); @@ -254,11 +248,7 @@ int mmc_set_relative_addr(struct mmc_card *card) cmd.arg = card->rca << 16; cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; - err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES); - if (err) - return err; - - return 0; + return mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES); } static int @@ -743,7 +733,7 @@ mmc_send_bus_test(struct mmc_card *card, struct mmc_host *host, u8 opcode, int mmc_bus_test(struct mmc_card *card, u8 bus_width) { - int err, width; + int width; if (bus_width == MMC_BUS_WIDTH_8) width = 8; @@ -759,8 +749,7 @@ int mmc_bus_test(struct mmc_card *card, u8 bus_width) * is a problem. This improves chances that the test will work. */ mmc_send_bus_test(card, card->host, MMC_BUS_TEST_W, width); - err = mmc_send_bus_test(card, card->host, MMC_BUS_TEST_R, width); - return err; + return mmc_send_bus_test(card, card->host, MMC_BUS_TEST_R, width); } int mmc_send_hpi_cmd(struct mmc_card *card, u32 *status) diff --git a/drivers/mmc/core/sd_ops.c b/drivers/mmc/core/sd_ops.c index 48d0c93..16b774c 100644 --- a/drivers/mmc/core/sd_ops.c +++ b/drivers/mmc/core/sd_ops.c @@ -120,7 +120,6 @@ EXPORT_SYMBOL(mmc_wait_for_app_cmd); int mmc_app_set_bus_width(struct mmc_card *card, int width) { - int err; struct mmc_command cmd = {0}; BUG_ON(!card); @@ -140,11 +139,7 @@ int mmc_app_set_bus_width(struct mmc_card *card, int width) return -EINVAL; } - err = mmc_wait_for_app_cmd(card->host, card, &cmd, MMC_CMD_RETRIES); - if (err) - return err; - - return 0; + return mmc_wait_for_app_cmd(card->host, card, &cmd, MMC_CMD_RETRIES); } int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) diff --git a/drivers/mmc/core/sdio_ops.c b/drivers/mmc/core/sdio_ops.c index 62508b4..34f6e80 100644 --- a/drivers/mmc/core/sdio_ops.c +++ b/drivers/mmc/core/sdio_ops.c @@ -217,7 +217,6 @@ int sdio_reset(struct mmc_host *host) else abort |= 0x08; - ret = mmc_io_rw_direct_host(host, 1, 0, SDIO_CCCR_ABORT, abort, NULL); - return ret; + return mmc_io_rw_direct_host(host, 1, 0, SDIO_CCCR_ABORT, abort, NULL); } -- cgit v0.10.2 From 9143757b57ce549127e1f7bc942e7b61e3b51adf Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Thu, 14 Jan 2016 14:45:20 +0530 Subject: mmc: host: omap_hsmmc: add a verbose print to enable CONFIG_REGULATOR_PBIAS Since v4.3+, CONFIG_REGULATOR_PBIAS should be enabled (for platforms that have PBIAS regulator) in order for MMC1 to work. Add a more verbose print to help enable CONFIG_REGULATOR_PBIAS for users using a olddefconfig or a custom .config. Signed-off-by: Kishon Vijay Abraham I Acked-by: Sebastian Reichel Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index f6e4d97..f636ef2 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -503,8 +503,11 @@ static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host) host->pbias = devm_regulator_get_optional(host->dev, "pbias"); if (IS_ERR(host->pbias)) { ret = PTR_ERR(host->pbias); - if ((ret != -ENODEV) && host->dev->of_node) + if ((ret != -ENODEV) && host->dev->of_node) { + dev_err(host->dev, + "SD card detect fail? enable CONFIG_REGULATOR_PBIAS\n"); return ret; + } dev_dbg(host->dev, "unable to get pbias regulator %ld\n", PTR_ERR(host->pbias)); host->pbias = NULL; -- cgit v0.10.2 From e99369dc95fe99d4ee5f8a0f8bef59062365b7d1 Mon Sep 17 00:00:00 2001 From: Rameshwar Prasad Sahu Date: Wed, 23 Dec 2015 18:59:51 +0530 Subject: mmc: sdhci-of-arasan: Remove no-hispd and no-cmd23 quirks for sdhci-arasan4.9a The Arason SD host controller supports set block count command (cmd23) and high speed mode. This patch re-enable both of these features that was disabled. For device that doesn't support high speed, it should configure its capability register accordingly instead disables it explicitly. Signed-off-by: Rameshwar Prasad Sahu Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sdhci-of-arasan.c b/drivers/mmc/host/sdhci-of-arasan.c index 75379cb..5d9fdb3 100644 --- a/drivers/mmc/host/sdhci-of-arasan.c +++ b/drivers/mmc/host/sdhci-of-arasan.c @@ -172,11 +172,6 @@ static int sdhci_arasan_probe(struct platform_device *pdev) goto clk_disable_all; } - if (of_device_is_compatible(pdev->dev.of_node, "arasan,sdhci-4.9a")) { - host->quirks |= SDHCI_QUIRK_NO_HISPD_BIT; - host->quirks2 |= SDHCI_QUIRK2_HOST_NO_CMD23; - } - sdhci_get_of_property(pdev); pltfm_host = sdhci_priv(host); pltfm_host->priv = sdhci_arasan; -- cgit v0.10.2 From 1d6ad05777c27c7e8cfb32997a78c8252b85fbb4 Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Sun, 17 Jan 2016 14:59:00 +0000 Subject: mmc: sdhci-iproc: Clean up platform allocations if shdci init fails This patch adopts the changes from 475c9e43bfa7 ("mmc: sdhci-bcm2835: Clean up platform allocations if sdhci init fails") to sdhci-iproc. Signed-off-by: Stefan Wahren Acked-by: Scott Branden Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sdhci-iproc.c b/drivers/mmc/host/sdhci-iproc.c index 3b423b0..e22060a 100644 --- a/drivers/mmc/host/sdhci-iproc.c +++ b/drivers/mmc/host/sdhci-iproc.c @@ -213,7 +213,11 @@ static int sdhci_iproc_probe(struct platform_device *pdev) host->caps1 = iproc_host->data->caps1; } - return sdhci_add_host(host); + ret = sdhci_add_host(host); + if (ret) + goto err; + + return 0; err: sdhci_pltfm_free(pdev); -- cgit v0.10.2 From e5905ff1281f0a0f5c9863c430ac1ed5faaf5707 Mon Sep 17 00:00:00 2001 From: Chuanxiao Dong Date: Thu, 21 Jan 2016 13:57:51 +0100 Subject: mmc: debugfs: Add a restriction to mmc debugfs clock setting Clock frequency values written to an mmc host should not be less than the minimum clock frequency which the mmc host supports. Signed-off-by: Yuan Juntao Signed-off-by: Pawel Wodkowski Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c index 65cc0ac..9382a57 100644 --- a/drivers/mmc/core/debugfs.c +++ b/drivers/mmc/core/debugfs.c @@ -220,7 +220,7 @@ static int mmc_clock_opt_set(void *data, u64 val) struct mmc_host *host = data; /* We need this check due to input value is u64 */ - if (val > host->f_max) + if (val != 0 && (val > host->f_max || val < host->f_min)) return -EINVAL; mmc_claim_host(host); -- cgit v0.10.2 From 9f24b0f2542f60bde7b699469a97cd852e1eed79 Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Sun, 17 Jan 2016 14:59:01 +0000 Subject: mmc: sdhci-iproc: Actually enable the clock The RPi firmware-based clocks driver can actually disable unused clocks, so when switching to use it we ended up losing our MMC clock once all devices were probed. This patch adopts the changes from 1e5a0a9a58e2 ("mmc: sdhci-bcm2835: Actually enable the clock") to sdhci-iproc. Signed-off-by: Stefan Wahren Acked-by: Scott Branden Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sdhci-iproc.c b/drivers/mmc/host/sdhci-iproc.c index e22060a..55bc348 100644 --- a/drivers/mmc/host/sdhci-iproc.c +++ b/drivers/mmc/host/sdhci-iproc.c @@ -207,6 +207,11 @@ static int sdhci_iproc_probe(struct platform_device *pdev) ret = PTR_ERR(pltfm_host->clk); goto err; } + ret = clk_prepare_enable(pltfm_host->clk); + if (ret) { + dev_err(&pdev->dev, "failed to enable host clk\n"); + goto err; + } if (iproc_host->data->pdata->quirks & SDHCI_QUIRK_MISSING_CAPS) { host->caps = iproc_host->data->caps; @@ -215,10 +220,12 @@ static int sdhci_iproc_probe(struct platform_device *pdev) ret = sdhci_add_host(host); if (ret) - goto err; + goto err_clk; return 0; +err_clk: + clk_disable_unprepare(pltfm_host->clk); err: sdhci_pltfm_free(pdev); return ret; -- cgit v0.10.2 From 0314cbd438d7b9c079c4daafbdf09e788df03be8 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Thu, 21 Jan 2016 13:26:28 +0800 Subject: mmc: sunxi: Document host init sequence sunxi_mmc_init_host() originated from Allwinner kernel sources. The magic numbers written to various registers was never documented. Add comments for values found in Allwinner user manuals. Signed-off-by: Chen-Yu Tsai Acked-by: Hans de Goede Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sunxi-mmc.c b/drivers/mmc/host/sunxi-mmc.c index 83de82b..cce5ca5 100644 --- a/drivers/mmc/host/sunxi-mmc.c +++ b/drivers/mmc/host/sunxi-mmc.c @@ -284,16 +284,28 @@ static int sunxi_mmc_init_host(struct mmc_host *mmc) if (sunxi_mmc_reset_host(host)) return -EIO; + /* + * Burst 8 transfers, RX trigger level: 7, TX trigger level: 8 + * + * TODO: sun9i has a larger FIFO and supports higher trigger values + */ mmc_writel(host, REG_FTRGL, 0x20070008); + /* Maximum timeout value */ mmc_writel(host, REG_TMOUT, 0xffffffff); + /* Unmask SDIO interrupt if needed */ mmc_writel(host, REG_IMASK, host->sdio_imask); + /* Clear all pending interrupts */ mmc_writel(host, REG_RINTR, 0xffffffff); + /* Debug register? undocumented */ mmc_writel(host, REG_DBGC, 0xdeb); + /* Enable CEATA support */ mmc_writel(host, REG_FUNS, SDXC_CEATA_ON); + /* Set DMA descriptor list base address */ mmc_writel(host, REG_DLBA, host->sg_dma); rval = mmc_readl(host, REG_GCTRL); rval |= SDXC_INTERRUPT_ENABLE_BIT; + /* Undocumented, but found in Allwinner code */ rval &= ~SDXC_ACCESS_DONE_DIRECT; mmc_writel(host, REG_GCTRL, rval); -- cgit v0.10.2 From 4159215ac9aa020c0815141f1916b33dc226fb42 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Thu, 21 Jan 2016 13:26:29 +0800 Subject: mmc: sunxi: Return error on mmc_regulator_set_ocr() fail in .set_ios op Let .set_ios() fail if mmc_regulator_set_ocr() fails to enable and set a proper voltage for vmmc. Signed-off-by: Chen-Yu Tsai Acked-by: Hans de Goede Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sunxi-mmc.c b/drivers/mmc/host/sunxi-mmc.c index cce5ca5..790f016 100644 --- a/drivers/mmc/host/sunxi-mmc.c +++ b/drivers/mmc/host/sunxi-mmc.c @@ -711,7 +711,10 @@ static void sunxi_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) break; case MMC_POWER_UP: - mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, ios->vdd); + host->ferror = mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, + ios->vdd); + if (host->ferror) + return; host->ferror = sunxi_mmc_init_host(mmc); if (host->ferror) -- cgit v0.10.2 From f771f6e832ce0b5e0d8b30b33c3f1d62f92655de Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Thu, 21 Jan 2016 13:26:31 +0800 Subject: mmc: sunxi: Support vqmmc regulator eMMC chips require 2 power supplies, vmmc for internal logic, and vqmmc for driving output buffers. vqmmc also controls signaling voltage. Most boards we've seen use the same regulator for both, nevertheless the 2 have different usages, and should be set separately. This patch adds support for vqmmc regulator supply, including voltage switching. The MMC core can use this to try different signaling voltages for eMMC. Signed-off-by: Chen-Yu Tsai Acked-by: Hans de Goede Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sunxi-mmc.c b/drivers/mmc/host/sunxi-mmc.c index 790f016..765dfb9 100644 --- a/drivers/mmc/host/sunxi-mmc.c +++ b/drivers/mmc/host/sunxi-mmc.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -256,6 +257,9 @@ struct sunxi_mmc_host { struct mmc_request *mrq; struct mmc_request *manual_stop_mrq; int ferror; + + /* vqmmc */ + bool vqmmc_enabled; }; static int sunxi_mmc_reset_host(struct sunxi_mmc_host *host) @@ -716,6 +720,16 @@ static void sunxi_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) if (host->ferror) return; + if (!IS_ERR(mmc->supply.vqmmc)) { + host->ferror = regulator_enable(mmc->supply.vqmmc); + if (host->ferror) { + dev_err(mmc_dev(mmc), + "failed to enable vqmmc\n"); + return; + } + host->vqmmc_enabled = true; + } + host->ferror = sunxi_mmc_init_host(mmc); if (host->ferror) return; @@ -727,6 +741,9 @@ static void sunxi_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) dev_dbg(mmc_dev(mmc), "power off!\n"); sunxi_mmc_reset_host(host); mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0); + if (!IS_ERR(mmc->supply.vqmmc) && host->vqmmc_enabled) + regulator_disable(mmc->supply.vqmmc); + host->vqmmc_enabled = false; break; } @@ -758,6 +775,19 @@ static void sunxi_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) } } +static int sunxi_mmc_volt_switch(struct mmc_host *mmc, struct mmc_ios *ios) +{ + /* vqmmc regulator is available */ + if (!IS_ERR(mmc->supply.vqmmc)) + return mmc_regulator_set_vqmmc(mmc, ios); + + /* no vqmmc regulator, assume fixed regulator at 3/3.3V */ + if (mmc->ios.signal_voltage == MMC_SIGNAL_VOLTAGE_330) + return 0; + + return -EINVAL; +} + static void sunxi_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable) { struct sunxi_mmc_host *host = mmc_priv(mmc); @@ -909,6 +939,7 @@ static struct mmc_host_ops sunxi_mmc_ops = { .get_ro = mmc_gpio_get_ro, .get_cd = mmc_gpio_get_cd, .enable_sdio_irq = sunxi_mmc_enable_sdio_irq, + .start_signal_voltage_switch = sunxi_mmc_volt_switch, .hw_reset = sunxi_mmc_hw_reset, .card_busy = sunxi_mmc_card_busy, }; -- cgit v0.10.2 From ccf7bfdc360820b4e089d7576eb074280c5ab4a3 Mon Sep 17 00:00:00 2001 From: "Fu, Zhonghui" Date: Fri, 22 Jan 2016 11:32:18 +0800 Subject: mmc: core: enable mmc host device to suspend/resume asynchronously This patch enables mmc hosts to suspend/resume asynchronously. This will improve system suspend/resume speed. After applying this patch and enabling all mmc hosts' child devices to suspend/resume asynchronously on ASUS T100TA, the system suspend-to-idle time is reduced from 1645ms to 1107ms, and the system resume time is reduced from 940ms to 914ms. Signed-off-by: Zhonghui Fu Acked-by: Venu Byravarasu Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index 0aecd5c..1d94607 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -339,6 +339,7 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev) host->class_dev.parent = dev; host->class_dev.class = &mmc_host_class; device_initialize(&host->class_dev); + device_enable_async_suspend(&host->class_dev); if (mmc_gpio_alloc(host)) { put_device(&host->class_dev); -- cgit v0.10.2 From 4e6a2ef9418cc48ecc5664c6549f52ad22330bc1 Mon Sep 17 00:00:00 2001 From: "Fu, Zhonghui" Date: Fri, 22 Jan 2016 12:35:26 +0800 Subject: mmc: sdhci-acpi: enable sdhci-acpi device to suspend/resume asynchronously This patch enables sdhci-acpi devices to suspend/resume asynchronously. This will improve system suspend/resume speed. After enabling the sdhci-acpi devices and all their child devices to suspend/resume asynchronously on ASUS T100TA, the system suspend-to-idle time is reduced from 1645ms to 1089ms, and the system resume time is reduced from 940ms to 908ms. Signed-off-by: Zhonghui Fu Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sdhci-acpi.c b/drivers/mmc/host/sdhci-acpi.c index a5cda92..195ff08 100644 --- a/drivers/mmc/host/sdhci-acpi.c +++ b/drivers/mmc/host/sdhci-acpi.c @@ -418,6 +418,8 @@ static int sdhci_acpi_probe(struct platform_device *pdev) pm_runtime_enable(dev); } + device_enable_async_suspend(dev); + return 0; err_free: -- cgit v0.10.2 From 358399f8caa3683c045bf297878b6401062a7dcb Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 26 Jan 2016 16:26:31 +0100 Subject: mmc: omap_hsmmc: don't print uninitialized variables When DT based probing is used but the DMA request fails, the driver will print uninitialized stack data from the rx_req and tx_req variables, as indicated by this warning: drivers/mmc/host/omap_hsmmc.c: In function 'omap_hsmmc_probe': drivers/mmc/host/omap_hsmmc.c:2162:3: warning: 'rx_req' may be used uninitialized in this function [-Wmaybe-uninitialized] dev_err(mmc_dev(host->mmc), "unable to obtain RX DMA engine channel %u\n", rx_req); This removes the DMA request line number from the warning, which is the easiest solution and won't hurt us any more as we are planning to remove the legacy code path anyway. Signed-off-by: Arnd Bergmann Acked-by: Tony Lindgren Reviewed-by: Peter Ujfalusi Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index f636ef2..f9ac3bb 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -2162,7 +2162,7 @@ static int omap_hsmmc_probe(struct platform_device *pdev) &rx_req, &pdev->dev, "rx"); if (!host->rx_chan) { - dev_err(mmc_dev(host->mmc), "unable to obtain RX DMA engine channel %u\n", rx_req); + dev_err(mmc_dev(host->mmc), "unable to obtain RX DMA engine channel\n"); ret = -ENXIO; goto err_irq; } @@ -2172,7 +2172,7 @@ static int omap_hsmmc_probe(struct platform_device *pdev) &tx_req, &pdev->dev, "tx"); if (!host->tx_chan) { - dev_err(mmc_dev(host->mmc), "unable to obtain TX DMA engine channel %u\n", tx_req); + dev_err(mmc_dev(host->mmc), "unable to obtain TX DMA engine channel\n"); ret = -ENXIO; goto err_irq; } -- cgit v0.10.2 From 4ec96b4cbde8d5714a4477b5a2562c3dd40bc5fa Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Mon, 25 Jan 2016 20:18:12 +0100 Subject: mmc: make MAN_BKOPS_EN message a debug IMO this info is only useful for developers. Most users won't need this information, since there is not much they can do about it. Signed-off-by: Wolfram Sang Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index bf49e44..07a135b 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -501,7 +501,7 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd) card->ext_csd.raw_bkops_status = ext_csd[EXT_CSD_BKOPS_STATUS]; if (!card->ext_csd.man_bkops_en) - pr_info("%s: MAN_BKOPS_EN bit is not set\n", + pr_debug("%s: MAN_BKOPS_EN bit is not set\n", mmc_hostname(card->host)); } -- cgit v0.10.2 From 963b14ffbcdba13a4e4d4ecf9123ec9ac51e18cd Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Mon, 25 Jan 2016 20:19:14 +0100 Subject: mmc: mmcif: don't depend on MMC_BLOCK I don't see a reason why a host driver should depend on the card driver. It also prevents that we can use the mmc_test driver. So, remove it. Signed-off-by: Wolfram Sang Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index 1526b8a..3f907db 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -673,7 +673,7 @@ config MMC_DW_ROCKCHIP config MMC_SH_MMCIF tristate "SuperH Internal MMCIF support" - depends on MMC_BLOCK && HAS_DMA + depends on HAS_DMA depends on SUPERH || ARCH_SHMOBILE || COMPILE_TEST help This selects the MMC Host Interface controller (MMCIF). -- cgit v0.10.2 From 1ac109ddc959f404e18addac24c6ddff6586cf48 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Mon, 25 Jan 2016 20:20:04 +0100 Subject: mmc: mmc_test: mention that '0' runs all tests I had to use the source to determine what I need to write to 'test' so that all tests are run. Let's mention this explicitly in 'testlist'. Signed-off-by: Wolfram Sang Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/card/mmc_test.c b/drivers/mmc/card/mmc_test.c index 7fc9174..c032eef 100644 --- a/drivers/mmc/card/mmc_test.c +++ b/drivers/mmc/card/mmc_test.c @@ -2829,6 +2829,7 @@ static int mtf_testlist_show(struct seq_file *sf, void *data) mutex_lock(&mmc_test_lock); + seq_printf(sf, "0:\tRun all tests\n"); for (i = 0; i < ARRAY_SIZE(mmc_test_cases); i++) seq_printf(sf, "%d:\t%s\n", i+1, mmc_test_cases[i].name); -- cgit v0.10.2 From b17b4ab8ce3894744b487e6c880ecea807ed5f86 Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Wed, 27 Jan 2016 22:25:40 +0000 Subject: mmc: sdhci-iproc: define MMC caps in platform data This patch moves the definition of the MMC capabilities from the probe function into iproc platform data. After that we are able to add support for another platform more easily. Signed-off-by: Stefan Wahren Suggested-by: Stephen Warren Acked-by: Scott Branden Acked-by: Stephen Warren Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sdhci-iproc.c b/drivers/mmc/host/sdhci-iproc.c index 55bc348..cdc6c4a 100644 --- a/drivers/mmc/host/sdhci-iproc.c +++ b/drivers/mmc/host/sdhci-iproc.c @@ -26,6 +26,7 @@ struct sdhci_iproc_data { const struct sdhci_pltfm_data *pdata; u32 caps; u32 caps1; + u32 mmc_caps; }; struct sdhci_iproc_host { @@ -165,6 +166,7 @@ static const struct sdhci_iproc_data iproc_data = { .pdata = &sdhci_iproc_pltfm_data, .caps = 0x05E90000, .caps1 = 0x00000064, + .mmc_caps = MMC_CAP_1_8V_DDR, }; static const struct of_device_id sdhci_iproc_of_match[] = { @@ -199,8 +201,7 @@ static int sdhci_iproc_probe(struct platform_device *pdev) mmc_of_parse(host->mmc); sdhci_get_of_property(pdev); - /* Enable EMMC 1/8V DDR capable */ - host->mmc->caps |= MMC_CAP_1_8V_DDR; + host->mmc->caps |= iproc_host->data->mmc_caps; pltfm_host->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(pltfm_host->clk)) { -- cgit v0.10.2 From 77cb7d3a4d9b790d929d425f623f48f72fd496c1 Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Wed, 27 Jan 2016 22:25:41 +0000 Subject: mmc: sdhci-iproc: add bcm2835 support Scott Branden from Broadcom said that the BCM2835 eMMC IP core is very similar to IPROC and share most of the quirks. So use this driver instead of separate one. The sdhci-iproc contains a better workaround for the clock domain crossing problem which doesn't need any delays. This results in a better write performance. Btw we get the rid of the SDHCI_CAPABILITIES hack in the sdhci_readl function. Suggested-by: Scott Branden Signed-off-by: Stefan Wahren Acked-by: Eric Anholt Acked-by: Scott Branden Acked-by: Stephen Warren Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index 3f907db..e8e0656 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -318,15 +318,15 @@ config MMC_SDHCI_F_SDH30 If unsure, say N. config MMC_SDHCI_IPROC - tristate "SDHCI platform support for the iProc SD/MMC Controller" - depends on ARCH_BCM_IPROC || COMPILE_TEST + tristate "SDHCI support for the BCM2835 & iProc SD/MMC Controller" + depends on ARCH_BCM2835 || ARCH_BCM_IPROC || COMPILE_TEST depends on MMC_SDHCI_PLTFM default ARCH_BCM_IPROC select MMC_SDHCI_IO_ACCESSORS help This selects the iProc SD/MMC controller. - If you have an IPROC platform with SD or MMC devices, + If you have a BCM2835 or IPROC platform with SD or MMC devices, say Y or M here. If unsure, say N. diff --git a/drivers/mmc/host/sdhci-iproc.c b/drivers/mmc/host/sdhci-iproc.c index cdc6c4a..871c92c 100644 --- a/drivers/mmc/host/sdhci-iproc.c +++ b/drivers/mmc/host/sdhci-iproc.c @@ -169,7 +169,22 @@ static const struct sdhci_iproc_data iproc_data = { .mmc_caps = MMC_CAP_1_8V_DDR, }; +static const struct sdhci_pltfm_data sdhci_bcm2835_pltfm_data = { + .quirks = SDHCI_QUIRK_BROKEN_CARD_DETECTION | + SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | + SDHCI_QUIRK_MISSING_CAPS, + .ops = &sdhci_iproc_ops, +}; + +static const struct sdhci_iproc_data bcm2835_data = { + .pdata = &sdhci_bcm2835_pltfm_data, + .caps = SDHCI_CAN_VDD_330, + .caps1 = 0x00000000, + .mmc_caps = 0x00000000, +}; + static const struct of_device_id sdhci_iproc_of_match[] = { + { .compatible = "brcm,bcm2835-sdhci", .data = &bcm2835_data }, { .compatible = "brcm,sdhci-iproc-cygnus", .data = &iproc_data }, { } }; -- cgit v0.10.2 From 07255f2816b6a75e40f43a113a76f37721f03674 Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Wed, 27 Jan 2016 22:25:42 +0000 Subject: mmc: DT: sdhci-iproc: add bcm2835 compatible Since sdhci-iproc can support bcm2835 we need add the compatible string to the binding. Signed-off-by: Stefan Wahren Acked-by: Scott Branden Acked-by: Eric Anholt Acked-by: Rob Herring Acked-by: Scott Branden Acked-by: Stephen Warren Signed-off-by: Ulf Hansson diff --git a/Documentation/devicetree/bindings/mmc/brcm,sdhci-iproc.txt b/Documentation/devicetree/bindings/mmc/brcm,sdhci-iproc.txt index 72cc9cc..be56d2b 100644 --- a/Documentation/devicetree/bindings/mmc/brcm,sdhci-iproc.txt +++ b/Documentation/devicetree/bindings/mmc/brcm,sdhci-iproc.txt @@ -4,7 +4,10 @@ This file documents differences between the core properties described by mmc.txt and the properties that represent the IPROC SDHCI controller. Required properties: -- compatible : Should be "brcm,sdhci-iproc-cygnus". +- compatible : Should be one of the following + "brcm,bcm2835-sdhci" + "brcm,sdhci-iproc-cygnus" + - clocks : The clock feeding the SDHCI controller. Optional properties: -- cgit v0.10.2 From d1a13c5ed3b0c5d75aa413195fbd150adfa93cc8 Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Tue, 26 Jan 2016 18:26:03 +0800 Subject: mmc: sdhci-iproc: use sdhci_pltfm_unregister directly The sdhci_iproc_remove() is jsut a wrapper to sdhci_pltfm_unregister. So use the sdhci_pltfm_unregister() for the .remove hook directly. Signed-off-by: Jisheng Zhang Acked-by: Scott Branden Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sdhci-iproc.c b/drivers/mmc/host/sdhci-iproc.c index 871c92c..1110f73 100644 --- a/drivers/mmc/host/sdhci-iproc.c +++ b/drivers/mmc/host/sdhci-iproc.c @@ -247,11 +247,6 @@ err: return ret; } -static int sdhci_iproc_remove(struct platform_device *pdev) -{ - return sdhci_pltfm_unregister(pdev); -} - static struct platform_driver sdhci_iproc_driver = { .driver = { .name = "sdhci-iproc", @@ -259,7 +254,7 @@ static struct platform_driver sdhci_iproc_driver = { .pm = SDHCI_PLTFM_PMOPS, }, .probe = sdhci_iproc_probe, - .remove = sdhci_iproc_remove, + .remove = sdhci_pltfm_unregister, }; module_platform_driver(sdhci_iproc_driver); -- cgit v0.10.2 From 6067bafe44d7ce0fbbfe7aa3c463630e61d35237 Mon Sep 17 00:00:00 2001 From: Jaehoon Chung Date: Fri, 29 Jan 2016 08:52:57 +0900 Subject: mmc: core: use the defined function to check whether card is removable In linux/mmc/host.h, mmc_card_is_removable() is already defined. There is no reason that it doesn't use. Signed-off-by: Jaehoon Chung Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index f95d41f..9da9b60 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -2532,7 +2532,7 @@ int mmc_detect_card_removed(struct mmc_host *host) if (!card) return 1; - if (host->caps & MMC_CAP_NONREMOVABLE) + if (!mmc_card_is_removable(host)) return 0; ret = mmc_card_removed(card); @@ -2570,7 +2570,7 @@ void mmc_rescan(struct work_struct *work) return; /* If there is a non-removable card registered, only scan once */ - if ((host->caps & MMC_CAP_NONREMOVABLE) && host->rescan_entered) + if (!mmc_card_is_removable(host) && host->rescan_entered) return; host->rescan_entered = 1; @@ -2587,8 +2587,7 @@ void mmc_rescan(struct work_struct *work) * if there is a _removable_ card registered, check whether it is * still present */ - if (host->bus_ops && !host->bus_dead - && !(host->caps & MMC_CAP_NONREMOVABLE)) + if (host->bus_ops && !host->bus_dead && mmc_card_is_removable(host)) host->bus_ops->detect(host); host->detect_change = 0; @@ -2613,7 +2612,7 @@ void mmc_rescan(struct work_struct *work) mmc_bus_put(host); mmc_claim_host(host); - if (!(host->caps & MMC_CAP_NONREMOVABLE) && host->ops->get_cd && + if (mmc_card_is_removable(host) && host->ops->get_cd && host->ops->get_cd(host) == 0) { mmc_power_off(host); mmc_release_host(host); -- cgit v0.10.2 From ed9feec72fc1fa194ebfdb79e14561b35decce63 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Fri, 29 Jan 2016 09:27:50 +0100 Subject: mmc: sanitize 'bus width' in debug output The bus width is sometimes the actual bus width, and sometimes indices to different arrays encoding the bus width. In my debugging case "2" could mean 8-bit as well as 4-bit, which was extremly confusing. Let's use the human-readable actual bus width in all places. Signed-off-by: Wolfram Sang Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 9da9b60..abd3212 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -1033,7 +1033,7 @@ static inline void mmc_set_ios(struct mmc_host *host) "width %u timing %u\n", mmc_hostname(host), ios->clock, ios->bus_mode, ios->power_mode, ios->chip_select, ios->vdd, - ios->bus_width, ios->timing); + 1 << ios->bus_width, ios->timing); host->ops->set_ios(host, ios); } diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 07a135b..4dbe3df 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -945,7 +945,7 @@ static int mmc_select_bus_width(struct mmc_card *card) break; } else { pr_warn("%s: switch to bus width %d failed\n", - mmc_hostname(host), ext_csd_bits[idx]); + mmc_hostname(host), 1 << bus_width); } } -- cgit v0.10.2 From 2dcb305a9ef0f98645dafa6d916936772fde2ad5 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Sat, 30 Jan 2016 01:21:46 +0800 Subject: mmc: sunxi: Support MMC_DDR52 timing modes DDR transfer modes include UHS-1 DDR50 and MMC HS-DDR (or MMC_DDR52). Consider MMC_DDR52 when setting clock delays. Since MMC high speed mode goes up to 52 MHz instead of 50 MHz for SD, and this number is visible in the capability macro, increase the clock rate upper limit to 52 MHz. Signed-off-by: Chen-Yu Tsai Reviewed-by: Hans de Goede Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sunxi-mmc.c b/drivers/mmc/host/sunxi-mmc.c index 765dfb9..fe6c171 100644 --- a/drivers/mmc/host/sunxi-mmc.c +++ b/drivers/mmc/host/sunxi-mmc.c @@ -686,8 +686,9 @@ static int sunxi_mmc_clk_set_rate(struct sunxi_mmc_host *host, } else if (rate <= 25000000) { oclk_dly = host->clk_delays[SDXC_CLK_25M].output; sclk_dly = host->clk_delays[SDXC_CLK_25M].sample; - } else if (rate <= 50000000) { - if (ios->timing == MMC_TIMING_UHS_DDR50) { + } else if (rate <= 52000000) { + if (ios->timing == MMC_TIMING_UHS_DDR50 || + ios->timing == MMC_TIMING_MMC_DDR52) { oclk_dly = host->clk_delays[SDXC_CLK_50M_DDR].output; sclk_dly = host->clk_delays[SDXC_CLK_50M_DDR].sample; } else { @@ -762,7 +763,8 @@ static void sunxi_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) /* set ddr mode */ rval = mmc_readl(host, REG_GCTRL); - if (ios->timing == MMC_TIMING_UHS_DDR50) + if (ios->timing == MMC_TIMING_UHS_DDR50 || + ios->timing == MMC_TIMING_MMC_DDR52) rval |= SDXC_DDR_MODE; else rval &= ~SDXC_DDR_MODE; @@ -1106,9 +1108,9 @@ static int sunxi_mmc_probe(struct platform_device *pdev) mmc->max_segs = PAGE_SIZE / sizeof(struct sunxi_idma_des); mmc->max_seg_size = (1 << host->idma_des_size_bits); mmc->max_req_size = mmc->max_seg_size * mmc->max_segs; - /* 400kHz ~ 50MHz */ + /* 400kHz ~ 52MHz */ mmc->f_min = 400000; - mmc->f_max = 50000000; + mmc->f_max = 52000000; mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED | MMC_CAP_ERASE | MMC_CAP_SDIO_IRQ; -- cgit v0.10.2 From 2a7aa63a27840ca246f81cb466063f2a74001ca1 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Sat, 30 Jan 2016 01:21:47 +0800 Subject: mmc: sunxi: Support 8 bit eMMC DDR transfer modes Allwinner's MMC controller needs to run at double the card clock rate for 8 bit DDR transfer modes. Interestingly, this is not needed for 4 bit DDR transfers. Different clock delays are needed for 8 bit eMMC DDR, due to the increased module clock rate. For the A80 though, the same values for 4 bit and 8 bit are shared. The new values for the other SoCs were from A83T user manual's "new timing mode" default values, which describes them in clock phase, rather than delay periods. These values were used without any modification. They may not be correct, but they work. Signed-off-by: Chen-Yu Tsai Reviewed-by: Hans de Goede Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sunxi-mmc.c b/drivers/mmc/host/sunxi-mmc.c index fe6c171..bb45926 100644 --- a/drivers/mmc/host/sunxi-mmc.c +++ b/drivers/mmc/host/sunxi-mmc.c @@ -215,6 +215,7 @@ #define SDXC_CLK_25M 1 #define SDXC_CLK_50M 2 #define SDXC_CLK_50M_DDR 3 +#define SDXC_CLK_50M_DDR_8BIT 4 struct sunxi_mmc_clk_delay { u32 output; @@ -656,11 +657,17 @@ static int sunxi_mmc_clk_set_rate(struct sunxi_mmc_host *host, struct mmc_ios *ios) { u32 rate, oclk_dly, rval, sclk_dly; + u32 clock = ios->clock; int ret; - rate = clk_round_rate(host->clk_mmc, ios->clock); + /* 8 bit DDR requires a higher module clock */ + if (ios->timing == MMC_TIMING_MMC_DDR52 && + ios->bus_width == MMC_BUS_WIDTH_8) + clock <<= 1; + + rate = clk_round_rate(host->clk_mmc, clock); dev_dbg(mmc_dev(host->mmc), "setting clk to %d, rounded %d\n", - ios->clock, rate); + clock, rate); /* setting clock rate */ ret = clk_set_rate(host->clk_mmc, rate); @@ -677,6 +684,12 @@ static int sunxi_mmc_clk_set_rate(struct sunxi_mmc_host *host, /* clear internal divider */ rval = mmc_readl(host, REG_CLKCR); rval &= ~0xff; + /* set internal divider for 8 bit eMMC DDR, so card clock is right */ + if (ios->timing == MMC_TIMING_MMC_DDR52 && + ios->bus_width == MMC_BUS_WIDTH_8) { + rval |= 1; + rate >>= 1; + } mmc_writel(host, REG_CLKCR, rval); /* determine delays */ @@ -687,13 +700,16 @@ static int sunxi_mmc_clk_set_rate(struct sunxi_mmc_host *host, oclk_dly = host->clk_delays[SDXC_CLK_25M].output; sclk_dly = host->clk_delays[SDXC_CLK_25M].sample; } else if (rate <= 52000000) { - if (ios->timing == MMC_TIMING_UHS_DDR50 || - ios->timing == MMC_TIMING_MMC_DDR52) { - oclk_dly = host->clk_delays[SDXC_CLK_50M_DDR].output; - sclk_dly = host->clk_delays[SDXC_CLK_50M_DDR].sample; - } else { + if (ios->timing != MMC_TIMING_UHS_DDR50 && + ios->timing != MMC_TIMING_MMC_DDR52) { oclk_dly = host->clk_delays[SDXC_CLK_50M].output; sclk_dly = host->clk_delays[SDXC_CLK_50M].sample; + } else if (ios->bus_width == MMC_BUS_WIDTH_8) { + oclk_dly = host->clk_delays[SDXC_CLK_50M_DDR_8BIT].output; + sclk_dly = host->clk_delays[SDXC_CLK_50M_DDR_8BIT].sample; + } else { + oclk_dly = host->clk_delays[SDXC_CLK_50M_DDR].output; + sclk_dly = host->clk_delays[SDXC_CLK_50M_DDR].sample; } } else { return -EINVAL; @@ -951,6 +967,8 @@ static const struct sunxi_mmc_clk_delay sunxi_mmc_clk_delays[] = { [SDXC_CLK_25M] = { .output = 180, .sample = 75 }, [SDXC_CLK_50M] = { .output = 90, .sample = 120 }, [SDXC_CLK_50M_DDR] = { .output = 60, .sample = 120 }, + /* Value from A83T "new timing mode". Works but might not be right. */ + [SDXC_CLK_50M_DDR_8BIT] = { .output = 90, .sample = 180 }, }; static const struct sunxi_mmc_clk_delay sun9i_mmc_clk_delays[] = { @@ -958,6 +976,7 @@ static const struct sunxi_mmc_clk_delay sun9i_mmc_clk_delays[] = { [SDXC_CLK_25M] = { .output = 180, .sample = 75 }, [SDXC_CLK_50M] = { .output = 150, .sample = 120 }, [SDXC_CLK_50M_DDR] = { .output = 90, .sample = 120 }, + [SDXC_CLK_50M_DDR_8BIT] = { .output = 90, .sample = 120 }, }; static int sunxi_mmc_resource_request(struct sunxi_mmc_host *host, -- cgit v0.10.2 From aed26fcafe786294c60e382063168a0bcea85a27 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Sat, 30 Jan 2016 01:21:48 +0800 Subject: mmc: sunxi: Enable eMMC HS-DDR (MMC_CAP_1_8V_DDR) support Now that clock delay settings for 8 bit DDR are correct, and vqmmc support is available, we can enable MMC_CAP_1_8V_DDR support. This enables MMC HS-DDR at up to 52 MHz, even if signal voltage switching is not available. Signed-off-by: Chen-Yu Tsai Reviewed-by: Hans de Goede Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sunxi-mmc.c b/drivers/mmc/host/sunxi-mmc.c index bb45926..2aee17c 100644 --- a/drivers/mmc/host/sunxi-mmc.c +++ b/drivers/mmc/host/sunxi-mmc.c @@ -1131,6 +1131,7 @@ static int sunxi_mmc_probe(struct platform_device *pdev) mmc->f_min = 400000; mmc->f_max = 52000000; mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED | + MMC_CAP_1_8V_DDR | MMC_CAP_ERASE | MMC_CAP_SDIO_IRQ; ret = mmc_of_parse(mmc); -- cgit v0.10.2 From fd551d940f77d4ca2bd408c672698d9bf9a4b7ae Mon Sep 17 00:00:00 2001 From: Jaehoon Chung Date: Mon, 1 Feb 2016 21:07:26 +0900 Subject: mmc: atmel-mci: remove the MMC_DATA_STREAM flag Remove the MMC_DATA_STREAM flag because it isn't used anymore. Signed-off-by: Jaehoon Chung Acked-by: Ludovic Desroches Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c index 851ccd9..7f9d3de 100644 --- a/drivers/mmc/host/atmel-mci.c +++ b/drivers/mmc/host/atmel-mci.c @@ -848,9 +848,7 @@ static u32 atmci_prepare_command(struct mmc_host *mmc, if (cmd->opcode == SD_IO_RW_EXTENDED) { cmdr |= ATMCI_CMDR_SDIO_BLOCK; } else { - if (data->flags & MMC_DATA_STREAM) - cmdr |= ATMCI_CMDR_STREAM; - else if (data->blocks > 1) + if (data->blocks > 1) cmdr |= ATMCI_CMDR_MULTI_BLOCK; else cmdr |= ATMCI_CMDR_BLOCK; @@ -1371,10 +1369,7 @@ static void atmci_start_request(struct atmel_mci *host, host->stop_cmdr |= ATMCI_CMDR_STOP_XFER; if (!(data->flags & MMC_DATA_WRITE)) host->stop_cmdr |= ATMCI_CMDR_TRDIR_READ; - if (data->flags & MMC_DATA_STREAM) - host->stop_cmdr |= ATMCI_CMDR_STREAM; - else - host->stop_cmdr |= ATMCI_CMDR_MULTI_BLOCK; + host->stop_cmdr |= ATMCI_CMDR_MULTI_BLOCK; } /* -- cgit v0.10.2 From c52f76244791d5ce7f960c961520fc10eb2d42fe Mon Sep 17 00:00:00 2001 From: Jaehoon Chung Date: Mon, 1 Feb 2016 21:07:27 +0900 Subject: mmc: bfin_sdh: remove the MMC_DATA_STREAM flag Remove the MMC_DATA_STREAM flag because it isn't used anymore. Signed-off-by: Jaehoon Chung Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/bfin_sdh.c b/drivers/mmc/host/bfin_sdh.c index 2b7f37e..526231e 100644 --- a/drivers/mmc/host/bfin_sdh.c +++ b/drivers/mmc/host/bfin_sdh.c @@ -126,9 +126,6 @@ static int sdh_setup_data(struct sdh_host *host, struct mmc_data *data) length = data->blksz * data->blocks; bfin_write_SDH_DATA_LGTH(length); - if (data->flags & MMC_DATA_STREAM) - data_ctl |= DTX_MODE; - if (data->flags & MMC_DATA_READ) data_ctl |= DTX_DIR; /* Only supports power-of-2 block size */ -- cgit v0.10.2 From bbb66fcbd52510b676a2372c8daa5e3cf44240d6 Mon Sep 17 00:00:00 2001 From: Jaehoon Chung Date: Mon, 1 Feb 2016 21:07:28 +0900 Subject: mmc: davinci_mmc: remove the MMC_DATA_STREAM flag Remove the MMC_DATA_STREAM flag because it isn't used anymore. Signed-off-by: Jaehoon Chung Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/davinci_mmc.c b/drivers/mmc/host/davinci_mmc.c index ea2a2eb..693144e 100644 --- a/drivers/mmc/host/davinci_mmc.c +++ b/drivers/mmc/host/davinci_mmc.c @@ -346,10 +346,6 @@ static void mmc_davinci_start_command(struct mmc_davinci_host *host, if (cmd->data) cmd_reg |= MMCCMD_WDATX; - /* Setting whether stream or block transfer */ - if (cmd->flags & MMC_DATA_STREAM) - cmd_reg |= MMCCMD_STRMTP; - /* Setting whether data read or write */ if (host->data_dir == DAVINCI_MMC_DATADIR_WRITE) cmd_reg |= MMCCMD_DTRW; @@ -568,8 +564,7 @@ mmc_davinci_prepare_data(struct mmc_davinci_host *host, struct mmc_request *req) return; } - dev_dbg(mmc_dev(host->mmc), "%s %s, %d blocks of %d bytes\n", - (data->flags & MMC_DATA_STREAM) ? "stream" : "block", + dev_dbg(mmc_dev(host->mmc), "%s, %d blocks of %d bytes\n", (data->flags & MMC_DATA_WRITE) ? "write" : "read", data->blocks, data->blksz); dev_dbg(mmc_dev(host->mmc), " DTO %d cycles + %d ns\n", @@ -584,22 +579,18 @@ mmc_davinci_prepare_data(struct mmc_davinci_host *host, struct mmc_request *req) writel(data->blksz, host->base + DAVINCI_MMCBLEN); /* Configure the FIFO */ - switch (data->flags & MMC_DATA_WRITE) { - case MMC_DATA_WRITE: + if (data->flags & MMC_DATA_WRITE) { host->data_dir = DAVINCI_MMC_DATADIR_WRITE; writel(fifo_lev | MMCFIFOCTL_FIFODIR_WR | MMCFIFOCTL_FIFORST, host->base + DAVINCI_MMCFIFOCTL); writel(fifo_lev | MMCFIFOCTL_FIFODIR_WR, host->base + DAVINCI_MMCFIFOCTL); - break; - - default: + } else { host->data_dir = DAVINCI_MMC_DATADIR_READ; writel(fifo_lev | MMCFIFOCTL_FIFODIR_RD | MMCFIFOCTL_FIFORST, host->base + DAVINCI_MMCFIFOCTL); writel(fifo_lev | MMCFIFOCTL_FIFODIR_RD, host->base + DAVINCI_MMCFIFOCTL); - break; } host->buffer = NULL; -- cgit v0.10.2 From 538fdf56a7d57f0575e8ba34aab2dba33a73df54 Mon Sep 17 00:00:00 2001 From: Jaehoon Chung Date: Mon, 1 Feb 2016 21:07:29 +0900 Subject: mmc: dw_mmc: remove the MMC_DATA_STREAM flag Remove the MMC_DATA_STREAM flag because it isn't used anymore. Signed-off-by: Jaehoon Chung Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 7128351..40fcf9e 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -290,8 +290,6 @@ static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd) data = cmd->data; if (data) { cmdr |= SDMMC_CMD_DAT_EXP; - if (data->flags & MMC_DATA_STREAM) - cmdr |= SDMMC_CMD_STRM_MODE; if (data->flags & MMC_DATA_WRITE) cmdr |= SDMMC_CMD_DAT_WR; } -- cgit v0.10.2 From 31f1c4425bbc9d77e20562f7502360ba614f8131 Mon Sep 17 00:00:00 2001 From: Jaehoon Chung Date: Mon, 1 Feb 2016 21:07:30 +0900 Subject: mmc: jz4740_mmc: remove the MMC_DATA_STREAM flag Remove the MMC_DATA_STREAM flag because it isn't used anymore. Signed-off-by: Jaehoon Chung Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/jz4740_mmc.c b/drivers/mmc/host/jz4740_mmc.c index 76e8bce..03ddf0e 100644 --- a/drivers/mmc/host/jz4740_mmc.c +++ b/drivers/mmc/host/jz4740_mmc.c @@ -660,8 +660,6 @@ static void jz4740_mmc_send_command(struct jz4740_mmc_host *host, cmdat |= JZ_MMC_CMDAT_DATA_EN; if (cmd->data->flags & MMC_DATA_WRITE) cmdat |= JZ_MMC_CMDAT_WRITE; - if (cmd->data->flags & MMC_DATA_STREAM) - cmdat |= JZ_MMC_CMDAT_STREAM; if (host->use_dma) cmdat |= JZ_MMC_CMDAT_DMA_EN; -- cgit v0.10.2 From a7357754e9b8ac8873c5c27777e4b56f5aad7361 Mon Sep 17 00:00:00 2001 From: Jaehoon Chung Date: Mon, 1 Feb 2016 21:07:31 +0900 Subject: mmc: mxcmmc: remove the MMC_DATA_STREAM flag Remove the MMC_DATA_STREAM flag because it isn't used anymore. Signed-off-by: Jaehoon Chung Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c index d110f9e..3d1ea5e 100644 --- a/drivers/mmc/host/mxcmmc.c +++ b/drivers/mmc/host/mxcmmc.c @@ -307,9 +307,6 @@ static int mxcmci_setup_data(struct mxcmci_host *host, struct mmc_data *data) enum dma_transfer_direction slave_dirn; int i, nents; - if (data->flags & MMC_DATA_STREAM) - nob = 0xffff; - host->data = data; data->bytes_xfered = 0; -- cgit v0.10.2 From 2249f6a06e9ef98e73aaf40a4b0db84a3a5e3b5c Mon Sep 17 00:00:00 2001 From: Jaehoon Chung Date: Mon, 1 Feb 2016 21:07:32 +0900 Subject: mmc: pxamci: remove the MMC_DATA_STREAM flag Remove the MMC_DATA_STREAM flag because it isn't used anymore. Signed-off-by: Jaehoon Chung Acked-by: Robert Jarzmik Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c index da82477..86fac3e 100644 --- a/drivers/mmc/host/pxamci.c +++ b/drivers/mmc/host/pxamci.c @@ -191,9 +191,6 @@ static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data) host->data = data; - if (data->flags & MMC_DATA_STREAM) - nob = 0xffff; - writel(nob, host->base + MMC_NOB); writel(data->blksz, host->base + MMC_BLKLEN); @@ -443,9 +440,6 @@ static void pxamci_request(struct mmc_host *mmc, struct mmc_request *mrq) cmdat |= CMDAT_DATAEN | CMDAT_DMAEN; if (mrq->data->flags & MMC_DATA_WRITE) cmdat |= CMDAT_WRITE; - - if (mrq->data->flags & MMC_DATA_STREAM) - cmdat |= CMDAT_STREAM; } pxamci_start_cmd(host, mrq->cmd, cmdat); -- cgit v0.10.2 From 5a6c15a2a3de64c432a5e55132fd9658092d6442 Mon Sep 17 00:00:00 2001 From: Jaehoon Chung Date: Mon, 1 Feb 2016 21:07:33 +0900 Subject: mmc: s3cmci: remove the MMC_DATA_STREAM flag Remove the MMC_DATA_STREAM flag because it isn't used anymore. Signed-off-by: Jaehoon Chung Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/s3cmci.c b/drivers/mmc/host/s3cmci.c index 6291d50..39814f3 100644 --- a/drivers/mmc/host/s3cmci.c +++ b/drivers/mmc/host/s3cmci.c @@ -1014,8 +1014,7 @@ static int s3cmci_setup_data(struct s3cmci_host *host, struct mmc_data *data) if (host->bus_width == MMC_BUS_WIDTH_4) dcon |= S3C2410_SDIDCON_WIDEBUS; - if (!(data->flags & MMC_DATA_STREAM)) - dcon |= S3C2410_SDIDCON_BLOCKMODE; + dcon |= S3C2410_SDIDCON_BLOCKMODE; if (data->flags & MMC_DATA_WRITE) { dcon |= S3C2410_SDIDCON_TXAFTERRESP; -- cgit v0.10.2 From f2c90c389e361075850ebc67a84f629fb595d24a Mon Sep 17 00:00:00 2001 From: Jaehoon Chung Date: Mon, 1 Feb 2016 21:07:34 +0900 Subject: mmc: sunxi-mmc: remove the MMC_DATA_STREAM flag Remove the MMC_DATA_STREAM flag because it isn't used anymore. Signed-off-by: Jaehoon Chung Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sunxi-mmc.c b/drivers/mmc/host/sunxi-mmc.c index 2aee17c..8372a41 100644 --- a/drivers/mmc/host/sunxi-mmc.c +++ b/drivers/mmc/host/sunxi-mmc.c @@ -878,11 +878,6 @@ static void sunxi_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq) if ((cmd->flags & MMC_CMD_MASK) == MMC_CMD_ADTC) { cmd_val |= SDXC_DATA_EXPIRE | SDXC_WAIT_PRE_OVER; - if (cmd->data->flags & MMC_DATA_STREAM) { - imask |= SDXC_AUTO_COMMAND_DONE; - cmd_val |= SDXC_SEQUENCE_MODE | - SDXC_SEND_AUTO_STOP; - } if (cmd->data->stop) { imask |= SDXC_AUTO_COMMAND_DONE; -- cgit v0.10.2 From d3204ab9951b755d35c540836402ae2668d3158b Mon Sep 17 00:00:00 2001 From: Jaehoon Chung Date: Mon, 1 Feb 2016 21:07:35 +0900 Subject: mmc: core: remove the MMC_DATA_STREAM flag It's not set to MMC_DATA_STREAM anywhere. It seems that it had been used with CMD11/CMD20. But according to Spec, CMD11/CMD20 are obsolete command. Signed-off-by: Jaehoon Chung Signed-off-by: Ulf Hansson diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h index 37967b6..b01e77d 100644 --- a/include/linux/mmc/core.h +++ b/include/linux/mmc/core.h @@ -113,7 +113,6 @@ struct mmc_data { #define MMC_DATA_WRITE (1 << 8) #define MMC_DATA_READ (1 << 9) -#define MMC_DATA_STREAM (1 << 10) unsigned int bytes_xfered; -- cgit v0.10.2 From f53f1102950072e4c2548d1fd01de6aadb2202bd Mon Sep 17 00:00:00 2001 From: Jaehoon Chung Date: Mon, 1 Feb 2016 21:07:36 +0900 Subject: mmc: block: don't use the OR operation for flag of data After removed the MMC_DATA_STREAM, only two flags are remained. (MMC_DATA_READ and MMC_DATA_WRITE) The flags of READ and WRITE can't be used together. That's why it doesn't need to use "OR' operation. Signed-off-by: Jaehoon Chung Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index fe207e5..16d6597 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -1524,13 +1524,13 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq, } if (rq_data_dir(req) == READ) { brq->cmd.opcode = readcmd; - brq->data.flags |= MMC_DATA_READ; + brq->data.flags = MMC_DATA_READ; if (brq->mrq.stop) brq->stop.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC; } else { brq->cmd.opcode = writecmd; - brq->data.flags |= MMC_DATA_WRITE; + brq->data.flags = MMC_DATA_WRITE; if (brq->mrq.stop) brq->stop.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC; @@ -1799,7 +1799,7 @@ static void mmc_blk_packed_hdr_wrq_prep(struct mmc_queue_req *mqrq, brq->data.blksz = 512; brq->data.blocks = packed->blocks + hdr_blocks; - brq->data.flags |= MMC_DATA_WRITE; + brq->data.flags = MMC_DATA_WRITE; brq->stop.opcode = MMC_STOP_TRANSMISSION; brq->stop.arg = 0; -- cgit v0.10.2 From 254d1456560fa42d4ca901c9b9308e87c951fee1 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Fri, 22 Jan 2016 15:51:59 +0100 Subject: mmc: tmio_dma: remove debug messages with little information When compiling the driver with CONFIG_MMC_DEBUG set, I got build warnings. They have been 'fixed' meanwhile. However, because these debug messages look random anyhow (some duplicate information printed etc), let's just drop them and rather re-add something consistent if that should ever be needed. Signed-off-by: Wolfram Sang Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/tmio_mmc_dma.c b/drivers/mmc/host/tmio_mmc_dma.c index 4a0d6b8..6754358 100644 --- a/drivers/mmc/host/tmio_mmc_dma.c +++ b/drivers/mmc/host/tmio_mmc_dma.c @@ -94,10 +94,7 @@ static void tmio_mmc_start_dma_rx(struct tmio_mmc_host *host) desc = NULL; ret = cookie; } - dev_dbg(&host->pdev->dev, "%s(): mapped %d -> %d, cookie %d, rq %p\n", - __func__, host->sg_len, ret, cookie, host->mrq); } - pio: if (!desc) { /* DMA failed, fall back to PIO */ @@ -115,9 +112,6 @@ pio: dev_warn(&host->pdev->dev, "DMA failed: %d, falling back to PIO\n", ret); } - - dev_dbg(&host->pdev->dev, "%s(): desc %p, sg[%d]\n", __func__, - desc, host->sg_len); } static void tmio_mmc_start_dma_tx(struct tmio_mmc_host *host) @@ -174,10 +168,7 @@ static void tmio_mmc_start_dma_tx(struct tmio_mmc_host *host) desc = NULL; ret = cookie; } - dev_dbg(&host->pdev->dev, "%s(): mapped %d -> %d, cookie %d, rq %p\n", - __func__, host->sg_len, ret, cookie, host->mrq); } - pio: if (!desc) { /* DMA failed, fall back to PIO */ @@ -195,8 +186,6 @@ pio: dev_warn(&host->pdev->dev, "DMA failed: %d, falling back to PIO\n", ret); } - - dev_dbg(&host->pdev->dev, "%s(): desc %p\n", __func__, desc); } void tmio_mmc_start_dma(struct tmio_mmc_host *host, -- cgit v0.10.2 From ff741cfde98bd867eb4c9477bc9ba0df3507eed8 Mon Sep 17 00:00:00 2001 From: Shinobu Uehara Date: Fri, 25 Apr 2014 18:14:17 +0900 Subject: mmc: sdhi: Add EXT_ACC register busy check All the docs I have access to say that this register needs the bus busy check. Signed-off-by: Shinobu Uehara Signed-off-by: Ai Kyuse Signed-off-by: Wolfram Sang Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/sh_mobile_sdhi.c index 354f4f3..61671f3 100644 --- a/drivers/mmc/host/sh_mobile_sdhi.c +++ b/drivers/mmc/host/sh_mobile_sdhi.c @@ -163,6 +163,7 @@ static int sh_mobile_sdhi_write16_hook(struct tmio_mmc_host *host, int addr) case CTL_SD_MEM_CARD_OPT: case CTL_TRANSACTION_CTL: case CTL_DMA_ENABLE: + case EXT_ACC: return sh_mobile_sdhi_wait_idle(host); } -- cgit v0.10.2 From 2bf8ab6ba23483a49d29a726d047f3be81ccc952 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 19 Jan 2016 11:42:22 +0100 Subject: mmc: sdhi: error message on ENOMEM is superfluous We will get a full dump anyhow. Signed-off-by: Wolfram Sang Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/sh_mobile_sdhi.c index 61671f3..5a10fb3 100644 --- a/drivers/mmc/host/sh_mobile_sdhi.c +++ b/drivers/mmc/host/sh_mobile_sdhi.c @@ -214,10 +214,8 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev) return -EINVAL; priv = devm_kzalloc(&pdev->dev, sizeof(struct sh_mobile_sdhi), GFP_KERNEL); - if (priv == NULL) { - dev_err(&pdev->dev, "kzalloc failed\n"); + if (!priv) return -ENOMEM; - } mmc_data = &priv->mmc_data; dma_priv = &priv->dma_priv; -- cgit v0.10.2 From 04e24b80a3ddf4cdf85e49a99d33aec27c9432ad Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 19 Jan 2016 12:28:31 +0100 Subject: mmc: tmio: add flag to reduce delay after changing clock status The docs for RCar Gen2 & 3 I have access to, mention delays of 5ms after stop and 1ms after start. Make it possible to apply these values. Signed-off-by: Wolfram Sang Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c index a10fde4..ffff687 100644 --- a/drivers/mmc/host/tmio_mmc_pio.c +++ b/drivers/mmc/host/tmio_mmc_pio.c @@ -172,7 +172,8 @@ static void tmio_mmc_set_clock(struct tmio_mmc_host *host, host->set_clk_div(host->pdev, (clk>>22) & 1); sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, clk & 0x1ff); - msleep(10); + if (!(host->pdata->flags & TMIO_MMC_FAST_CLK_CHG)) + msleep(10); } static void tmio_mmc_clk_stop(struct tmio_mmc_host *host) @@ -185,14 +186,14 @@ static void tmio_mmc_clk_stop(struct tmio_mmc_host *host) sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~0x0100 & sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL)); - msleep(10); + msleep(host->pdata->flags & TMIO_MMC_FAST_CLK_CHG ? 5 : 10); } static void tmio_mmc_clk_start(struct tmio_mmc_host *host) { sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, 0x0100 | sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL)); - msleep(10); + msleep(host->pdata->flags & TMIO_MMC_FAST_CLK_CHG ? 1 : 10); /* implicit BUG_ON(!res) */ if (host->pdata->flags & TMIO_MMC_HAVE_HIGH_REG) { diff --git a/include/linux/mfd/tmio.h b/include/linux/mfd/tmio.h index 24b86d5..05d58ee 100644 --- a/include/linux/mfd/tmio.h +++ b/include/linux/mfd/tmio.h @@ -65,6 +65,10 @@ * Some controllers can support SDIO IRQ signalling. */ #define TMIO_MMC_SDIO_IRQ (1 << 2) + +/* Some controllers don't need to wait 10ms for clock changes */ +#define TMIO_MMC_FAST_CLK_CHG (1 << 3) + /* * Some controllers require waiting for the SD bus to become * idle before writing to some registers. -- cgit v0.10.2 From 6d2bcbe5d1ee44271b30d445b55c49219b33fc6e Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 19 Jan 2016 12:32:58 +0100 Subject: mmc: tmio: remove stale comments These don't make sense anymore. Since commit 5d60e500541ed1 ("mmc: tmio: add new TMIO_MMC_HAVE_HIGH_REG flags"), we don't deal with a resource here. Signed-off-by: Wolfram Sang Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c index ffff687..207e77a 100644 --- a/drivers/mmc/host/tmio_mmc_pio.c +++ b/drivers/mmc/host/tmio_mmc_pio.c @@ -178,7 +178,6 @@ static void tmio_mmc_set_clock(struct tmio_mmc_host *host, static void tmio_mmc_clk_stop(struct tmio_mmc_host *host) { - /* implicit BUG_ON(!res) */ if (host->pdata->flags & TMIO_MMC_HAVE_HIGH_REG) { sd_ctrl_write16(host, CTL_CLK_AND_WAIT_CTL, 0x0000); msleep(10); @@ -195,7 +194,6 @@ static void tmio_mmc_clk_start(struct tmio_mmc_host *host) sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL)); msleep(host->pdata->flags & TMIO_MMC_FAST_CLK_CHG ? 1 : 10); - /* implicit BUG_ON(!res) */ if (host->pdata->flags & TMIO_MMC_HAVE_HIGH_REG) { sd_ctrl_write16(host, CTL_CLK_AND_WAIT_CTL, 0x0100); msleep(10); @@ -206,7 +204,6 @@ static void tmio_mmc_reset(struct tmio_mmc_host *host) { /* FIXME - should we set stop clock reg here */ sd_ctrl_write16(host, CTL_RESET_SD, 0x0000); - /* implicit BUG_ON(!res) */ if (host->pdata->flags & TMIO_MMC_HAVE_HIGH_REG) sd_ctrl_write16(host, CTL_RESET_SDIO, 0x0000); msleep(10); -- cgit v0.10.2 From 16a655248965cd04db3e6616a47231fecbf87839 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 19 Jan 2016 12:36:16 +0100 Subject: mmc: sdhi: use faster clock handling on RCar Gen2 Signed-off-by: Wolfram Sang Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/sh_mobile_sdhi.c index 5a10fb3..557e2b9 100644 --- a/drivers/mmc/host/sh_mobile_sdhi.c +++ b/drivers/mmc/host/sh_mobile_sdhi.c @@ -59,7 +59,7 @@ static const struct sh_mobile_sdhi_of_data of_rcar_gen1_compatible = { static const struct sh_mobile_sdhi_of_data of_rcar_gen2_compatible = { .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_WRPROTECT_DISABLE | - TMIO_MMC_CLK_ACTUAL, + TMIO_MMC_CLK_ACTUAL | TMIO_MMC_FAST_CLK_CHG, .capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ, .dma_buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES, .dma_rx_offset = 0x2000, -- cgit v0.10.2 From bf96208f0539d2009ca0b031da2ed7c430edc3a2 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 19 Jan 2016 12:32:58 +0100 Subject: mmc: tmio: refactor set_clock a little Some of the indentation made the code awful to read. Fix that. Also, introduce defines instead of magic hex values. Note that this includes one change: We mask out know 0xff instead of 0x1ff. But 0x100 has always been the clock enable bit. It doesn't make any sense to set it depending on the clock calculation. Update copyright notices, too. I'll be working on those files some more in the future. Signed-off-by: Wolfram Sang Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c index 207e77a..7f6b5ad 100644 --- a/drivers/mmc/host/tmio_mmc_pio.c +++ b/drivers/mmc/host/tmio_mmc_pio.c @@ -1,6 +1,8 @@ /* * linux/drivers/mmc/host/tmio_mmc_pio.c * + * Copyright (C) 2016 Sang Engineering, Wolfram Sang + * Copyright (C) 2015-16 Renesas Electronics Corporation * Copyright (C) 2011 Guennadi Liakhovetski * Copyright (C) 2007 Ian Molton * Copyright (C) 2004 Ian Molton @@ -159,19 +161,20 @@ static void tmio_mmc_set_clock(struct tmio_mmc_host *host, if (new_clock) { for (clock = host->mmc->f_min, clk = 0x80000080; - new_clock >= (clock<<1); clk >>= 1) + new_clock >= (clock << 1); + clk >>= 1) clock <<= 1; /* 1/1 clock is option */ if ((host->pdata->flags & TMIO_MMC_CLK_ACTUAL) && - ((clk >> 22) & 0x1)) + ((clk >> 22) & 0x1)) clk |= 0xff; } if (host->set_clk_div) - host->set_clk_div(host->pdev, (clk>>22) & 1); + host->set_clk_div(host->pdev, (clk >> 22) & 1); - sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, clk & 0x1ff); + sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, clk & CLK_CTL_DIV_MASK); if (!(host->pdata->flags & TMIO_MMC_FAST_CLK_CHG)) msleep(10); } @@ -183,14 +186,14 @@ static void tmio_mmc_clk_stop(struct tmio_mmc_host *host) msleep(10); } - sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~0x0100 & + sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~CLK_CTL_SCLKEN & sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL)); msleep(host->pdata->flags & TMIO_MMC_FAST_CLK_CHG ? 5 : 10); } static void tmio_mmc_clk_start(struct tmio_mmc_host *host) { - sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, 0x0100 | + sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, CLK_CTL_SCLKEN | sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL)); msleep(host->pdata->flags & TMIO_MMC_FAST_CLK_CHG ? 1 : 10); diff --git a/include/linux/mmc/tmio.h b/include/linux/mmc/tmio.h index 84d9053..5f5cd80 100644 --- a/include/linux/mmc/tmio.h +++ b/include/linux/mmc/tmio.h @@ -1,6 +1,8 @@ /* * include/linux/mmc/tmio.h * + * Copyright (C) 2016 Sang Engineering, Wolfram Sang + * Copyright (C) 2015-16 Renesas Electronics Corporation * Copyright (C) 2007 Ian Molton * Copyright (C) 2004 Ian Molton * @@ -61,6 +63,9 @@ #define TMIO_STAT_CMD_BUSY 0x40000000 #define TMIO_STAT_ILL_ACCESS 0x80000000 +#define CLK_CTL_DIV_MASK 0xff +#define CLK_CTL_SCLKEN BIT(8) + #define TMIO_BBS 512 /* Boot block size */ #endif /* LINUX_MMC_TMIO_H */ -- cgit v0.10.2 From 14d5828f4ebbfbe8e07d4d01eb85a684a9290243 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 19 Jan 2016 12:32:58 +0100 Subject: mmc: tmio: disable clock before changing it Rcar2 & 3 docs state that for going to and coming from the 0xff setting, the clock must first be disabled before the DIV bits are changed. Instead of tracking this, let's just do this unconditionally. Signed-off-by: Wolfram Sang Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c index 7f6b5ad..03f6e74 100644 --- a/drivers/mmc/host/tmio_mmc_pio.c +++ b/drivers/mmc/host/tmio_mmc_pio.c @@ -174,6 +174,8 @@ static void tmio_mmc_set_clock(struct tmio_mmc_host *host, if (host->set_clk_div) host->set_clk_div(host->pdev, (clk >> 22) & 1); + sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~CLK_CTL_SCLKEN & + sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL)); sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, clk & CLK_CTL_DIV_MASK); if (!(host->pdata->flags & TMIO_MMC_FAST_CLK_CHG)) msleep(10); -- cgit v0.10.2 From 10a16a01d8f72e80f4780e40cf3122f4caffa411 Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 29 Jan 2016 09:43:50 +0000 Subject: mmc: core: shut up "voltage-ranges unspecified" pr_info() Each time a driver such as sdhci-esdhc-imx is probed, we get a info printk complaining that the DT voltage-ranges property has not been specified. However, the DT binding specifically says that the voltage-ranges property is optional. That means we should not be complaining that DT hasn't specified this property: by indicating that it's optional, it is valid not to have the property in DT. Silence the warning if the property is missing. Signed-off-by: Russell King Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index abd3212..a6ad78c 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -1214,8 +1214,12 @@ int mmc_of_parse_voltage(struct device_node *np, u32 *mask) voltage_ranges = of_get_property(np, "voltage-ranges", &num_ranges); num_ranges = num_ranges / sizeof(*voltage_ranges) / 2; - if (!voltage_ranges || !num_ranges) { - pr_info("%s: voltage-ranges unspecified\n", np->full_name); + if (!voltage_ranges) { + pr_debug("%s: voltage-ranges unspecified\n", np->full_name); + return -EINVAL; + } + if (!num_ranges) { + pr_err("%s: voltage-ranges empty\n", np->full_name); return -EINVAL; } -- cgit v0.10.2 From cf925747d20b7a932db01c1f0abeaeacd0d0477d Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 29 Jan 2016 09:43:55 +0000 Subject: mmc: core: improve mmc_of_parse_voltage() to return better status Improve mmc_of_parse_voltage()'s return values so that drivers can tell whether a voltage-range specification was present, and whether it has been successfully parsed, or there was an error while parsing. We return a negative errno when parsing fails, zero if no voltage-range specification is present, or one if a voltage-range specification is successfully parsed. No users need modifying as no users check the return value. Signed-off-by: Russell King Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index a6ad78c..319efdc 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -1204,8 +1204,9 @@ EXPORT_SYMBOL(mmc_vddrange_to_ocrmask); * @np: The device node need to be parsed. * @mask: mask of voltages available for MMC/SD/SDIO * - * 1. Return zero on success. - * 2. Return negative errno: voltage-range is invalid. + * Parse the "voltage-ranges" DT property, returning zero if it is not + * found, negative errno if the voltage-range specification is invalid, + * or one if the voltage-range is specified and successfully parsed. */ int mmc_of_parse_voltage(struct device_node *np, u32 *mask) { @@ -1216,7 +1217,7 @@ int mmc_of_parse_voltage(struct device_node *np, u32 *mask) num_ranges = num_ranges / sizeof(*voltage_ranges) / 2; if (!voltage_ranges) { pr_debug("%s: voltage-ranges unspecified\n", np->full_name); - return -EINVAL; + return 0; } if (!num_ranges) { pr_err("%s: voltage-ranges empty\n", np->full_name); @@ -1238,7 +1239,7 @@ int mmc_of_parse_voltage(struct device_node *np, u32 *mask) *mask |= ocr_mask; } - return 0; + return 1; } EXPORT_SYMBOL(mmc_of_parse_voltage); -- cgit v0.10.2 From 09faf61d1c3f70866a2f0864c00df6daaff52012 Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 29 Jan 2016 09:44:00 +0000 Subject: mmc: block: shut up "retrying because a re-tune was needed" message Re-tuning is part of standard requirements for the higher speed SD card protocols, and is not an error when this occurs. When we retry a command due to a retune, we should not print a message to the kernel log. Signed-off-by: Russell King Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index 16d6597..47bc87d 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -1362,8 +1362,8 @@ static int mmc_blk_err_check(struct mmc_card *card, if (brq->data.error) { if (need_retune && !brq->retune_retry_done) { - pr_info("%s: retrying because a re-tune was needed\n", - req->rq_disk->disk_name); + pr_debug("%s: retrying because a re-tune was needed\n", + req->rq_disk->disk_name); brq->retune_retry_done = 1; return MMC_BLK_RETRY; } -- cgit v0.10.2 From 07d97d872359d15f0f50f3bceb8f932be99a2226 Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 29 Jan 2016 09:44:05 +0000 Subject: mmc: core: report tuning command execution failure reason Print the error code when the tuning command fails. This allows the reason for the failure to be reported, which aids debugging. Signed-off-by: Russell King Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 319efdc..41b1e76 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -1079,7 +1079,8 @@ int mmc_execute_tuning(struct mmc_card *card) err = host->ops->execute_tuning(host, opcode); if (err) - pr_err("%s: tuning execution failed\n", mmc_hostname(host)); + pr_err("%s: tuning execution failed: %d\n", + mmc_hostname(host), err); else mmc_retune_enable(host); -- cgit v0.10.2 From aaaaeb7a933471f6413ca44dd36efd57f2fa9429 Mon Sep 17 00:00:00 2001 From: Jaehoon Chung Date: Thu, 21 Jan 2016 11:01:06 +0900 Subject: mmc: dw_mmc: remove the prepare_command hook This patch removes the prepare_command hook from entire dw_mmc driver. Now, almost all SoCs are using by default, except Exynos. It seems that dwmmc controller is using unnecessary hook. To know whether needs to set this bit or not, add the DW_MMC_CARD_NO_USE_HOLD bit. If some SoCs need to disable this in future, just set the DW_MMC_CARD_NO_USE_HOLD bit. set_bit(DW_MMC_CARD_NO_USE_HOLD, &slot->flags), Signed-off-by: Jaehoon Chung Tested-by: Shawn Lin Reviewed-by: Shawn Lin Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/dw_mmc-exynos.c b/drivers/mmc/host/dw_mmc-exynos.c index 3a7e835..8790f2a 100644 --- a/drivers/mmc/host/dw_mmc-exynos.c +++ b/drivers/mmc/host/dw_mmc-exynos.c @@ -145,6 +145,16 @@ static void dw_mci_exynos_set_clksel_timing(struct dw_mci *host, u32 timing) mci_writel(host, CLKSEL64, clksel); else mci_writel(host, CLKSEL, clksel); + + /* + * Exynos4412 and Exynos5250 extends the use of CMD register with the + * use of bit 29 (which is reserved on standard MSHC controllers) for + * optionally bypassing the HOLD register for command and data. The + * 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(clksel)) + set_bit(DW_MMC_CARD_NO_USE_HOLD, &host->cur_slot->flags); } #ifdef CONFIG_PM_SLEEP @@ -202,26 +212,6 @@ static int dw_mci_exynos_resume_noirq(struct device *dev) #define dw_mci_exynos_resume_noirq NULL #endif /* CONFIG_PM_SLEEP */ -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 - * optionally bypassing the HOLD register for command and data. The - * HOLD register should be bypassed in case there is no phase shift - * applied on CMD/DATA that is sent to the card. - */ - 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_config_hs400(struct dw_mci *host, u32 timing) { struct dw_mci_exynos_priv_data *priv = host->priv; @@ -500,7 +490,6 @@ static const struct dw_mci_drv_data exynos_drv_data = { .caps = exynos_dwmmc_caps, .init = dw_mci_exynos_priv_init, .setup_clock = dw_mci_exynos_setup_clock, - .prepare_command = dw_mci_exynos_prepare_command, .set_ios = dw_mci_exynos_set_ios, .parse_dt = dw_mci_exynos_parse_dt, .execute_tuning = dw_mci_exynos_execute_tuning, diff --git a/drivers/mmc/host/dw_mmc-pltfm.c b/drivers/mmc/host/dw_mmc-pltfm.c index 81bdeeb..c0bb0c7 100644 --- a/drivers/mmc/host/dw_mmc-pltfm.c +++ b/drivers/mmc/host/dw_mmc-pltfm.c @@ -26,19 +26,6 @@ #include "dw_mmc.h" #include "dw_mmc-pltfm.h" -static void dw_mci_pltfm_prepare_command(struct dw_mci *host, u32 *cmdr) -{ - *cmdr |= SDMMC_CMD_USE_HOLD_REG; -} - -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) { @@ -94,10 +81,8 @@ EXPORT_SYMBOL_GPL(dw_mci_pltfm_pmops); 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 }, + { .compatible = "altr,socfpga-dw-mshc", }, + { .compatible = "img,pistachio-dw-mshc", }, {}, }; MODULE_DEVICE_TABLE(of, dw_mci_pltfm_match); diff --git a/drivers/mmc/host/dw_mmc-rockchip.c b/drivers/mmc/host/dw_mmc-rockchip.c index d9c92f3..84e50f3 100644 --- a/drivers/mmc/host/dw_mmc-rockchip.c +++ b/drivers/mmc/host/dw_mmc-rockchip.c @@ -26,11 +26,6 @@ struct dw_mci_rockchip_priv_data { int default_sample_phase; }; -static void dw_mci_rockchip_prepare_command(struct dw_mci *host, u32 *cmdr) -{ - *cmdr |= SDMMC_CMD_USE_HOLD_REG; -} - static int dw_mci_rk3288_setup_clock(struct dw_mci *host) { host->bus_hz /= RK3288_CLKGEN_DIV; @@ -240,12 +235,10 @@ static int dw_mci_rockchip_init(struct dw_mci *host) } 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, .execute_tuning = dw_mci_rk3288_execute_tuning, .parse_dt = dw_mci_rk3288_parse_dt, diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 40fcf9e..7d6bd9d 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -234,7 +234,6 @@ static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd) struct mmc_data *data; struct dw_mci_slot *slot = mmc_priv(mmc); struct dw_mci *host = slot->host; - const struct dw_mci_drv_data *drv_data = slot->host->drv_data; u32 cmdr; cmd->error = -EINPROGRESS; @@ -294,8 +293,8 @@ static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd) cmdr |= SDMMC_CMD_DAT_WR; } - if (drv_data && drv_data->prepare_command) - drv_data->prepare_command(slot->host, &cmdr); + if (!test_bit(DW_MMC_CARD_NO_USE_HOLD, &slot->flags)) + cmdr |= SDMMC_CMD_USE_HOLD_REG; return cmdr; } diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h index f695b58..6fc84b6 100644 --- a/drivers/mmc/host/dw_mmc.h +++ b/drivers/mmc/host/dw_mmc.h @@ -265,6 +265,7 @@ struct dw_mci_slot { #define DW_MMC_CARD_PRESENT 0 #define DW_MMC_CARD_NEED_INIT 1 #define DW_MMC_CARD_NO_LOW_PWR 2 +#define DW_MMC_CARD_NO_USE_HOLD 3 int id; int sdio_id; }; @@ -274,7 +275,6 @@ struct dw_mci_slot { * @caps: mmc subsystem specified capabilities of the controller(s). * @init: early implementation specific initialization. * @setup_clock: implementation specific clock configuration. - * @prepare_command: handle CMD register extensions. * @set_ios: handle bus specific extensions. * @parse_dt: parse implementation specific device tree properties. * @execute_tuning: implementation specific tuning procedure. @@ -287,7 +287,6 @@ struct dw_mci_drv_data { unsigned long *caps; int (*init)(struct dw_mci *host); int (*setup_clock)(struct dw_mci *host); - void (*prepare_command)(struct dw_mci *host, u32 *cmdr); void (*set_ios)(struct dw_mci *host, struct mmc_ios *ios); int (*parse_dt)(struct dw_mci *host); int (*execute_tuning)(struct dw_mci_slot *slot, u32 opcode); -- cgit v0.10.2 From 935a665e15dcda3b0b986829f32e2724db1f20fc Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Thu, 14 Jan 2016 09:08:02 +0800 Subject: mmc: dw_mmc: add hw_reset support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch implement hw_reset function for DesignWare MMC controller. By adding this feature, mmc blk can do some basic recovery. Set the following resets: software reset – BMOD[0] for IDMAC only DMA reset - CTRL[2] FIFO reset - CTRL[1] bits Program the CARD_RESET register with a value of 0 for the bit corresponding to the card number; This programming asserts the RST_n signal and resets the card. After a minimum of 1 ?s, de-asserts the RST_n signal and takes the card out of reset. The application can program a new CMD only after a minimum of 200 us This implementation can be easily tested by cutting off->On vmmc while doing data accessing in background to simulate that case. Signed-off-by: Shawn Lin Signed-off-by: Jaehoon Chung Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 7d6bd9d..6ad9ebf 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -1474,6 +1474,34 @@ static int dw_mci_get_cd(struct mmc_host *mmc) return present; } +static void dw_mci_hw_reset(struct mmc_host *mmc) +{ + struct dw_mci_slot *slot = mmc_priv(mmc); + struct dw_mci *host = slot->host; + int reset; + + if (host->use_dma == TRANS_MODE_IDMAC) + dw_mci_idmac_reset(host); + + if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_DMA_RESET | + SDMMC_CTRL_FIFO_RESET)) + return; + + /* + * According to eMMC spec, card reset procedure: + * tRstW >= 1us: RST_n pulse width + * tRSCA >= 200us: RST_n to Command time + * tRSTH >= 1us: RST_n high period + */ + reset = mci_readl(host, RST_N); + reset &= ~(SDMMC_RST_HWACTIVE << slot->id); + mci_writel(host, RST_N, reset); + usleep_range(1, 2); + reset |= SDMMC_RST_HWACTIVE << slot->id; + mci_writel(host, RST_N, reset); + usleep_range(200, 300); +} + static void dw_mci_init_card(struct mmc_host *mmc, struct mmc_card *card) { struct dw_mci_slot *slot = mmc_priv(mmc); @@ -1560,6 +1588,7 @@ static const struct mmc_host_ops dw_mci_ops = { .set_ios = dw_mci_set_ios, .get_ro = dw_mci_get_ro, .get_cd = dw_mci_get_cd, + .hw_reset = dw_mci_hw_reset, .enable_sdio_irq = dw_mci_enable_sdio_irq, .execute_tuning = dw_mci_execute_tuning, .card_busy = dw_mci_card_busy, diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h index 6fc84b6..68d5da2 100644 --- a/drivers/mmc/host/dw_mmc.h +++ b/drivers/mmc/host/dw_mmc.h @@ -46,6 +46,7 @@ #define SDMMC_VERID 0x06c #define SDMMC_HCON 0x070 #define SDMMC_UHS_REG 0x074 +#define SDMMC_RST_N 0x078 #define SDMMC_BMOD 0x080 #define SDMMC_PLDMND 0x084 #define SDMMC_DBADDR 0x088 @@ -169,6 +170,8 @@ #define SDMMC_IDMAC_ENABLE BIT(7) #define SDMMC_IDMAC_FB BIT(1) #define SDMMC_IDMAC_SWRESET BIT(0) +/* H/W reset */ +#define SDMMC_RST_HWACTIVE 0x1 /* Version ID register define */ #define SDMMC_GET_VERID(x) ((x) & 0xFFFF) /* Card read threshold */ -- cgit v0.10.2 From 13c3d4740216c4931fce1e764b9a76dd55c2da23 Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Thu, 21 Jan 2016 16:06:14 +0800 Subject: mmc: dw_mmc: remove struct block_settings This patch removes struct block_settings since it's never used anywhere. Signed-off-by: Shawn Lin Signed-off-by: Jaehoon Chung Signed-off-by: Ulf Hansson diff --git a/include/linux/mmc/dw_mmc.h b/include/linux/mmc/dw_mmc.h index 89df7ab..e1f90b8 100644 --- a/include/linux/mmc/dw_mmc.h +++ b/include/linux/mmc/dw_mmc.h @@ -242,14 +242,6 @@ struct dw_mci_dma_ops { struct dma_pdata; -struct block_settings { - unsigned short max_segs; /* see blk_queue_max_segments */ - unsigned int max_blk_size; /* maximum size of one mmc block */ - unsigned int max_blk_count; /* maximum number of blocks in one req*/ - unsigned int max_req_size; /* maximum number of bytes in one req*/ - unsigned int max_seg_size; /* see blk_queue_max_segment_size */ -}; - /* Board platform data */ struct dw_mci_board { u32 num_slots; -- cgit v0.10.2 From e8cc37b8fc3a94d17a2689cd77a7744d70477c14 Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Thu, 21 Jan 2016 14:52:52 +0800 Subject: mmc: dw_mmc: remove DW_MCI_QUIRK_BROKEN_CARD_DETECTION quirk dw_mmc already use mmc_of_parse to get "broken-cd" property, but it considered "broken-cd" to be a quirk in its driver. We don't need this quirk here, and just take what we need from mmc->caps. Signed-off-by: Shawn Lin Tested-by: Jaehoon Chung Signed-off-by: Jaehoon Chung Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 6ad9ebf..8cb8c1c 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -1447,12 +1447,11 @@ static int dw_mci_get_cd(struct mmc_host *mmc) { int present; struct dw_mci_slot *slot = mmc_priv(mmc); - struct dw_mci_board *brd = slot->host->pdata; struct dw_mci *host = slot->host; int gpio_cd = mmc_gpio_get_cd(mmc); /* Use platform get_cd function, else try onboard card detect */ - if ((brd->quirks & DW_MCI_QUIRK_BROKEN_CARD_DETECTION) || + if ((mmc->caps & MMC_CAP_NEEDS_POLL) || (mmc->caps & MMC_CAP_NONREMOVABLE)) present = 1; else if (!IS_ERR_VALUE(gpio_cd)) @@ -2866,23 +2865,13 @@ static void dw_mci_dto_timer(unsigned long arg) } #ifdef CONFIG_OF -static struct dw_mci_of_quirks { - char *quirk; - int id; -} of_quirks[] = { - { - .quirk = "broken-cd", - .id = DW_MCI_QUIRK_BROKEN_CARD_DETECTION, - }, -}; - static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host) { struct dw_mci_board *pdata; struct device *dev = host->dev; struct device_node *np = dev->of_node; const struct dw_mci_drv_data *drv_data = host->drv_data; - int idx, ret; + int ret; u32 clock_frequency; pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); @@ -2897,11 +2886,6 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host) pdata->num_slots = 1; } - /* get quirks */ - for (idx = 0; idx < ARRAY_SIZE(of_quirks); idx++) - if (of_get_property(np, of_quirks[idx].quirk, NULL)) - pdata->quirks |= of_quirks[idx].id; - if (of_property_read_u32(np, "fifo-depth", &pdata->fifo_depth)) dev_info(dev, "fifo-depth property not found, using value of FIFOTH register as default\n"); @@ -2934,18 +2918,19 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host) static void dw_mci_enable_cd(struct dw_mci *host) { - struct dw_mci_board *brd = host->pdata; unsigned long irqflags; u32 temp; int i; + struct dw_mci_slot *slot; - /* No need for CD if broken card detection */ - if (brd->quirks & DW_MCI_QUIRK_BROKEN_CARD_DETECTION) - return; - - /* No need for CD if all slots have a non-error GPIO */ + /* + * No need for CD if all slots have a non-error GPIO + * as well as broken card detection is found. + */ for (i = 0; i < host->num_slots; i++) { - struct dw_mci_slot *slot = host->slot[i]; + slot = host->slot[i]; + if (slot->mmc->caps & MMC_CAP_NEEDS_POLL) + return; if (IS_ERR_VALUE(mmc_gpio_get_cd(slot->mmc))) break; diff --git a/include/linux/mmc/dw_mmc.h b/include/linux/mmc/dw_mmc.h index e1f90b8..7b41c6d 100644 --- a/include/linux/mmc/dw_mmc.h +++ b/include/linux/mmc/dw_mmc.h @@ -235,10 +235,8 @@ struct dw_mci_dma_ops { }; /* IP Quirks/flags. */ -/* Unreliable card detection */ -#define DW_MCI_QUIRK_BROKEN_CARD_DETECTION BIT(0) /* Timer for broken data transfer over scheme */ -#define DW_MCI_QUIRK_BROKEN_DTO BIT(1) +#define DW_MCI_QUIRK_BROKEN_DTO BIT(0) struct dma_pdata; -- cgit v0.10.2 From 3744415cc4bc732dde6491295ec628a7e3b33754 Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Fri, 22 Jan 2016 15:43:12 +0800 Subject: mmc: dw_mmc: fix err handle of dw_mci_probe This patch add correct err handle if dw_mci_ctrl_reset failed while probing. Signed-off-by: Shawn Lin Signed-off-by: Jaehoon Chung Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 8cb8c1c..341e0f0 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -3063,8 +3063,10 @@ int dw_mci_probe(struct dw_mci *host) } /* Reset all blocks */ - if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_ALL_RESET_FLAGS)) - return -ENODEV; + if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_ALL_RESET_FLAGS)) { + ret = -ENODEV; + goto err_clk_ciu; + } host->dma_ops = host->pdata->dma_ops; dw_mci_init_dma(host); -- cgit v0.10.2 From 345efee3541f5931fbbd0f0bcebe9baa3ff2f5c2 Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Tue, 26 Jan 2016 08:43:36 +0800 Subject: mmc: dw_mmc: remove repetitive clear interrupt dw_mci_probe clear interrupts and disable all interrupts firstly. While it clear interrupt again before enable some interrupts. We can't see any reason to clear it twice here, so remove the second one. Signed-off-by: Shawn Lin Signed-off-by: Jaehoon Chung Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 341e0f0..0394ea8 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -3130,7 +3130,6 @@ int dw_mci_probe(struct dw_mci *host) * Enable interrupts for command done, data over, data empty, * receive ready and error such as transmit, receive timeout, crc error */ - mci_writel(host, RINTSTS, 0xFFFFFFFF); mci_writel(host, INTMASK, SDMMC_INT_CMD_DONE | SDMMC_INT_DATA_OVER | SDMMC_INT_TXDR | SDMMC_INT_RXDR | DW_MCI_ERROR_FLAGS); -- cgit v0.10.2 From 8a629d26f02351539dd1760c75656065b881cd9a Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Tue, 2 Feb 2016 14:11:25 +0800 Subject: mmc: dw_mmc: fix num_slots setting This patch make num_slots to 1 if pdata->num_slot is not defined. Meanwhile, we need to make sure num_slots should not larger that the supported slots Signed-off-by: Shawn Lin Signed-off-by: Jaehoon Chung Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 0394ea8..242f9a0 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -2879,12 +2879,7 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host) return ERR_PTR(-ENOMEM); /* find out number of slots supported */ - if (of_property_read_u32(dev->of_node, "num-slots", - &pdata->num_slots)) { - dev_info(dev, - "num-slots property not found, assuming 1 slot is available\n"); - pdata->num_slots = 1; - } + of_property_read_u32(np, "num-slots", &pdata->num_slots); if (of_property_read_u32(np, "fifo-depth", &pdata->fifo_depth)) dev_info(dev, @@ -2960,12 +2955,6 @@ int dw_mci_probe(struct dw_mci *host) } } - if (host->pdata->num_slots < 1) { - dev_err(host->dev, - "Platform data must supply num_slots.\n"); - return -ENODEV; - } - host->biu_clk = devm_clk_get(host->dev, "biu"); if (IS_ERR(host->biu_clk)) { dev_dbg(host->dev, "biu clock not available\n"); @@ -3124,7 +3113,15 @@ int dw_mci_probe(struct dw_mci *host) if (host->pdata->num_slots) host->num_slots = host->pdata->num_slots; else - host->num_slots = SDMMC_GET_SLOT_NUM(mci_readl(host, HCON)); + host->num_slots = 1; + + if (host->num_slots < 1 || + host->num_slots > SDMMC_GET_SLOT_NUM(mci_readl(host, HCON))) { + dev_err(host->dev, + "Platform data must supply correct num_slots.\n"); + ret = -ENODEV; + goto err_clk_ciu; + } /* * Enable interrupts for command done, data over, data empty, -- cgit v0.10.2 From d3ebd68d4d9edfbf169976edbd286436a9fc8ca8 Mon Sep 17 00:00:00 2001 From: Andrei Pistirica Date: Thu, 14 Jan 2016 02:15:44 +0100 Subject: dt/bindings: mmc: Add bindings for PIC32 SDHCI host controller Document the devicetree bindings for the SDHCI peripheral found on Microchip PIC32 class devices. Signed-off-by: Andrei Pistirica Signed-off-by: Joshua Henderson Cc: Ralf Baechle Acked-by: Rob Herring Signed-off-by: Ulf Hansson Acked-by: Adrian Hunter diff --git a/Documentation/devicetree/bindings/mmc/microchip,sdhci-pic32.txt b/Documentation/devicetree/bindings/mmc/microchip,sdhci-pic32.txt new file mode 100644 index 0000000..71ad57e --- /dev/null +++ b/Documentation/devicetree/bindings/mmc/microchip,sdhci-pic32.txt @@ -0,0 +1,29 @@ +* Microchip PIC32 SDHCI Controller + +This file documents differences between the core properties in mmc.txt +and the properties used by the sdhci-pic32 driver. + +Required properties: +- compatible: Should be "microchip,pic32mzda-sdhci" +- interrupts: Should contain interrupt +- clock-names: Should be "base_clk", "sys_clk". + See: Documentation/devicetree/bindings/resource-names.txt +- clocks: Phandle to the clock. + See: Documentation/devicetree/bindings/clock/clock-bindings.txt +- pinctrl-names: A pinctrl state names "default" must be defined. +- pinctrl-0: Phandle referencing pin configuration of the SDHCI controller. + See: Documentation/devicetree/bindings/pinctrl/pinctrl-binding.txt + +Example: + + sdhci@1f8ec000 { + compatible = "microchip,pic32mzda-sdhci"; + reg = <0x1f8ec000 0x100>; + interrupts = <191 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&REFCLKO4>, <&PBCLK5>; + clock-names = "base_clk", "sys_clk"; + bus-width = <4>; + cap-sd-highspeed; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_sdhc1>; + }; -- cgit v0.10.2 From 5d9460d74ce5c1f5f92d016c6a9be8336ef3f350 Mon Sep 17 00:00:00 2001 From: Andrei Pistirica Date: Wed, 13 Jan 2016 18:15:45 -0700 Subject: mmc: sdhci-pic32: Add PIC32 SDHCI host controller driver This driver supports the SDHCI host controller found on a PIC32. Signed-off-by: Andrei Pistirica Signed-off-by: Joshua Henderson Cc: Ralf Baechle Signed-off-by: Ulf Hansson Acked-by: Adrian Hunter diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index e8e0656..4a35ebf 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -786,3 +786,14 @@ config MMC_MTK If you have a machine with a integrated SD/MMC card reader, say Y or M here. This is needed if support for any SD/SDIO/MMC devices is required. If unsure, say N. + +config MMC_SDHCI_MICROCHIP_PIC32 + tristate "Microchip PIC32MZDA SDHCI support" + depends on MMC_SDHCI && PIC32MZDA && MMC_SDHCI_PLTFM + help + This selects the Secure Digital Host Controller Interface (SDHCI) + for PIC32MZDA platform. + + If you have a controller with this interface, say Y or M here. + + If unsure, say N. diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile index 3595f83..af918d2 100644 --- a/drivers/mmc/host/Makefile +++ b/drivers/mmc/host/Makefile @@ -75,6 +75,7 @@ obj-$(CONFIG_MMC_SDHCI_BCM2835) += sdhci-bcm2835.o obj-$(CONFIG_MMC_SDHCI_IPROC) += sdhci-iproc.o obj-$(CONFIG_MMC_SDHCI_MSM) += sdhci-msm.o obj-$(CONFIG_MMC_SDHCI_ST) += sdhci-st.o +obj-$(CONFIG_MMC_SDHCI_MICROCHIP_PIC32) += sdhci-pic32.o ifeq ($(CONFIG_CB710_DEBUG),y) CFLAGS-cb710-mmc += -DDEBUG diff --git a/drivers/mmc/host/sdhci-pic32.c b/drivers/mmc/host/sdhci-pic32.c new file mode 100644 index 0000000..059df70 --- /dev/null +++ b/drivers/mmc/host/sdhci-pic32.c @@ -0,0 +1,257 @@ +/* + * Support of SDHCI platform devices for Microchip PIC32. + * + * Copyright (C) 2015 Microchip + * Andrei Pistirica, Paul Thacker + * + * Inspired by sdhci-pltfm.c + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "sdhci.h" +#include "sdhci-pltfm.h" +#include + +#define SDH_SHARED_BUS_CTRL 0x000000E0 +#define SDH_SHARED_BUS_NR_CLK_PINS_MASK 0x7 +#define SDH_SHARED_BUS_NR_IRQ_PINS_MASK 0x30 +#define SDH_SHARED_BUS_CLK_PINS 0x10 +#define SDH_SHARED_BUS_IRQ_PINS 0x14 +#define SDH_CAPS_SDH_SLOT_TYPE_MASK 0xC0000000 +#define SDH_SLOT_TYPE_REMOVABLE 0x0 +#define SDH_SLOT_TYPE_EMBEDDED 0x1 +#define SDH_SLOT_TYPE_SHARED_BUS 0x2 +#define SDHCI_CTRL_CDSSEL 0x80 +#define SDHCI_CTRL_CDTLVL 0x40 + +#define ADMA_FIFO_RD_THSHLD 512 +#define ADMA_FIFO_WR_THSHLD 512 + +struct pic32_sdhci_priv { + struct platform_device *pdev; + struct clk *sys_clk; + struct clk *base_clk; +}; + +static unsigned int pic32_sdhci_get_max_clock(struct sdhci_host *host) +{ + struct pic32_sdhci_priv *sdhci_pdata = sdhci_priv(host); + + return clk_get_rate(sdhci_pdata->base_clk); +} + +static void pic32_sdhci_set_bus_width(struct sdhci_host *host, int width) +{ + u8 ctrl; + + ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); + if (width == MMC_BUS_WIDTH_8) { + ctrl &= ~SDHCI_CTRL_4BITBUS; + if (host->version >= SDHCI_SPEC_300) + ctrl |= SDHCI_CTRL_8BITBUS; + } else { + if (host->version >= SDHCI_SPEC_300) + ctrl &= ~SDHCI_CTRL_8BITBUS; + if (width == MMC_BUS_WIDTH_4) + ctrl |= SDHCI_CTRL_4BITBUS; + else + ctrl &= ~SDHCI_CTRL_4BITBUS; + } + + /* CD select and test bits must be set for errata workaround. */ + ctrl &= ~SDHCI_CTRL_CDTLVL; + ctrl |= SDHCI_CTRL_CDSSEL; + sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); +} + +static unsigned int pic32_sdhci_get_ro(struct sdhci_host *host) +{ + /* + * The SDHCI_WRITE_PROTECT bit is unstable on current hardware so we + * can't depend on its value in any way. + */ + return 0; +} + +static const struct sdhci_ops pic32_sdhci_ops = { + .get_max_clock = pic32_sdhci_get_max_clock, + .set_clock = sdhci_set_clock, + .set_bus_width = pic32_sdhci_set_bus_width, + .reset = sdhci_reset, + .set_uhs_signaling = sdhci_set_uhs_signaling, + .get_ro = pic32_sdhci_get_ro, +}; + +static struct sdhci_pltfm_data sdhci_pic32_pdata = { + .ops = &pic32_sdhci_ops, + .quirks = SDHCI_QUIRK_NO_HISPD_BIT, + .quirks2 = SDHCI_QUIRK2_NO_1_8_V, +}; + +static void pic32_sdhci_shared_bus(struct platform_device *pdev) +{ + struct sdhci_host *host = platform_get_drvdata(pdev); + u32 bus = readl(host->ioaddr + SDH_SHARED_BUS_CTRL); + u32 clk_pins = (bus & SDH_SHARED_BUS_NR_CLK_PINS_MASK) >> 0; + u32 irq_pins = (bus & SDH_SHARED_BUS_NR_IRQ_PINS_MASK) >> 4; + + /* select first clock */ + if (clk_pins & 1) + bus |= (1 << SDH_SHARED_BUS_CLK_PINS); + + /* select first interrupt */ + if (irq_pins & 1) + bus |= (1 << SDH_SHARED_BUS_IRQ_PINS); + + writel(bus, host->ioaddr + SDH_SHARED_BUS_CTRL); +} + +static int pic32_sdhci_probe_platform(struct platform_device *pdev, + struct pic32_sdhci_priv *pdata) +{ + int ret = 0; + u32 caps_slot_type; + struct sdhci_host *host = platform_get_drvdata(pdev); + + /* Check card slot connected on shared bus. */ + host->caps = readl(host->ioaddr + SDHCI_CAPABILITIES); + caps_slot_type = (host->caps & SDH_CAPS_SDH_SLOT_TYPE_MASK) >> 30; + if (caps_slot_type == SDH_SLOT_TYPE_SHARED_BUS) + pic32_sdhci_shared_bus(pdev); + + return ret; +} + +static int pic32_sdhci_probe(struct platform_device *pdev) +{ + struct sdhci_host *host; + struct sdhci_pltfm_host *pltfm_host; + struct pic32_sdhci_priv *sdhci_pdata; + struct pic32_sdhci_platform_data *plat_data; + int ret; + + host = sdhci_pltfm_init(pdev, &sdhci_pic32_pdata, + sizeof(struct pic32_sdhci_priv)); + if (IS_ERR(host)) { + ret = PTR_ERR(host); + goto err; + } + + pltfm_host = sdhci_priv(host); + sdhci_pdata = sdhci_pltfm_priv(pltfm_host); + + plat_data = pdev->dev.platform_data; + if (plat_data && plat_data->setup_dma) { + ret = plat_data->setup_dma(ADMA_FIFO_RD_THSHLD, + ADMA_FIFO_WR_THSHLD); + if (ret) + goto err_host; + } + + sdhci_pdata->sys_clk = devm_clk_get(&pdev->dev, "sys_clk"); + if (IS_ERR(sdhci_pdata->sys_clk)) { + ret = PTR_ERR(sdhci_pdata->sys_clk); + dev_err(&pdev->dev, "Error getting clock\n"); + goto err_host; + } + + ret = clk_prepare_enable(sdhci_pdata->sys_clk); + if (ret) { + dev_err(&pdev->dev, "Error enabling clock\n"); + goto err_host; + } + + sdhci_pdata->base_clk = devm_clk_get(&pdev->dev, "base_clk"); + if (IS_ERR(sdhci_pdata->base_clk)) { + ret = PTR_ERR(sdhci_pdata->base_clk); + dev_err(&pdev->dev, "Error getting clock\n"); + goto err_sys_clk; + } + + ret = clk_prepare_enable(sdhci_pdata->base_clk); + if (ret) { + dev_err(&pdev->dev, "Error enabling clock\n"); + goto err_base_clk; + } + + ret = mmc_of_parse(host->mmc); + if (ret) + goto err_base_clk; + + ret = pic32_sdhci_probe_platform(pdev, sdhci_pdata); + if (ret) { + dev_err(&pdev->dev, "failed to probe platform!\n"); + goto err_base_clk; + } + + ret = sdhci_add_host(host); + if (ret) { + dev_err(&pdev->dev, "error adding host\n"); + goto err_base_clk; + } + + dev_info(&pdev->dev, "Successfully added sdhci host\n"); + return 0; + +err_base_clk: + clk_disable_unprepare(sdhci_pdata->base_clk); +err_sys_clk: + clk_disable_unprepare(sdhci_pdata->sys_clk); +err_host: + sdhci_pltfm_free(pdev); +err: + dev_err(&pdev->dev, "pic32-sdhci probe failed: %d\n", ret); + return ret; +} + +static int pic32_sdhci_remove(struct platform_device *pdev) +{ + struct sdhci_host *host = platform_get_drvdata(pdev); + struct pic32_sdhci_priv *sdhci_pdata = sdhci_priv(host); + u32 scratch; + + scratch = readl(host->ioaddr + SDHCI_INT_STATUS); + sdhci_remove_host(host, scratch == (u32)~0); + clk_disable_unprepare(sdhci_pdata->base_clk); + clk_disable_unprepare(sdhci_pdata->sys_clk); + sdhci_pltfm_free(pdev); + + return 0; +} + +static const struct of_device_id pic32_sdhci_id_table[] = { + { .compatible = "microchip,pic32mzda-sdhci" }, + {} +}; +MODULE_DEVICE_TABLE(of, pic32_sdhci_id_table); + +static struct platform_driver pic32_sdhci_driver = { + .driver = { + .name = "pic32-sdhci", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(pic32_sdhci_id_table), + }, + .probe = pic32_sdhci_probe, + .remove = pic32_sdhci_remove, +}; + +module_platform_driver(pic32_sdhci_driver); + +MODULE_DESCRIPTION("Microchip PIC32 SDHCI driver"); +MODULE_AUTHOR("Pistirica Sorin Andrei & Sandeep Sheriker"); +MODULE_LICENSE("GPL v2"); -- cgit v0.10.2 From 5eaa7476f93768e5c64449ba1268ba5b6a2c12e1 Mon Sep 17 00:00:00 2001 From: Al Cooper Date: Wed, 10 Feb 2016 15:25:39 -0500 Subject: mmc: sdhci: Allow CAPS check for SDHCI_CAN_64BIT to use overridden caps sdhci_add_host() allows the Host Controller Capability registers to be supplied by the calling driver by using SDHCI_QUIRK_MISSING_CAPS, but the check for the Capabilities bit SDHCI_CAN_64BIT doesn't use the applied value and instead reads the Host register directly. This change uses the supplied "caps" register instead of reading the host register. This change will allow a calling driver to simply clear the SDHCI_CAN_64BIT bit in "caps" to handle some cases of SDHCI_QUIRK2_BROKEN_64_BIT_DMA. Signed-off-by: Al Cooper Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index add9fdf..fd91399 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -2928,7 +2928,7 @@ int sdhci_add_host(struct sdhci_host *host) * SDHCI_QUIRK2_BROKEN_64_BIT_DMA must be left to the drivers to * implement. */ - if (sdhci_readl(host, SDHCI_CAPABILITIES) & SDHCI_CAN_64BIT) + if (caps[0] & SDHCI_CAN_64BIT) host->flags |= SDHCI_USE_64_BIT_DMA; if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) { -- cgit v0.10.2 From ddfe954d364674ea9a492506e6ec6596b9f49b62 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Thu, 11 Feb 2016 15:14:59 +0100 Subject: MAINTAINERS: mmc: Add Adrian Hunter as the maintainer for SDHCI up the maintainer role for SDHCI. I am very pleased that Adrian Hunter volunteered and accepted the challenge! The SDHCI code is currently in quite poor quality, but we have agreed on a way forward to try to reach a point where the SDHCI core becomes more of a set of library functions. Each SDHCI driver variant can then decide which functions to use and allows it to implement variant specific code, without needing to also change SDHCI core code. In the end we aim to get better optimized and maintainable code. Signed-off-by: Ulf Hansson Acked-by: Adrian Hunter diff --git a/MAINTAINERS b/MAINTAINERS index da3e4d8..95ec961 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9702,10 +9702,12 @@ S: Maintained F: drivers/mmc/host/sdricoh_cs.c SECURE DIGITAL HOST CONTROLLER INTERFACE (SDHCI) DRIVER +M: Adrian Hunter L: linux-mmc@vger.kernel.org -S: Orphan -F: drivers/mmc/host/sdhci.* -F: drivers/mmc/host/sdhci-pltfm.[ch] +T: git git://git.infradead.org/users/ahunter/linux-sdhci.git +S: Maintained +F: drivers/mmc/host/sdhci* +F: include/linux/mmc/sdhci* SECURE COMPUTING M: Kees Cook -- cgit v0.10.2 From 96776200898cf9c1965b9f8b9a128e94bb6dce18 Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 26 Jan 2016 13:39:34 +0000 Subject: mmc: sdhci: move initialisation of command error member When a command is started, logically it has no error. Initialise the command's error member to zero whenever we start a command. Signed-off-by: Russell King Signed-off-by: Adrian Hunter [ Goes with "mmc: sdhci: fix command response CRC error handling" ] Cc: stable@vger.kernel.org # v4.5+ Tested-by: Gregory CLEMENT Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index fd91399..43d8717 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -1003,6 +1003,9 @@ void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd) WARN_ON(host->cmd); + /* Initially, a command has no error */ + cmd->error = 0; + /* Wait max 10 ms */ timeout = 10; @@ -1097,8 +1100,6 @@ static void sdhci_finish_command(struct sdhci_host *host) } } - host->cmd->error = 0; - /* Finished CMD23, now send actual command. */ if (host->cmd == host->mrq->sbc) { host->cmd = NULL; -- cgit v0.10.2 From ec014cbacf6229c583cb832726ca39be1ae3d8c3 Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 26 Jan 2016 13:39:39 +0000 Subject: mmc: sdhci: clean up command error handling Avoid multiple tests while handling a command error; simplify the code. Signed-off-by: Russell King Signed-off-by: Adrian Hunter [ Goes with "mmc: sdhci: fix command response CRC error handling" ] Cc: stable@vger.kernel.org # v4.5+ Tested-by: Gregory CLEMENT Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 43d8717..b261613 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -2323,13 +2323,13 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask, u32 *mask) return; } - if (intmask & SDHCI_INT_TIMEOUT) - host->cmd->error = -ETIMEDOUT; - else if (intmask & (SDHCI_INT_CRC | SDHCI_INT_END_BIT | - SDHCI_INT_INDEX)) - host->cmd->error = -EILSEQ; + if (intmask & (SDHCI_INT_TIMEOUT | SDHCI_INT_CRC | + SDHCI_INT_END_BIT | SDHCI_INT_INDEX)) { + if (intmask & SDHCI_INT_TIMEOUT) + host->cmd->error = -ETIMEDOUT; + else + host->cmd->error = -EILSEQ; - if (host->cmd->error) { tasklet_schedule(&host->finish_tasklet); return; } -- cgit v0.10.2 From 71fcbda0fcddd0896c4982a484f6c8aa802d28b1 Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 26 Jan 2016 13:39:45 +0000 Subject: mmc: sdhci: fix command response CRC error handling When we get a response CRC error on a command, it means that the response we received back from the card was not correct. It does not mean that the card did not receive the command correctly. If the command is one which initiates a data transfer, the card can enter the data transfer state, and start sending data. Moreover, if the request contained a data phase, we do not clean this up, and this results in the driver triggering DMA API debug warnings, and also creates a race condition in the driver, between running the finish_tasklet and the data transfer interrupts, which can trigger a "Got data interrupt" state dump. Fix this by handing a response CRC error slightly differently: record the failure of the data initiating command, but allow the remainder of the request to be processed normally. This is safe as core MMC checks the status of all commands and data transfer phases of the request. If the card does not initiate a data transfer, then we should time out according to the data transfer parameters. Signed-off-by: Russell King [ Fix missing parenthesis around bitwise-AND expression, and tweak subject ] Signed-off-by: Adrian Hunter Cc: stable@vger.kernel.org # v4.5+ Tested-by: Gregory CLEMENT Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index b261613..5c90941 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -2330,6 +2330,23 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask, u32 *mask) else host->cmd->error = -EILSEQ; + /* + * If this command initiates a data phase and a response + * CRC error is signalled, the card can start transferring + * data - the card may have received the command without + * error. We must not terminate the mmc_request early. + * + * If the card did not receive the command or returned an + * error which prevented it sending data, the data phase + * will time out. + */ + if (host->cmd->data && + (intmask & (SDHCI_INT_CRC | SDHCI_INT_TIMEOUT)) == + SDHCI_INT_CRC) { + host->cmd = NULL; + return; + } + tasklet_schedule(&host->finish_tasklet); return; } -- cgit v0.10.2 From edd63fcc97cdb53279a7c43fa1691f5913d92793 Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 26 Jan 2016 13:39:50 +0000 Subject: mmc: sdhci: avoid unnecessary mapping/unmapping of align buffer Unnecessarily mapping and unmapping the align buffer for SD cards is expensive: performance measurements on iMX6 show that this gives a hit of 10% on hdparm buffered disk reads. MMC/SD card IO comes from the mm/vfs which gives us page based IO, so for this case, the align buffer is not going to be used. However, we still map and unmap this buffer. Eliminate this by switching the align buffer to be a DMA coherent buffer, which needs no DMA maintenance to access the buffer. Signed-off-by: Russell King Signed-off-by: Adrian Hunter Cc: stable@vger.kernel.org # v4.5+ Tested-by: Gregory CLEMENT Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 5c90941..78359ba 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -465,8 +465,6 @@ static void sdhci_adma_mark_end(void *desc) static int sdhci_adma_table_pre(struct sdhci_host *host, struct mmc_data *data) { - int direction; - void *desc; void *align; dma_addr_t addr; @@ -483,20 +481,9 @@ static int sdhci_adma_table_pre(struct sdhci_host *host, * We currently guess that it is LE. */ - if (data->flags & MMC_DATA_READ) - direction = DMA_FROM_DEVICE; - else - direction = DMA_TO_DEVICE; - - host->align_addr = dma_map_single(mmc_dev(host->mmc), - 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 & SDHCI_ADMA2_MASK); - host->sg_count = sdhci_pre_dma_transfer(host, data); if (host->sg_count < 0) - goto unmap_align; + return -EINVAL; desc = host->adma_table; align = host->align_buffer; @@ -570,22 +557,7 @@ static int sdhci_adma_table_pre(struct sdhci_host *host, /* nop, end, valid */ sdhci_adma_write_desc(host, desc, 0, 0, ADMA2_NOP_END_VALID); } - - /* - * Resync align buffer as we might have changed it. - */ - if (data->flags & MMC_DATA_WRITE) { - dma_sync_single_for_device(mmc_dev(host->mmc), - host->align_addr, host->align_buffer_sz, direction); - } - return 0; - -unmap_align: - dma_unmap_single(mmc_dev(host->mmc), host->align_addr, - host->align_buffer_sz, direction); -fail: - return -EINVAL; } static void sdhci_adma_table_post(struct sdhci_host *host, @@ -605,9 +577,6 @@ static void sdhci_adma_table_post(struct sdhci_host *host, else direction = DMA_TO_DEVICE; - dma_unmap_single(mmc_dev(host->mmc), host->align_addr, - 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) @@ -2985,14 +2954,21 @@ int sdhci_add_host(struct sdhci_host *host) &host->adma_addr, GFP_KERNEL); host->align_buffer_sz = SDHCI_MAX_SEGS * SDHCI_ADMA2_ALIGN; - host->align_buffer = kmalloc(host->align_buffer_sz, GFP_KERNEL); + host->align_buffer = dma_alloc_coherent(mmc_dev(mmc), + host->align_buffer_sz, + &host->align_addr, + GFP_KERNEL); if (!host->adma_table || !host->align_buffer) { if (host->adma_table) dma_free_coherent(mmc_dev(mmc), host->adma_table_sz, host->adma_table, host->adma_addr); - kfree(host->align_buffer); + if (host->align_buffer) + dma_free_coherent(mmc_dev(mmc), + host->align_buffer_sz, + host->align_buffer, + host->align_addr); pr_warn("%s: Unable to allocate ADMA buffers - falling back to standard DMA\n", mmc_hostname(mmc)); host->flags &= ~SDHCI_USE_ADMA; @@ -3004,10 +2980,14 @@ int sdhci_add_host(struct sdhci_host *host) host->flags &= ~SDHCI_USE_ADMA; dma_free_coherent(mmc_dev(mmc), host->adma_table_sz, host->adma_table, host->adma_addr); - kfree(host->align_buffer); + dma_free_coherent(mmc_dev(mmc), host->align_buffer_sz, + host->align_buffer, host->align_addr); host->adma_table = NULL; host->align_buffer = NULL; } + + /* dma_alloc_coherent returns page aligned and sized buffers */ + BUG_ON(host->align_addr & SDHCI_ADMA2_MASK); } /* @@ -3470,7 +3450,9 @@ void sdhci_remove_host(struct sdhci_host *host, int dead) if (host->adma_table) dma_free_coherent(mmc_dev(mmc), host->adma_table_sz, host->adma_table, host->adma_addr); - kfree(host->align_buffer); + if (host->align_buffer) + dma_free_coherent(mmc_dev(mmc), host->align_buffer_sz, + host->align_buffer, host->align_addr); host->adma_table = NULL; host->align_buffer = NULL; -- cgit v0.10.2 From 054cedff5e025a54ceefff891c6ea42ee8b37eab Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 26 Jan 2016 13:40:42 +0000 Subject: mmc: sdhci: plug DMA mapping leak on error If we terminate a command early, we fail to properly clean up the DMA mappings for the data part of the request. Put this clean up to the tasklet, which is the common path for finishing a request so we always clean up after ourselves. Signed-off-by: Russell King [ Split original patch so that it now contains only the fix ] Signed-off-by: Adrian Hunter Cc: stable@vger.kernel.org # v4.5+ Tested-by: Gregory CLEMENT Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 78359ba..97e5f40 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -2208,6 +2208,22 @@ static void sdhci_tasklet_finish(unsigned long param) mrq = host->mrq; /* + * Always unmap the data buffers if they were mapped by + * sdhci_prepare_data() whenever we finish with a request. + * This avoids leaking DMA mappings on error. + */ + if (host->flags & SDHCI_REQ_USE_DMA) { + struct mmc_data *data = mrq->data; + + if (data && data->host_cookie == COOKIE_MAPPED) { + dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len, + (data->flags & MMC_DATA_READ) ? + DMA_FROM_DEVICE : DMA_TO_DEVICE); + data->host_cookie = COOKIE_UNMAPPED; + } + } + + /* * The controller needs a reset of internal state machines * upon error conditions. */ -- cgit v0.10.2 From 0ca33b4ad9cfc133bb3d93eec1ad0eea83d6f252 Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 26 Jan 2016 13:40:47 +0000 Subject: mmc: sdhci-pxav3: fix higher speed mode capabilities Commit 1140011ee9d9 ("mmc: sdhci-pxav3: Modify clock settings for the SDR50 and DDR50 modes") broke any chance of the SDR50 or DDR50 modes being used. The commit claims that SDR50 and DDR50 require clock adjustments in the SDIO3 Configuration register, which is located via the "conf-sdio3" resource. However, when this resource is given, we fail to read the host capabilities 1 register, resulting in host->caps1 being zero. Hence, both SDHCI_SUPPORT_SDR50 and SDHCI_SUPPORT_DDR50 bits remain zero, disabling the SDR50 and DDR50 modes. The underlying idea in this function appears to be to read the device capabilities, modify them, and set SDHCI_QUIRK_MISSING_CAPS to cause our modified capabilities to be used. Implement exactly that. Fixes: 1140011ee9d9 ("mmc: sdhci-pxav3: Modify clock settings for the SDR50 and DDR50 modes") Signed-off-by: Russell King Cc: stable@vger.kernel.org # v4.5+ Signed-off-by: Adrian Hunter Tested-by: Gregory CLEMENT Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sdhci-pxav3.c b/drivers/mmc/host/sdhci-pxav3.c index f5edf9d..c7f27fe 100644 --- a/drivers/mmc/host/sdhci-pxav3.c +++ b/drivers/mmc/host/sdhci-pxav3.c @@ -137,6 +137,10 @@ static int armada_38x_quirks(struct platform_device *pdev, host->quirks &= ~SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN; host->quirks |= SDHCI_QUIRK_MISSING_CAPS; + + host->caps = sdhci_readl(host, SDHCI_CAPABILITIES); + host->caps1 = sdhci_readl(host, SDHCI_CAPABILITIES_1); + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "conf-sdio3"); if (res) { @@ -150,7 +154,6 @@ static int armada_38x_quirks(struct platform_device *pdev, * Configuration register, if the adjustment is not done, * remove them from the capabilities. */ - host->caps1 = sdhci_readl(host, SDHCI_CAPABILITIES_1); host->caps1 &= ~(SDHCI_SUPPORT_SDR50 | SDHCI_SUPPORT_DDR50); dev_warn(&pdev->dev, "conf-sdio3 register not found: disabling SDR50 and DDR50 modes.\nConsider updating your dtb\n"); @@ -161,7 +164,6 @@ static int armada_38x_quirks(struct platform_device *pdev, * controller has different capabilities than the ones shown * in its registers */ - host->caps = sdhci_readl(host, SDHCI_CAPABILITIES); if (of_property_read_bool(np, "no-1-8-v")) { host->caps &= ~SDHCI_CAN_VDD_180; host->mmc->caps &= ~MMC_CAP_1_8V_DDR; -- cgit v0.10.2 From 771a3dc225815b7cc691c1ce703a3af8488e48df Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 26 Jan 2016 13:40:53 +0000 Subject: mmc: sdhci: further fix for DMA unmapping in sdhci_post_req() sdhci_post_req() exists to unmap a previously mapped but already finished request, while the next request is in progress. However, the state of the SDHCI_REQ_USE_DMA flag depends on the last submitted request. This means we can end up clearing the flag due to a quirk, which then means that sdhci_post_req() fails to unmap the DMA buffer, potentially leading to data corruption. We can safely ignore the SDHCI_REQ_USE_DMA here, as testing data->host_cookie is entirely sufficient. Signed-off-by: Russell King [ Re-based to apply as a separate fix ] Signed-off-by: Adrian Hunter Cc: stable@vger.kernel.org # v4.5+ Tested-by: Gregory CLEMENT Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 97e5f40..6fe0e78 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -2084,14 +2084,13 @@ static void sdhci_post_req(struct mmc_host *mmc, struct mmc_request *mrq, struct sdhci_host *host = mmc_priv(mmc); struct mmc_data *data = mrq->data; - if (host->flags & SDHCI_REQ_USE_DMA) { - if (data->host_cookie == COOKIE_GIVEN || - data->host_cookie == COOKIE_MAPPED) - dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len, - data->flags & MMC_DATA_WRITE ? - DMA_TO_DEVICE : DMA_FROM_DEVICE); - data->host_cookie = COOKIE_UNMAPPED; - } + if (data->host_cookie == COOKIE_GIVEN || + data->host_cookie == COOKIE_MAPPED) + dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len, + data->flags & MMC_DATA_WRITE ? + DMA_TO_DEVICE : DMA_FROM_DEVICE); + + data->host_cookie = COOKIE_UNMAPPED; } static int sdhci_pre_dma_transfer(struct sdhci_host *host, -- cgit v0.10.2 From fafcfda9e78cae8796d1799f14e6457790797555 Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 26 Jan 2016 13:40:58 +0000 Subject: mmc: sdhci: fix data timeout (part 1) The data timeout gives the minimum amount of time that should be waited before timing out if no data is received from the card. Simply dividing the nanosecond part by 1000 does not give this required guarantee, since such a division rounds down. Use DIV_ROUND_UP() to give the desired timeout. Signed-off-by: Russell King Signed-off-by: Adrian Hunter Cc: stable@vger.kernel.org # v3.15+ Tested-by: Gregory CLEMENT Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 6fe0e78..1d1b3c5 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -635,7 +635,7 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd) if (!data) target_timeout = cmd->busy_timeout * 1000; else { - target_timeout = data->timeout_ns / 1000; + target_timeout = DIV_ROUND_UP(data->timeout_ns, 1000); if (host->clock) target_timeout += data->timeout_clks / host->clock; } -- cgit v0.10.2 From 7f05538af71c7d30b5fc821cbe9f318edc645961 Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 26 Jan 2016 13:41:04 +0000 Subject: mmc: sdhci: fix data timeout (part 2) The calculation for the timeout based on the number of card clocks is incorrect. The calculation assumed: timeout in microseconds = clock cycles / clock in Hz which is clearly a several orders of magnitude wrong. Fix this by multiplying the clock cycles by 1000000 prior to dividing by the Hz based clock. Also, as per part 1, ensure that the division rounds up. As this needs 64-bit math via do_div(), avoid it if the clock cycles is zero. Signed-off-by: Russell King Signed-off-by: Adrian Hunter Cc: stable@vger.kernel.org # v3.15+ Tested-by: Gregory CLEMENT Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 1d1b3c5..5a7517f 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -636,8 +636,19 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd) target_timeout = cmd->busy_timeout * 1000; else { target_timeout = DIV_ROUND_UP(data->timeout_ns, 1000); - if (host->clock) - target_timeout += data->timeout_clks / host->clock; + if (host->clock && data->timeout_clks) { + unsigned long long val; + + /* + * data->timeout_clks is in units of clock cycles. + * host->clock is in Hz. target_timeout is in us. + * Hence, us = 1000000 * cycles / Hz. Round up. + */ + val = 1000000 * data->timeout_clks; + if (do_div(val, host->clock)) + target_timeout++; + target_timeout += val; + } } /* -- cgit v0.10.2 From e66e61cba1fffc53151b5303688f9c077f87104c Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 26 Jan 2016 13:39:55 +0000 Subject: mmc: sdhci: allocate alignment and DMA descriptor buffer together Allocate both the alignment and DMA descriptor buffers together. The size of the alignment buffer will always be aligned to the hosts required alignment, which gives appropriate alignment to the DMA descriptors. We have a maximum of 128 segments, and a maximum alignment of 64 bits. This gives a maximum alignment buffer size of 1024 bytes. The DMA descriptors are a maximum of 12 bytes, and we allocate 128 * 2 + 1 of these, which gives a maximum DMA descriptor buffer size of 3084 bytes. This means the allocation for a 4K page sized system will be an order-1 allocation, since the resulting overall size is 4108. This is more prone to failure than page-sized allocations, but since this allocation commonly occurs at startup, the chances of failure are small. Signed-off-by: Russell King [ Changed to check ADMA table alignment ] Signed-off-by: Adrian Hunter Tested-by: Gregory CLEMENT Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 5a7517f..59ffe35 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -2960,6 +2960,9 @@ int sdhci_add_host(struct sdhci_host *host) host->flags &= ~SDHCI_USE_SDMA; if (host->flags & SDHCI_USE_ADMA) { + dma_addr_t dma; + void *buf; + /* * The DMA descriptor table size is calculated as the maximum * number of segments times 2, to allow for an alignment @@ -2975,45 +2978,28 @@ int sdhci_add_host(struct sdhci_host *host) SDHCI_ADMA2_32_DESC_SZ; host->desc_sz = SDHCI_ADMA2_32_DESC_SZ; } - host->adma_table = dma_alloc_coherent(mmc_dev(mmc), - host->adma_table_sz, - &host->adma_addr, - GFP_KERNEL); + host->align_buffer_sz = SDHCI_MAX_SEGS * SDHCI_ADMA2_ALIGN; - host->align_buffer = dma_alloc_coherent(mmc_dev(mmc), - host->align_buffer_sz, - &host->align_addr, - GFP_KERNEL); - if (!host->adma_table || !host->align_buffer) { - if (host->adma_table) - dma_free_coherent(mmc_dev(mmc), - host->adma_table_sz, - host->adma_table, - host->adma_addr); - if (host->align_buffer) - dma_free_coherent(mmc_dev(mmc), - host->align_buffer_sz, - host->align_buffer, - host->align_addr); + buf = dma_alloc_coherent(mmc_dev(mmc), host->align_buffer_sz + + host->adma_table_sz, &dma, GFP_KERNEL); + if (!buf) { pr_warn("%s: Unable to allocate ADMA buffers - falling back to standard DMA\n", mmc_hostname(mmc)); host->flags &= ~SDHCI_USE_ADMA; - host->adma_table = NULL; - host->align_buffer = NULL; - } else if (host->adma_addr & (SDHCI_ADMA2_DESC_ALIGN - 1)) { + } else if ((dma + host->align_buffer_sz) & + (SDHCI_ADMA2_DESC_ALIGN - 1)) { pr_warn("%s: unable to allocate aligned ADMA descriptor\n", mmc_hostname(mmc)); host->flags &= ~SDHCI_USE_ADMA; - dma_free_coherent(mmc_dev(mmc), host->adma_table_sz, - host->adma_table, host->adma_addr); - dma_free_coherent(mmc_dev(mmc), host->align_buffer_sz, - host->align_buffer, host->align_addr); - host->adma_table = NULL; - host->align_buffer = NULL; - } + dma_free_coherent(mmc_dev(mmc), host->align_buffer_sz + + host->adma_table_sz, buf, dma); + } else { + host->align_buffer = buf; + host->align_addr = dma; - /* dma_alloc_coherent returns page aligned and sized buffers */ - BUG_ON(host->align_addr & SDHCI_ADMA2_MASK); + host->adma_table = buf + host->align_buffer_sz; + host->adma_addr = dma + host->align_buffer_sz; + } } /* @@ -3473,12 +3459,10 @@ void sdhci_remove_host(struct sdhci_host *host, int dead) if (!IS_ERR(mmc->supply.vqmmc)) regulator_disable(mmc->supply.vqmmc); - if (host->adma_table) - dma_free_coherent(mmc_dev(mmc), host->adma_table_sz, - host->adma_table, host->adma_addr); if (host->align_buffer) - dma_free_coherent(mmc_dev(mmc), host->align_buffer_sz, - host->align_buffer, host->align_addr); + dma_free_coherent(mmc_dev(mmc), host->align_buffer_sz + + host->adma_table_sz, host->align_buffer, + host->align_addr); host->adma_table = NULL; host->align_buffer = NULL; -- cgit v0.10.2 From acc3ad13832ab1aa01bdf9b7e1d76171d1e4d060 Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 26 Jan 2016 13:40:00 +0000 Subject: mmc: sdhci: clean up coding style in sdhci_adma_table_pre() Signed-off-by: Russell King Signed-off-by: Adrian Hunter Tested-by: Gregory CLEMENT Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 59ffe35..bc645bb 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -465,16 +465,12 @@ static void sdhci_adma_mark_end(void *desc) static int sdhci_adma_table_pre(struct sdhci_host *host, struct mmc_data *data) { - void *desc; - void *align; - dma_addr_t addr; - dma_addr_t align_addr; - int len, offset; - struct scatterlist *sg; - int i; - char *buffer; unsigned long flags; + dma_addr_t addr, align_addr; + void *desc, *align; + char *buffer; + int len, offset, i; /* * The spec does not specify endianness of descriptor table. @@ -495,10 +491,9 @@ static int sdhci_adma_table_pre(struct sdhci_host *host, len = sg_dma_len(sg); /* - * The SDHCI specification states that ADMA - * addresses must be 32-bit aligned. If they - * aren't, then we use a bounce buffer for - * the (up to three) bytes that screw up the + * The SDHCI specification states that ADMA addresses must + * be 32-bit aligned. If they aren't, then we use a bounce + * buffer for the (up to three) bytes that screw up the * alignment. */ offset = (SDHCI_ADMA2_ALIGN - (addr & SDHCI_ADMA2_MASK)) & @@ -542,19 +537,13 @@ static int sdhci_adma_table_pre(struct sdhci_host *host, } if (host->quirks & SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC) { - /* - * Mark the last descriptor as the terminating descriptor - */ + /* Mark the last descriptor as the terminating descriptor */ if (desc != host->adma_table) { desc -= host->desc_sz; sdhci_adma_mark_end(desc); } } else { - /* - * Add a terminating entry. - */ - - /* nop, end, valid */ + /* Add a terminating entry - nop, end, valid */ sdhci_adma_write_desc(host, desc, 0, 0, ADMA2_NOP_END_VALID); } return 0; -- cgit v0.10.2 From 47fa961340d2181ebf1165b7651dcbb1b1029163 Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 26 Jan 2016 13:40:06 +0000 Subject: mmc: sdhci: avoid walking SG list for writes If we are writing data to the card, there is no point in walking the scatterlist to find out if there are any unaligned entries; this is a needless waste of CPU cycles. Avoid this by checking for a non-read tranfer first. Signed-off-by: Russell King Signed-off-by: Adrian Hunter Tested-by: Gregory CLEMENT Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index bc645bb..b28aa0f 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -559,37 +559,39 @@ static void sdhci_adma_table_post(struct sdhci_host *host, void *align; char *buffer; unsigned long flags; - bool has_unaligned; if (data->flags & MMC_DATA_READ) direction = DMA_FROM_DEVICE; else direction = DMA_TO_DEVICE; - /* 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) & SDHCI_ADMA2_MASK) { - has_unaligned = true; - break; - } + if (data->flags & MMC_DATA_READ) { + bool has_unaligned = false; - if (has_unaligned && data->flags & MMC_DATA_READ) { - dma_sync_sg_for_cpu(mmc_dev(host->mmc), data->sg, - data->sg_len, direction); + /* Do a quick scan of the SG list for any unaligned mappings */ + for_each_sg(data->sg, sg, host->sg_count, i) + if (sg_dma_address(sg) & SDHCI_ADMA2_MASK) { + has_unaligned = true; + break; + } - align = host->align_buffer; + if (has_unaligned) { + dma_sync_sg_for_cpu(mmc_dev(host->mmc), data->sg, + data->sg_len, direction); - for_each_sg(data->sg, sg, host->sg_count, i) { - if (sg_dma_address(sg) & SDHCI_ADMA2_MASK) { - size = SDHCI_ADMA2_ALIGN - - (sg_dma_address(sg) & SDHCI_ADMA2_MASK); + align = host->align_buffer; - buffer = sdhci_kmap_atomic(sg, &flags); - memcpy(buffer, align, size); - sdhci_kunmap_atomic(buffer, &flags); + for_each_sg(data->sg, sg, host->sg_count, i) { + if (sg_dma_address(sg) & SDHCI_ADMA2_MASK) { + size = SDHCI_ADMA2_ALIGN - + (sg_dma_address(sg) & SDHCI_ADMA2_MASK); - align += SDHCI_ADMA2_ALIGN; + buffer = sdhci_kmap_atomic(sg, &flags); + memcpy(buffer, align, size); + sdhci_kunmap_atomic(buffer, &flags); + + align += SDHCI_ADMA2_ALIGN; + } } } } -- cgit v0.10.2 From f55c98f7466c2e52125d6ffd69295c0158ac609a Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 26 Jan 2016 13:40:11 +0000 Subject: mmc: sdhci: factor out common DMA cleanup in sdhci_finish_data() sdhci_finish_data() has two paths which result in identical DMA cleanup. One is when SDHCI_USE_ADMA is clear, and the other is just before when SDHCI_USE_ADMA is set, and is performed within sdhci_adma_table_post(). Simplify the code by removing the 'else' and eliminating the duplicate inside sdhci_adma_table_post(). Signed-off-by: Russell King Signed-off-by: Adrian Hunter Tested-by: Gregory CLEMENT Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index b28aa0f..54ab050 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -552,19 +552,12 @@ static int sdhci_adma_table_pre(struct sdhci_host *host, static void sdhci_adma_table_post(struct sdhci_host *host, struct mmc_data *data) { - int direction; - struct scatterlist *sg; int i, size; void *align; char *buffer; unsigned long flags; - if (data->flags & MMC_DATA_READ) - direction = DMA_FROM_DEVICE; - else - direction = DMA_TO_DEVICE; - if (data->flags & MMC_DATA_READ) { bool has_unaligned = false; @@ -577,7 +570,7 @@ static void sdhci_adma_table_post(struct sdhci_host *host, if (has_unaligned) { dma_sync_sg_for_cpu(mmc_dev(host->mmc), data->sg, - data->sg_len, direction); + data->sg_len, DMA_FROM_DEVICE); align = host->align_buffer; @@ -595,12 +588,6 @@ static void sdhci_adma_table_post(struct sdhci_host *host, } } } - - if (data->host_cookie == COOKIE_MAPPED) { - dma_unmap_sg(mmc_dev(host->mmc), data->sg, - data->sg_len, direction); - data->host_cookie = COOKIE_UNMAPPED; - } } static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd) @@ -920,14 +907,12 @@ static void sdhci_finish_data(struct sdhci_host *host) if (host->flags & SDHCI_REQ_USE_DMA) { if (host->flags & SDHCI_USE_ADMA) sdhci_adma_table_post(host, data); - else { - if (data->host_cookie == COOKIE_MAPPED) { - dma_unmap_sg(mmc_dev(host->mmc), - data->sg, data->sg_len, - (data->flags & MMC_DATA_READ) ? - DMA_FROM_DEVICE : DMA_TO_DEVICE); - data->host_cookie = COOKIE_UNMAPPED; - } + + if (data->host_cookie == COOKIE_MAPPED) { + dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len, + (data->flags & MMC_DATA_READ) ? + DMA_FROM_DEVICE : DMA_TO_DEVICE); + data->host_cookie = COOKIE_UNMAPPED; } } -- cgit v0.10.2 From 48857d9b7865c4110ecf9c57b85224a3ec84ad54 Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 26 Jan 2016 13:40:16 +0000 Subject: mmc: sdhci: move sdhci_pre_dma_transfer() Move sdhci_pre_dma_transfer() to avoid needing to declare this function before use. Signed-off-by: Russell King Signed-off-by: Adrian Hunter Tested-by: Gregory CLEMENT Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 54ab050..1278a8d 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -53,8 +53,6 @@ static void sdhci_finish_data(struct sdhci_host *); static void sdhci_finish_command(struct sdhci_host *); static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode); static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable); -static int sdhci_pre_dma_transfer(struct sdhci_host *host, - struct mmc_data *data); static int sdhci_do_get_cd(struct sdhci_host *host); #ifdef CONFIG_PM @@ -428,6 +426,31 @@ static void sdhci_transfer_pio(struct sdhci_host *host) DBG("PIO transfer complete.\n"); } +static int sdhci_pre_dma_transfer(struct sdhci_host *host, + struct mmc_data *data) +{ + int sg_count; + + if (data->host_cookie == COOKIE_MAPPED) { + data->host_cookie = COOKIE_GIVEN; + return data->sg_count; + } + + WARN_ON(data->host_cookie == COOKIE_GIVEN); + + sg_count = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len, + data->flags & MMC_DATA_WRITE ? + DMA_TO_DEVICE : DMA_FROM_DEVICE); + + if (sg_count == 0) + return -ENOSPC; + + data->sg_count = sg_count; + data->host_cookie = COOKIE_MAPPED; + + return sg_count; +} + static char *sdhci_kmap_atomic(struct scatterlist *sg, unsigned long *flags) { local_irq_save(*flags); @@ -2080,31 +2103,6 @@ static void sdhci_post_req(struct mmc_host *mmc, struct mmc_request *mrq, data->host_cookie = COOKIE_UNMAPPED; } -static int sdhci_pre_dma_transfer(struct sdhci_host *host, - struct mmc_data *data) -{ - int sg_count; - - if (data->host_cookie == COOKIE_MAPPED) { - data->host_cookie = COOKIE_GIVEN; - return data->sg_count; - } - - WARN_ON(data->host_cookie == COOKIE_GIVEN); - - sg_count = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len, - data->flags & MMC_DATA_WRITE ? - DMA_TO_DEVICE : DMA_FROM_DEVICE); - - if (sg_count == 0) - return -ENOSPC; - - data->sg_count = sg_count; - data->host_cookie = COOKIE_MAPPED; - - return sg_count; -} - static void sdhci_pre_req(struct mmc_host *mmc, struct mmc_request *mrq, bool is_first_req) { -- cgit v0.10.2 From 60c647624a67f6057866b685ba20abce52e259e5 Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 26 Jan 2016 13:40:22 +0000 Subject: mmc: sdhci: factor out sdhci_pre_dma_transfer() from sdhci_adma_table_pre() In sdhci_prepare_data(), when SDHCI_REQ_USE_DMA is set, there are two paths that prepare the data buffers for transfer. One is when SDHCI_USE_ADMA is set, and is located inside sdhci_adma_table_pre(). The other is when SDHCI_USE_ADMA is clear, in the else clause of the above. Factor out the call to sdhci_pre_dma_transfer() along with its error checking. Signed-off-by: Russell King Signed-off-by: Adrian Hunter Tested-by: Gregory CLEMENT Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 1278a8d..8b455cd 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -485,8 +485,8 @@ static void sdhci_adma_mark_end(void *desc) dma_desc->cmd |= cpu_to_le16(ADMA2_END); } -static int sdhci_adma_table_pre(struct sdhci_host *host, - struct mmc_data *data) +static void sdhci_adma_table_pre(struct sdhci_host *host, + struct mmc_data *data, int sg_count) { struct scatterlist *sg; unsigned long flags; @@ -500,9 +500,7 @@ static int sdhci_adma_table_pre(struct sdhci_host *host, * We currently guess that it is LE. */ - host->sg_count = sdhci_pre_dma_transfer(host, data); - if (host->sg_count < 0) - return -EINVAL; + host->sg_count = sg_count; desc = host->adma_table; align = host->align_buffer; @@ -569,7 +567,6 @@ static int sdhci_adma_table_pre(struct sdhci_host *host, /* Add a terminating entry - nop, end, valid */ sdhci_adma_write_desc(host, desc, 0, 0, ADMA2_NOP_END_VALID); } - return 0; } static void sdhci_adma_table_post(struct sdhci_host *host, @@ -710,7 +707,6 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd) { u8 ctrl; struct mmc_data *data = cmd->data; - int ret; WARN_ON(host->data); @@ -795,39 +791,27 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd) } if (host->flags & SDHCI_REQ_USE_DMA) { - if (host->flags & SDHCI_USE_ADMA) { - ret = sdhci_adma_table_pre(host, data); - if (ret) { - /* - * This only happens when someone fed - * us an invalid request. - */ - WARN_ON(1); - host->flags &= ~SDHCI_REQ_USE_DMA; - } 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; + int sg_cnt = sdhci_pre_dma_transfer(host, data); - sg_cnt = sdhci_pre_dma_transfer(host, data); - if (sg_cnt <= 0) { - /* - * This only happens when someone fed - * us an invalid request. - */ - WARN_ON(1); - host->flags &= ~SDHCI_REQ_USE_DMA; - } else { - WARN_ON(sg_cnt != 1); - sdhci_writel(host, sg_dma_address(data->sg), - SDHCI_DMA_ADDRESS); - } + if (sg_cnt <= 0) { + /* + * This only happens when someone fed + * us an invalid request. + */ + WARN_ON(1); + host->flags &= ~SDHCI_REQ_USE_DMA; + } else if (host->flags & SDHCI_USE_ADMA) { + sdhci_adma_table_pre(host, data, sg_cnt); + + 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 { + WARN_ON(sg_cnt != 1); + sdhci_writel(host, sg_dma_address(data->sg), + SDHCI_DMA_ADDRESS); } } -- cgit v0.10.2 From c0999b720c4f9c34cf10f79caf71bf8c1a246390 Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 26 Jan 2016 13:40:27 +0000 Subject: mmc: sdhci: pass the cookie into sdhci_pre_dma_transfer() Pass the desired cookie for a successful map. This is in preparation to clean up the MAPPED/GIVEN states. Signed-off-by: Russell King Signed-off-by: Adrian Hunter Tested-by: Gregory CLEMENT Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 8b455cd..9321d4a 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -427,7 +427,7 @@ static void sdhci_transfer_pio(struct sdhci_host *host) } static int sdhci_pre_dma_transfer(struct sdhci_host *host, - struct mmc_data *data) + struct mmc_data *data, int cookie) { int sg_count; @@ -446,7 +446,7 @@ static int sdhci_pre_dma_transfer(struct sdhci_host *host, return -ENOSPC; data->sg_count = sg_count; - data->host_cookie = COOKIE_MAPPED; + data->host_cookie = cookie; return sg_count; } @@ -791,7 +791,7 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd) } if (host->flags & SDHCI_REQ_USE_DMA) { - int sg_cnt = sdhci_pre_dma_transfer(host, data); + int sg_cnt = sdhci_pre_dma_transfer(host, data, COOKIE_MAPPED); if (sg_cnt <= 0) { /* @@ -2095,7 +2095,7 @@ static void sdhci_pre_req(struct mmc_host *mmc, struct mmc_request *mrq, mrq->data->host_cookie = COOKIE_UNMAPPED; if (host->flags & SDHCI_REQ_USE_DMA) - sdhci_pre_dma_transfer(host, mrq->data); + sdhci_pre_dma_transfer(host, mrq->data, COOKIE_MAPPED); } static void sdhci_card_event(struct mmc_host *mmc) -- cgit v0.10.2 From f48f039cd2d33d01ba15e92018dc18a0ea68c764 Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 26 Jan 2016 13:40:32 +0000 Subject: mmc: sdhci: always unmap a mapped data transfer in sdhci_post_req() If the host cookie indicates that the data buffers of a request are mapped at sdhci_post_req() time, always unmap the data buffers. Signed-off-by: Russell King Signed-off-by: Adrian Hunter Tested-by: Gregory CLEMENT Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 9321d4a..393a1b0 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -2078,8 +2078,7 @@ static void sdhci_post_req(struct mmc_host *mmc, struct mmc_request *mrq, struct sdhci_host *host = mmc_priv(mmc); struct mmc_data *data = mrq->data; - if (data->host_cookie == COOKIE_GIVEN || - data->host_cookie == COOKIE_MAPPED) + if (data->host_cookie != COOKIE_UNMAPPED) dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len, data->flags & MMC_DATA_WRITE ? DMA_TO_DEVICE : DMA_FROM_DEVICE); -- cgit v0.10.2 From 94538e51d67da97e798d379d6bcf3d386d609bfb Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 26 Jan 2016 13:40:37 +0000 Subject: mmc: sdhci: clean up host cookie handling Commit d31911b9374a ("mmc: sdhci: fix dma memory leak in sdhci_pre_req()") added a complicated method to manage the DMA map state for the data transfer, but this complexity is not required. There are three states: * Unmapped * Mapped by sdhci_pre_req() * Mapped by sdhci_prepare_data() sdhci_prepare_data() needs to know when the data buffers have been successfully mapped by sdhci_pre_req(), and if so, there is no need to map them a second time. When we come to tear down the mapping, we want to know whether sdhci_post_req() will be called (which is determined by sdhci_pre_req() having been previously called) so that we can postpone the unmap operation. Hence, it makes sense to simply record when the successful DMA map happened (via COOKIE_PRE_MAPPED vs COOKIE_MAPPED) rather than having the complex mechanics involving COOKIE_MAPPED vs COOKIE_GIVEN. If a mapping is created by sdhci_prepare_data(), we must tear it down ourselves, without waiting for sdhci_post_req() (hence, the new COOKIE_MAPPED case). If the mapping is created by sdhci_pre_req() then sdhci_post_req() is responsible for tearing the mapping down. Signed-off-by: Russell King Signed-off-by: Adrian Hunter Tested-by: Gregory CLEMENT Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 393a1b0..16e8db0 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -431,12 +431,12 @@ static int sdhci_pre_dma_transfer(struct sdhci_host *host, { int sg_count; - if (data->host_cookie == COOKIE_MAPPED) { - data->host_cookie = COOKIE_GIVEN; + /* + * If the data buffers are already mapped, return the previous + * dma_map_sg() result. + */ + if (data->host_cookie == COOKIE_PRE_MAPPED) return data->sg_count; - } - - WARN_ON(data->host_cookie == COOKIE_GIVEN); sg_count = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len, data->flags & MMC_DATA_WRITE ? @@ -2094,7 +2094,7 @@ static void sdhci_pre_req(struct mmc_host *mmc, struct mmc_request *mrq, mrq->data->host_cookie = COOKIE_UNMAPPED; if (host->flags & SDHCI_REQ_USE_DMA) - sdhci_pre_dma_transfer(host, mrq->data, COOKIE_MAPPED); + sdhci_pre_dma_transfer(host, mrq->data, COOKIE_PRE_MAPPED); } static void sdhci_card_event(struct mmc_host *mmc) diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index 0115e99..3bd2803 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -316,8 +316,8 @@ struct sdhci_adma2_64_desc { enum sdhci_cookie { COOKIE_UNMAPPED, - COOKIE_MAPPED, - COOKIE_GIVEN, + COOKIE_PRE_MAPPED, /* mapped by sdhci_pre_req() */ + COOKIE_MAPPED, /* mapped by sdhci_prepare_data() */ }; struct sdhci_host { -- cgit v0.10.2 From add8913d5d73fe617fd7fa0f62f170c8ac5f313b Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 26 Jan 2016 13:40:42 +0000 Subject: mmc: sdhci: cleanup DMA un-mapping The patch "mmc: sdhci: plug DMA mapping leak on error" added un-mapping logic to sdhci_tasklet_finish() where it is always called, thereby preventing the mapping leaking. Consequently the un-mapping code in sdhci_finish_data() is no longer needed. Remove it. Signed-off-by: Russell King [ Split from original "mmc: sdhci: plug DMA mapping leak on error" patch ] Signed-off-by: Adrian Hunter Tested-by: Gregory CLEMENT Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 16e8db0..082c2f9 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -911,17 +911,9 @@ static void sdhci_finish_data(struct sdhci_host *host) data = host->data; host->data = NULL; - if (host->flags & SDHCI_REQ_USE_DMA) { - if (host->flags & SDHCI_USE_ADMA) - sdhci_adma_table_post(host, data); - - if (data->host_cookie == COOKIE_MAPPED) { - dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len, - (data->flags & MMC_DATA_READ) ? - DMA_FROM_DEVICE : DMA_TO_DEVICE); - data->host_cookie = COOKIE_UNMAPPED; - } - } + if ((host->flags & (SDHCI_REQ_USE_DMA | SDHCI_USE_ADMA)) == + (SDHCI_REQ_USE_DMA | SDHCI_USE_ADMA)) + sdhci_adma_table_post(host, data); /* * The specification states that the block count register must -- cgit v0.10.2 From a0eaf0f93f0630ac09519e27c84f88c8e41c6f8b Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 26 Jan 2016 13:41:09 +0000 Subject: mmc: sdhci: prepare DMA address/size quirk handling consolidation Prepare to consolidate the DMA address/size quirk handling into one single loop. Signed-off-by: Russell King Signed-off-by: Adrian Hunter Tested-by: Gregory CLEMENT Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 082c2f9..5119904 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -733,23 +733,24 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd) * scatterlist. */ if (host->flags & SDHCI_REQ_USE_DMA) { - int broken, i; struct scatterlist *sg; + unsigned int length_mask; + int i; - broken = 0; + length_mask = 0; if (host->flags & SDHCI_USE_ADMA) { if (host->quirks & SDHCI_QUIRK_32BIT_ADMA_SIZE) - broken = 1; + length_mask = 3; } else { if (host->quirks & SDHCI_QUIRK_32BIT_DMA_SIZE) - broken = 1; + length_mask = 3; } - if (unlikely(broken)) { + if (unlikely(length_mask)) { for_each_sg(data->sg, sg, data->sg_len, i) { - if (sg->length & 0x3) { + if (sg->length & length_mask) { DBG("Reverting to PIO because of transfer size (%d)\n", - sg->length); + sg->length); host->flags &= ~SDHCI_REQ_USE_DMA; break; } @@ -762,10 +763,11 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd) * translation to device address space. */ if (host->flags & SDHCI_REQ_USE_DMA) { - int broken, i; struct scatterlist *sg; + unsigned int offset_mask; + int i; - broken = 0; + offset_mask = 0; if (host->flags & SDHCI_USE_ADMA) { /* * As we use 3 byte chunks to work around @@ -773,15 +775,15 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd) * quirk. */ if (host->quirks & SDHCI_QUIRK_32BIT_ADMA_SIZE) - broken = 1; + offset_mask = 3; } else { if (host->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR) - broken = 1; + offset_mask = 3; } - if (unlikely(broken)) { + if (unlikely(offset_mask)) { for_each_sg(data->sg, sg, data->sg_len, i) { - if (sg->offset & 0x3) { + if (sg->offset & offset_mask) { DBG("Reverting to PIO because of bad alignment\n"); host->flags &= ~SDHCI_REQ_USE_DMA; break; -- cgit v0.10.2 From df953925a504d3c7a2a8814143a044c14d6660c0 Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 26 Jan 2016 13:41:14 +0000 Subject: mmc: sdhci: consolidate the DMA/ADMA size/address quicks Rather than scanning the scatterlist multiple times for each quirk, scan it once, checking for each possible quirk. This should be cheaper due to the length and offset members commonly sharing the same cache line than scanning the scatterlist multiple times. Signed-off-by: Russell King Signed-off-by: Adrian Hunter Tested-by: Gregory CLEMENT Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 5119904..2bd6bc1 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -731,22 +731,35 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd) /* * FIXME: This doesn't account for merging when mapping the * scatterlist. + * + * The assumption here being that alignment and lengths are + * the same after DMA mapping to device address space. */ if (host->flags & SDHCI_REQ_USE_DMA) { struct scatterlist *sg; - unsigned int length_mask; + unsigned int length_mask, offset_mask; int i; length_mask = 0; + offset_mask = 0; if (host->flags & SDHCI_USE_ADMA) { - if (host->quirks & SDHCI_QUIRK_32BIT_ADMA_SIZE) + if (host->quirks & SDHCI_QUIRK_32BIT_ADMA_SIZE) { length_mask = 3; + /* + * As we use up to 3 byte chunks to work + * around alignment problems, we need to + * check the offset as well. + */ + offset_mask = 3; + } } else { if (host->quirks & SDHCI_QUIRK_32BIT_DMA_SIZE) length_mask = 3; + if (host->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR) + offset_mask = 3; } - if (unlikely(length_mask)) { + if (unlikely(length_mask | offset_mask)) { for_each_sg(data->sg, sg, data->sg_len, i) { if (sg->length & length_mask) { DBG("Reverting to PIO because of transfer size (%d)\n", @@ -754,35 +767,6 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd) host->flags &= ~SDHCI_REQ_USE_DMA; break; } - } - } - } - - /* - * The assumption here being that alignment is the same after - * translation to device address space. - */ - if (host->flags & SDHCI_REQ_USE_DMA) { - struct scatterlist *sg; - unsigned int offset_mask; - int i; - - offset_mask = 0; - if (host->flags & SDHCI_USE_ADMA) { - /* - * As we use 3 byte chunks to work around - * alignment problems, we need to check this - * quirk. - */ - if (host->quirks & SDHCI_QUIRK_32BIT_ADMA_SIZE) - offset_mask = 3; - } else { - if (host->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR) - offset_mask = 3; - } - - if (unlikely(offset_mask)) { - for_each_sg(data->sg, sg, data->sg_len, i) { if (sg->offset & offset_mask) { DBG("Reverting to PIO because of bad alignment\n"); host->flags &= ~SDHCI_REQ_USE_DMA; -- cgit v0.10.2 From fce1442164cff51250c8f264b3757fd76f2a955b Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 26 Jan 2016 13:41:20 +0000 Subject: mmc: sdhci: further code simplication Further simplify the code in sdhci_prepare_data() - we don't set SDHCI_REQ_USE_DMA anywhere else in the driver, so there is no need to set it, and then immediately test it. Signed-off-by: Russell King Signed-off-by: Adrian Hunter Tested-by: Gregory CLEMENT Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 2bd6bc1..03fbb36 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -725,21 +725,20 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd) host->data_early = 0; host->data->bytes_xfered = 0; - if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) - host->flags |= SDHCI_REQ_USE_DMA; - - /* - * FIXME: This doesn't account for merging when mapping the - * scatterlist. - * - * The assumption here being that alignment and lengths are - * the same after DMA mapping to device address space. - */ - if (host->flags & SDHCI_REQ_USE_DMA) { + if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) { struct scatterlist *sg; unsigned int length_mask, offset_mask; int i; + host->flags |= SDHCI_REQ_USE_DMA; + + /* + * FIXME: This doesn't account for merging when mapping the + * scatterlist. + * + * The assumption here being that alignment and lengths are + * the same after DMA mapping to device address space. + */ length_mask = 0; offset_mask = 0; if (host->flags & SDHCI_USE_ADMA) { -- cgit v0.10.2 From a72e8b170069e98e1f5ca2a2855ee399148a9152 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Mon, 15 Feb 2016 16:01:48 +0100 Subject: mmc: sdhi: Add r8a7795 support Registers are 64bit apart, so we refactor bus_shift handling a little and set it based on the DT compatible. Also, EXT_ACC is different. It has been tested on a Salvator-X (Gen3) and, to check for regressions, on a Lager (Gen2). Signed-off-by: Ai Kyuse Signed-off-by: Wolfram Sang Signed-off-by: Ulf Hansson diff --git a/Documentation/devicetree/bindings/mmc/tmio_mmc.txt b/Documentation/devicetree/bindings/mmc/tmio_mmc.txt index 400b640..7fb746d 100644 --- a/Documentation/devicetree/bindings/mmc/tmio_mmc.txt +++ b/Documentation/devicetree/bindings/mmc/tmio_mmc.txt @@ -22,6 +22,7 @@ Required properties: "renesas,sdhi-r8a7792" - SDHI IP on R8A7792 SoC "renesas,sdhi-r8a7793" - SDHI IP on R8A7793 SoC "renesas,sdhi-r8a7794" - SDHI IP on R8A7794 SoC + "renesas,sdhi-r8a7795" - SDHI IP on R8A7795 SoC Optional properties: - toshiba,mmc-wrprotect-disable: write-protect detection is unavailable diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index 4a35ebf..d9a9d92 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -560,7 +560,7 @@ config MMC_TMIO config MMC_SDHI tristate "SH-Mobile SDHI SD/SDIO controller support" - depends on SUPERH || ARM + depends on SUPERH || ARM || ARM64 depends on SUPERH || ARCH_SHMOBILE || COMPILE_TEST select MMC_TMIO_CORE help diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/sh_mobile_sdhi.c index 557e2b9..9aa1479 100644 --- a/drivers/mmc/host/sh_mobile_sdhi.c +++ b/drivers/mmc/host/sh_mobile_sdhi.c @@ -1,6 +1,8 @@ /* * SuperH Mobile SDHI * + * Copyright (C) 2016 Sang Engineering, Wolfram Sang + * Copyright (C) 2015-16 Renesas Electronics Corporation * Copyright (C) 2009 Magnus Damm * * This program is free software; you can redistribute it and/or modify @@ -43,6 +45,7 @@ struct sh_mobile_sdhi_of_data { unsigned long capabilities2; enum dma_slave_buswidth dma_buswidth; dma_addr_t dma_rx_offset; + unsigned bus_shift; }; static const struct sh_mobile_sdhi_of_data sh_mobile_sdhi_of_cfg[] = { @@ -65,6 +68,13 @@ static const struct sh_mobile_sdhi_of_data of_rcar_gen2_compatible = { .dma_rx_offset = 0x2000, }; +static const struct sh_mobile_sdhi_of_data of_rcar_gen3_compatible = { + .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_WRPROTECT_DISABLE | + TMIO_MMC_CLK_ACTUAL | TMIO_MMC_FAST_CLK_CHG, + .capabilities = MMC_CAP_SD_HIGHSPEED, + .bus_shift = 2, +}; + static const struct of_device_id sh_mobile_sdhi_of_match[] = { { .compatible = "renesas,sdhi-shmobile" }, { .compatible = "renesas,sdhi-sh7372" }, @@ -78,6 +88,7 @@ static const struct of_device_id sh_mobile_sdhi_of_match[] = { { .compatible = "renesas,sdhi-r8a7792", .data = &of_rcar_gen2_compatible, }, { .compatible = "renesas,sdhi-r8a7793", .data = &of_rcar_gen2_compatible, }, { .compatible = "renesas,sdhi-r8a7794", .data = &of_rcar_gen2_compatible, }, + { .compatible = "renesas,sdhi-r8a7795", .data = &of_rcar_gen3_compatible, }, {}, }; MODULE_DEVICE_TABLE(of, sh_mobile_sdhi_of_match); @@ -103,6 +114,15 @@ static void sh_mobile_sdhi_sdbuf_width(struct tmio_mmc_host *host, int width) case 0xCB0D: val = (width == 32) ? 0x0000 : 0x0001; break; + case 0xCC10: /* Gen3, SD only */ + case 0xCD10: /* Gen3, SD + MMC */ + if (width == 64) + val = 0x0000; + else if (width == 32) + val = 0x0101; + else + val = 0x0001; + break; default: /* nothing to do */ return; @@ -233,16 +253,26 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev) goto eprobe; } + if (of_id && of_id->data) { + const struct sh_mobile_sdhi_of_data *of_data = of_id->data; + + mmc_data->flags |= of_data->tmio_flags; + mmc_data->capabilities |= of_data->capabilities; + mmc_data->capabilities2 |= of_data->capabilities2; + mmc_data->dma_rx_offset = of_data->dma_rx_offset; + dma_priv->dma_buswidth = of_data->dma_buswidth; + host->bus_shift = of_data->bus_shift; + } + host->dma = dma_priv; host->write16_hook = sh_mobile_sdhi_write16_hook; host->clk_enable = sh_mobile_sdhi_clk_enable; host->clk_disable = sh_mobile_sdhi_clk_disable; host->multi_io_quirk = sh_mobile_sdhi_multi_io_quirk; - /* SD control register space size is 0x100, 0x200 for bus_shift=1 */ - if (resource_size(res) > 0x100) + + /* Orginally registers were 16 bit apart, could be 32 or 64 nowadays */ + if (!host->bus_shift && resource_size(res) > 0x100) /* old way to determine the shift */ host->bus_shift = 1; - else - host->bus_shift = 0; if (mmd) *mmc_data = *mmd; @@ -274,15 +304,6 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev) */ mmc_data->flags |= TMIO_MMC_SDIO_STATUS_QUIRK; - if (of_id && of_id->data) { - const struct sh_mobile_sdhi_of_data *of_data = of_id->data; - mmc_data->flags |= of_data->tmio_flags; - mmc_data->capabilities |= of_data->capabilities; - mmc_data->capabilities2 |= of_data->capabilities2; - mmc_data->dma_rx_offset = of_data->dma_rx_offset; - dma_priv->dma_buswidth = of_data->dma_buswidth; - } - ret = tmio_mmc_host_probe(host, mmc_data); if (ret < 0) goto efree; -- cgit v0.10.2 From 8d53e41238a860fa27c6d312adde16148d2ffe07 Mon Sep 17 00:00:00 2001 From: Chaotian Jing Date: Mon, 15 Feb 2016 02:31:00 +0800 Subject: mmc: mediatek: add SD write protect support use mmc core layer's API to support sd write protect Signed-off-by: Chaotian Jing Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c index 82a97ac..f01972e 100644 --- a/drivers/mmc/host/mtk-sd.c +++ b/drivers/mmc/host/mtk-sd.c @@ -35,6 +35,7 @@ #include #include #include +#include #define MAX_BD_NUM 1024 @@ -1452,6 +1453,7 @@ static struct mmc_host_ops mt_msdc_ops = { .pre_req = msdc_pre_req, .request = msdc_ops_request, .set_ios = msdc_ops_set_ios, + .get_ro = mmc_gpio_get_ro, .start_signal_voltage_switch = msdc_ops_switch_volt, .card_busy = msdc_card_busy, .execute_tuning = msdc_execute_tuning, -- cgit v0.10.2 From 13db83e2b60464266098b52344c7db6b848f4154 Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Tue, 16 Feb 2016 21:08:19 +0800 Subject: mmc: sdhci-bcm2835: use sdhci_pltfm_init for private allocation Commit 0e748234293f ("mmc: sdhci: Add size for caller in init+register") allows users of sdhci_pltfm to allocate private space in calls to sdhci_pltfm_init+sdhci_pltfm_register. This patch migrates sdhci-bcm2835 to this allocation. Signed-off-by: Jisheng Zhang Acked-by: Arnd Bergmann Acked-by: Adrian Hunter Acked-by: Eric Anholt Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sdhci-bcm2835.c b/drivers/mmc/host/sdhci-bcm2835.c index 1c65d46..4a6a1d1 100644 --- a/drivers/mmc/host/sdhci-bcm2835.c +++ b/drivers/mmc/host/sdhci-bcm2835.c @@ -74,7 +74,7 @@ static inline u32 bcm2835_sdhci_readl(struct sdhci_host *host, int reg) static void bcm2835_sdhci_writew(struct sdhci_host *host, u16 val, int reg) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct bcm2835_sdhci *bcm2835_host = pltfm_host->priv; + struct bcm2835_sdhci *bcm2835_host = sdhci_pltfm_priv(pltfm_host); u32 oldval = (reg == SDHCI_COMMAND) ? bcm2835_host->shadow : bcm2835_sdhci_readl(host, reg & ~3); u32 word_num = (reg >> 1) & 1; @@ -152,20 +152,12 @@ static int bcm2835_sdhci_probe(struct platform_device *pdev) struct sdhci_pltfm_host *pltfm_host; int ret; - host = sdhci_pltfm_init(pdev, &bcm2835_sdhci_pdata, 0); + host = sdhci_pltfm_init(pdev, &bcm2835_sdhci_pdata, + sizeof(*bcm2835_host)); if (IS_ERR(host)) return PTR_ERR(host); - bcm2835_host = devm_kzalloc(&pdev->dev, sizeof(*bcm2835_host), - GFP_KERNEL); - if (!bcm2835_host) { - dev_err(mmc_dev(host->mmc), - "failed to allocate bcm2835_sdhci\n"); - return -ENOMEM; - } - pltfm_host = sdhci_priv(host); - pltfm_host->priv = bcm2835_host; pltfm_host->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(pltfm_host->clk)) { -- cgit v0.10.2 From 070e6d3ff5a69694fd354b705e04007e6630da48 Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Tue, 16 Feb 2016 21:08:20 +0800 Subject: mmc: sdhci-esdhc-imx: use sdhci_pltfm_init for private allocation Commit 0e748234293f ("mmc: sdhci: Add size for caller in init+register") allows users of sdhci_pltfm to allocate private space in calls to sdhci_pltfm_init+sdhci_pltfm_register. This patch migrates the sdhci esdhc-imx driver to this allocation. Signed-off-by: Jisheng Zhang Acked-by: Arnd Bergmann Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c index f25f292..2d300d8 100644 --- a/drivers/mmc/host/sdhci-esdhc-imx.c +++ b/drivers/mmc/host/sdhci-esdhc-imx.c @@ -260,7 +260,7 @@ static inline void esdhc_clrset_le(struct sdhci_host *host, u32 mask, u32 val, i static u32 esdhc_readl_le(struct sdhci_host *host, int reg) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct pltfm_imx_data *imx_data = pltfm_host->priv; + struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); u32 val = readl(host->ioaddr + reg); if (unlikely(reg == SDHCI_PRESENT_STATE)) { @@ -338,7 +338,7 @@ static u32 esdhc_readl_le(struct sdhci_host *host, int reg) static void esdhc_writel_le(struct sdhci_host *host, u32 val, int reg) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct pltfm_imx_data *imx_data = pltfm_host->priv; + struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); u32 data; if (unlikely(reg == SDHCI_INT_ENABLE || reg == SDHCI_SIGNAL_ENABLE)) { @@ -388,7 +388,7 @@ static void esdhc_writel_le(struct sdhci_host *host, u32 val, int reg) static u16 esdhc_readw_le(struct sdhci_host *host, int reg) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct pltfm_imx_data *imx_data = pltfm_host->priv; + struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); u16 ret = 0; u32 val; @@ -448,7 +448,7 @@ static u16 esdhc_readw_le(struct sdhci_host *host, int reg) static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct pltfm_imx_data *imx_data = pltfm_host->priv; + struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); u32 new_val = 0; switch (reg) { @@ -556,7 +556,7 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg) static void esdhc_writeb_le(struct sdhci_host *host, u8 val, int reg) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct pltfm_imx_data *imx_data = pltfm_host->priv; + struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); u32 new_val; u32 mask; @@ -633,7 +633,7 @@ static inline void esdhc_pltfm_set_clock(struct sdhci_host *host, unsigned int clock) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct pltfm_imx_data *imx_data = pltfm_host->priv; + struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); unsigned int host_clock = pltfm_host->clock; int pre_div = 2; int div = 1; @@ -692,7 +692,7 @@ static inline void esdhc_pltfm_set_clock(struct sdhci_host *host, static unsigned int esdhc_pltfm_get_ro(struct sdhci_host *host) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct pltfm_imx_data *imx_data = pltfm_host->priv; + struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); struct esdhc_platform_data *boarddata = &imx_data->boarddata; switch (boarddata->wp_type) { @@ -794,7 +794,7 @@ static int esdhc_change_pinstate(struct sdhci_host *host, unsigned int uhs) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct pltfm_imx_data *imx_data = pltfm_host->priv; + struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); struct pinctrl_state *pinctrl; dev_dbg(mmc_dev(host->mmc), "change pinctrl state for uhs %d\n", uhs); @@ -864,7 +864,7 @@ static void esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned timing) { u32 m; struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct pltfm_imx_data *imx_data = pltfm_host->priv; + struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); struct esdhc_platform_data *boarddata = &imx_data->boarddata; /* disable ddr mode and disable HS400 mode */ @@ -917,7 +917,7 @@ static void esdhc_reset(struct sdhci_host *host, u8 mask) static unsigned int esdhc_get_max_timeout_count(struct sdhci_host *host) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct pltfm_imx_data *imx_data = pltfm_host->priv; + struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); return esdhc_is_usdhc(imx_data) ? 1 << 28 : 1 << 27; } @@ -925,7 +925,7 @@ static unsigned int esdhc_get_max_timeout_count(struct sdhci_host *host) static void esdhc_set_timeout(struct sdhci_host *host, struct mmc_command *cmd) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct pltfm_imx_data *imx_data = pltfm_host->priv; + struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); /* use maximum timeout counter */ sdhci_writeb(host, esdhc_is_usdhc(imx_data) ? 0xF : 0xE, @@ -1100,21 +1100,17 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev) int err; struct pltfm_imx_data *imx_data; - host = sdhci_pltfm_init(pdev, &sdhci_esdhc_imx_pdata, 0); + host = sdhci_pltfm_init(pdev, &sdhci_esdhc_imx_pdata, + sizeof(*imx_data)); if (IS_ERR(host)) return PTR_ERR(host); pltfm_host = sdhci_priv(host); - imx_data = devm_kzalloc(&pdev->dev, sizeof(*imx_data), GFP_KERNEL); - if (!imx_data) { - err = -ENOMEM; - goto free_sdhci; - } + imx_data = sdhci_pltfm_priv(pltfm_host); imx_data->socdata = of_id ? of_id->data : (struct esdhc_soc_data *) pdev->id_entry->driver_data; - pltfm_host->priv = imx_data; imx_data->clk_ipg = devm_clk_get(&pdev->dev, "ipg"); if (IS_ERR(imx_data->clk_ipg)) { @@ -1241,7 +1237,7 @@ static int sdhci_esdhc_imx_remove(struct platform_device *pdev) { struct sdhci_host *host = platform_get_drvdata(pdev); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct pltfm_imx_data *imx_data = pltfm_host->priv; + struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); int dead = (readl(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff); pm_runtime_get_sync(&pdev->dev); @@ -1264,7 +1260,7 @@ static int sdhci_esdhc_runtime_suspend(struct device *dev) { struct sdhci_host *host = dev_get_drvdata(dev); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct pltfm_imx_data *imx_data = pltfm_host->priv; + struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); int ret; ret = sdhci_runtime_suspend_host(host); @@ -1282,7 +1278,7 @@ static int sdhci_esdhc_runtime_resume(struct device *dev) { struct sdhci_host *host = dev_get_drvdata(dev); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct pltfm_imx_data *imx_data = pltfm_host->priv; + struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); if (!sdhci_sdio_irq_enabled(host)) { clk_prepare_enable(imx_data->clk_per); -- cgit v0.10.2 From a50396a40fa796787eeef7143d17268dbecc79ef Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Tue, 16 Feb 2016 21:08:21 +0800 Subject: mmc: sdhci-msm: factorise sdhci_msm_pdata outisde of sdhci_msm_host There's no need to allocate one sdhci_msm_pdata for each sdhci_msm_host. This patch removes the sdhci_msm_pdata member from sdhci_msm_host and uses one static global sdhci_msm_pdata for all sdhci msm hosts. It also marks sdhci_msm_ops as const. Signed-off-by: Jisheng Zhang Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index 4695bee..ffac9b4 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -60,7 +60,6 @@ struct sdhci_msm_host { struct clk *pclk; /* SDHC peripheral bus clock */ struct clk *bus_clk; /* SDHC bus voter clock */ struct mmc_host *mmc; - struct sdhci_pltfm_data sdhci_msm_pdata; }; /* Platform specific tuning */ @@ -418,7 +417,7 @@ static const struct of_device_id sdhci_msm_dt_match[] = { MODULE_DEVICE_TABLE(of, sdhci_msm_dt_match); -static struct sdhci_ops sdhci_msm_ops = { +static const struct sdhci_ops sdhci_msm_ops = { .platform_execute_tuning = sdhci_msm_execute_tuning, .reset = sdhci_reset, .set_clock = sdhci_set_clock, @@ -426,6 +425,12 @@ static struct sdhci_ops sdhci_msm_ops = { .set_uhs_signaling = sdhci_set_uhs_signaling, }; +static const struct sdhci_pltfm_data sdhci_msm_pdata = { + .quirks = SDHCI_QUIRK_BROKEN_CARD_DETECTION | + SDHCI_QUIRK_SINGLE_POWER_WRITE, + .ops = &sdhci_msm_ops, +}; + static int sdhci_msm_probe(struct platform_device *pdev) { struct sdhci_host *host; @@ -441,8 +446,7 @@ static int sdhci_msm_probe(struct platform_device *pdev) if (!msm_host) return -ENOMEM; - msm_host->sdhci_msm_pdata.ops = &sdhci_msm_ops; - host = sdhci_pltfm_init(pdev, &msm_host->sdhci_msm_pdata, 0); + host = sdhci_pltfm_init(pdev, &sdhci_msm_pdata, 0); if (IS_ERR(host)) return PTR_ERR(host); @@ -522,9 +526,6 @@ static int sdhci_msm_probe(struct platform_device *pdev) /* Set HC_MODE_EN bit in HC_MODE register */ writel_relaxed(HC_MODE_EN, (msm_host->core_mem + CORE_HC_MODE)); - host->quirks |= SDHCI_QUIRK_BROKEN_CARD_DETECTION; - host->quirks |= SDHCI_QUIRK_SINGLE_POWER_WRITE; - host_version = readw_relaxed((host->ioaddr + SDHCI_HOST_VERSION)); dev_dbg(&pdev->dev, "Host Version: 0x%x Vendor Version 0x%x\n", host_version, ((host_version & SDHCI_VENDOR_VER_MASK) >> -- cgit v0.10.2 From 6f699531b66aad7233bef797265ac6ff21bb4f73 Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Tue, 16 Feb 2016 21:08:22 +0800 Subject: mmc: sdhci-msm: use sdhci_pltfm_init for private allocation Commit 0e748234293f ("mmc: sdhci: Add size for caller in init+register") allows users of sdhci_pltfm to allocate private space in calls to sdhci_pltfm_init+sdhci_pltfm_register. This patch migrates sdhci-msm to this allocation. Signed-off-by: Jisheng Zhang Acked-by: Arnd Bergmann Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index ffac9b4..0653fe7 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -442,16 +442,12 @@ static int sdhci_msm_probe(struct platform_device *pdev) u32 core_version, caps; u8 core_major; - msm_host = devm_kzalloc(&pdev->dev, sizeof(*msm_host), GFP_KERNEL); - if (!msm_host) - return -ENOMEM; - - host = sdhci_pltfm_init(pdev, &sdhci_msm_pdata, 0); + host = sdhci_pltfm_init(pdev, &sdhci_msm_pdata, sizeof(*msm_host)); if (IS_ERR(host)) return PTR_ERR(host); pltfm_host = sdhci_priv(host); - pltfm_host->priv = msm_host; + msm_host = sdhci_pltfm_priv(pltfm_host); msm_host->mmc = host->mmc; msm_host->pdev = pdev; @@ -571,16 +567,16 @@ static int sdhci_msm_remove(struct platform_device *pdev) { struct sdhci_host *host = platform_get_drvdata(pdev); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct sdhci_msm_host *msm_host = pltfm_host->priv; + struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); int dead = (readl_relaxed(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff); sdhci_remove_host(host, dead); - sdhci_pltfm_free(pdev); clk_disable_unprepare(msm_host->clk); clk_disable_unprepare(msm_host->pclk); if (!IS_ERR(msm_host->bus_clk)) clk_disable_unprepare(msm_host->bus_clk); + sdhci_pltfm_free(pdev); return 0; } -- cgit v0.10.2 From 0c7fe32e847ff20d1ae04b4b9f3e32f8551b4a6a Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Tue, 16 Feb 2016 21:08:23 +0800 Subject: mmc: sdhci-of-arasan: fix clk issue in sdhci_arasan_remove() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit sdhci_pltfm_unregister() could operate host's registers, it will cause problems if the clk is already disabled and unprepared. Fix this issue by moving the clk_disable_unprepare() call to the end of remove function. Signed-off-by: Jisheng Zhang Acked-by: Sören Brinkmann Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sdhci-of-arasan.c b/drivers/mmc/host/sdhci-of-arasan.c index 5d9fdb3..8b4f8f7 100644 --- a/drivers/mmc/host/sdhci-of-arasan.c +++ b/drivers/mmc/host/sdhci-of-arasan.c @@ -201,13 +201,16 @@ clk_dis_ahb: static int sdhci_arasan_remove(struct platform_device *pdev) { + int ret; struct sdhci_host *host = platform_get_drvdata(pdev); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_arasan_data *sdhci_arasan = pltfm_host->priv; + ret = sdhci_pltfm_unregister(pdev); + clk_disable_unprepare(sdhci_arasan->clk_ahb); - return sdhci_pltfm_unregister(pdev); + return ret; } static const struct of_device_id sdhci_arasan_of_match[] = { -- cgit v0.10.2 From 89211418cb7102cc98164af08ce1c87a40b10c0a Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Tue, 16 Feb 2016 21:08:24 +0800 Subject: mmc: sdhci-of-arasan: use sdhci_pltfm_init for private allocation Commit 0e748234293f ("mmc: sdhci: Add size for caller in init+register") allows users of sdhci_pltfm to allocate private space in calls to sdhci_pltfm_init+sdhci_pltfm_register. This patch migrates the sdhci-of-arasan driver to this allocation. Signed-off-by: Jisheng Zhang Acked-by: Arnd Bergmann Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sdhci-of-arasan.c b/drivers/mmc/host/sdhci-of-arasan.c index 8b4f8f7..1e4b5e0 100644 --- a/drivers/mmc/host/sdhci-of-arasan.c +++ b/drivers/mmc/host/sdhci-of-arasan.c @@ -81,7 +81,7 @@ static int sdhci_arasan_suspend(struct device *dev) struct platform_device *pdev = to_platform_device(dev); struct sdhci_host *host = platform_get_drvdata(pdev); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct sdhci_arasan_data *sdhci_arasan = pltfm_host->priv; + struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host); int ret; ret = sdhci_suspend_host(host); @@ -106,7 +106,7 @@ static int sdhci_arasan_resume(struct device *dev) struct platform_device *pdev = to_platform_device(dev); struct sdhci_host *host = platform_get_drvdata(pdev); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct sdhci_arasan_data *sdhci_arasan = pltfm_host->priv; + struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host); int ret; ret = clk_enable(sdhci_arasan->clk_ahb); @@ -137,10 +137,13 @@ static int sdhci_arasan_probe(struct platform_device *pdev) struct sdhci_pltfm_host *pltfm_host; struct sdhci_arasan_data *sdhci_arasan; - sdhci_arasan = devm_kzalloc(&pdev->dev, sizeof(*sdhci_arasan), - GFP_KERNEL); - if (!sdhci_arasan) - return -ENOMEM; + host = sdhci_pltfm_init(pdev, &sdhci_arasan_pdata, + sizeof(*sdhci_arasan)); + if (IS_ERR(host)) + return PTR_ERR(host); + + pltfm_host = sdhci_priv(host); + sdhci_arasan = sdhci_pltfm_priv(pltfm_host); sdhci_arasan->clk_ahb = devm_clk_get(&pdev->dev, "clk_ahb"); if (IS_ERR(sdhci_arasan->clk_ahb)) { @@ -166,15 +169,7 @@ static int sdhci_arasan_probe(struct platform_device *pdev) goto clk_dis_ahb; } - host = sdhci_pltfm_init(pdev, &sdhci_arasan_pdata, 0); - if (IS_ERR(host)) { - ret = PTR_ERR(host); - goto clk_disable_all; - } - sdhci_get_of_property(pdev); - pltfm_host = sdhci_priv(host); - pltfm_host->priv = sdhci_arasan; pltfm_host->clk = clk_xin; ret = mmc_of_parse(host->mmc); @@ -204,11 +199,12 @@ static int sdhci_arasan_remove(struct platform_device *pdev) int ret; struct sdhci_host *host = platform_get_drvdata(pdev); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct sdhci_arasan_data *sdhci_arasan = pltfm_host->priv; + struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host); + struct clk *clk_ahb = sdhci_arasan->clk_ahb; ret = sdhci_pltfm_unregister(pdev); - clk_disable_unprepare(sdhci_arasan->clk_ahb); + clk_disable_unprepare(clk_ahb); return ret; } -- cgit v0.10.2 From 10f1c1352cb9a0a52a60a681dc6b4822416937ac Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Tue, 16 Feb 2016 21:08:25 +0800 Subject: mmc: sdhci-of-at91: use sdhci_pltfm_init for private allocation Commit 0e748234293f ("mmc: sdhci: Add size for caller in init+register") allows users of sdhci_pltfm to allocate private space in calls to sdhci_pltfm_init+sdhci_pltfm_register. This patch migrates the sdhci-of-at91 driver to this allocation. Signed-off-by: Jisheng Zhang Acked-by: Arnd Bergmann Acked-by: Ludovic Desroches Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sdhci-of-at91.c b/drivers/mmc/host/sdhci-of-at91.c index 9cb86fb..35c02fc 100644 --- a/drivers/mmc/host/sdhci-of-at91.c +++ b/drivers/mmc/host/sdhci-of-at91.c @@ -58,7 +58,7 @@ static int sdhci_at91_runtime_suspend(struct device *dev) { struct sdhci_host *host = dev_get_drvdata(dev); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct sdhci_at91_priv *priv = pltfm_host->priv; + struct sdhci_at91_priv *priv = sdhci_pltfm_priv(pltfm_host); int ret; ret = sdhci_runtime_suspend_host(host); @@ -74,7 +74,7 @@ static int sdhci_at91_runtime_resume(struct device *dev) { struct sdhci_host *host = dev_get_drvdata(dev); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct sdhci_at91_priv *priv = pltfm_host->priv; + struct sdhci_at91_priv *priv = sdhci_pltfm_priv(pltfm_host); int ret; ret = clk_prepare_enable(priv->mainck); @@ -124,11 +124,12 @@ static int sdhci_at91_probe(struct platform_device *pdev) return -EINVAL; soc_data = match->data; - priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); - if (!priv) { - dev_err(&pdev->dev, "unable to allocate private data\n"); - return -ENOMEM; - } + host = sdhci_pltfm_init(pdev, soc_data, sizeof(*priv)); + if (IS_ERR(host)) + return PTR_ERR(host); + + pltfm_host = sdhci_priv(host); + priv = sdhci_pltfm_priv(pltfm_host); priv->mainck = devm_clk_get(&pdev->dev, "baseclk"); if (IS_ERR(priv->mainck)) { @@ -148,10 +149,6 @@ static int sdhci_at91_probe(struct platform_device *pdev) return PTR_ERR(priv->gck); } - host = sdhci_pltfm_init(pdev, soc_data, 0); - if (IS_ERR(host)) - return PTR_ERR(host); - /* * The mult clock is provided by as a generated clock by the PMC * controller. In order to set the rate of gck, we have to get the @@ -191,9 +188,6 @@ static int sdhci_at91_probe(struct platform_device *pdev) clk_prepare_enable(priv->mainck); clk_prepare_enable(priv->gck); - pltfm_host = sdhci_priv(host); - pltfm_host->priv = priv; - ret = mmc_of_parse(host->mmc); if (ret) goto clocks_disable_unprepare; @@ -231,7 +225,10 @@ static int sdhci_at91_remove(struct platform_device *pdev) { struct sdhci_host *host = platform_get_drvdata(pdev); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct sdhci_at91_priv *priv = pltfm_host->priv; + struct sdhci_at91_priv *priv = sdhci_pltfm_priv(pltfm_host); + struct clk *gck = priv->gck; + struct clk *hclock = priv->hclock; + struct clk *mainck = priv->mainck; pm_runtime_get_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); @@ -239,9 +236,9 @@ static int sdhci_at91_remove(struct platform_device *pdev) sdhci_pltfm_unregister(pdev); - clk_disable_unprepare(priv->gck); - clk_disable_unprepare(priv->hclock); - clk_disable_unprepare(priv->mainck); + clk_disable_unprepare(gck); + clk_disable_unprepare(hclock); + clk_disable_unprepare(mainck); return 0; } -- cgit v0.10.2 From 8605e7aeab1c2e6aee05a513d1294668c58afc84 Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Tue, 16 Feb 2016 21:08:26 +0800 Subject: mmc: sdhci-of-esdhc: use sdhci_pltfm_init for private allocation Commit 0e748234293f ("mmc: sdhci: Add size for caller in init+register") allows users of sdhci_pltfm to allocate private space in calls to sdhci_pltfm_init+sdhci_pltfm_register. This patch migrates the sdhci-of-esdhc driver to this allocation. Signed-off-by: Jisheng Zhang Acked-by: Arnd Bergmann Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c index 83b1226..3f34d35 100644 --- a/drivers/mmc/host/sdhci-of-esdhc.c +++ b/drivers/mmc/host/sdhci-of-esdhc.c @@ -49,7 +49,7 @@ static u32 esdhc_readl_fixup(struct sdhci_host *host, int spec_reg, u32 value) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct sdhci_esdhc *esdhc = pltfm_host->priv; + struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host); u32 ret; /* @@ -354,7 +354,7 @@ static void esdhc_le_writeb(struct sdhci_host *host, u8 val, int reg) static void esdhc_of_adma_workaround(struct sdhci_host *host, u32 intmask) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct sdhci_esdhc *esdhc = pltfm_host->priv; + struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host); bool applicable; dma_addr_t dmastart; dma_addr_t dmanow; @@ -404,7 +404,7 @@ static unsigned int esdhc_of_get_min_clock(struct sdhci_host *host) static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct sdhci_esdhc *esdhc = pltfm_host->priv; + struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host); int pre_div = 1; int div = 1; u32 temp; @@ -569,15 +569,12 @@ static void esdhc_init(struct platform_device *pdev, struct sdhci_host *host) u16 host_ver; pltfm_host = sdhci_priv(host); - esdhc = devm_kzalloc(&pdev->dev, sizeof(struct sdhci_esdhc), - GFP_KERNEL); + esdhc = sdhci_pltfm_priv(pltfm_host); host_ver = sdhci_readw(host, SDHCI_HOST_VERSION); esdhc->vendor_ver = (host_ver & SDHCI_VENDOR_VER_MASK) >> SDHCI_VENDOR_VER_SHIFT; esdhc->spec_ver = host_ver & SDHCI_SPEC_VER_MASK; - - pltfm_host->priv = esdhc; } static int sdhci_esdhc_probe(struct platform_device *pdev) @@ -591,9 +588,11 @@ static int sdhci_esdhc_probe(struct platform_device *pdev) np = pdev->dev.of_node; if (of_get_property(np, "little-endian", NULL)) - host = sdhci_pltfm_init(pdev, &sdhci_esdhc_le_pdata, 0); + host = sdhci_pltfm_init(pdev, &sdhci_esdhc_le_pdata, + sizeof(struct sdhci_esdhc)); else - host = sdhci_pltfm_init(pdev, &sdhci_esdhc_be_pdata, 0); + host = sdhci_pltfm_init(pdev, &sdhci_esdhc_be_pdata, + sizeof(struct sdhci_esdhc)); if (IS_ERR(host)) return PTR_ERR(host); @@ -603,7 +602,7 @@ static int sdhci_esdhc_probe(struct platform_device *pdev) sdhci_get_of_property(pdev); pltfm_host = sdhci_priv(host); - esdhc = pltfm_host->priv; + esdhc = sdhci_pltfm_priv(pltfm_host); if (esdhc->vendor_ver == VENDOR_V_22) host->quirks2 |= SDHCI_QUIRK2_HOST_NO_CMD23; -- cgit v0.10.2 From f599da406bd06190110b48b49658d0c911df2ad6 Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Tue, 16 Feb 2016 21:08:27 +0800 Subject: mmc: sdhci-pxav3: use sdhci_pltfm_init for private allocation Commit 0e748234293f ("mmc: sdhci: Add size for caller in init+register") allows users of sdhci_pltfm to allocate private space in calls to sdhci_pltfm_init+sdhci_pltfm_register. This patch migrates sdhci-pxav3 to this allocation. Signed-off-by: Jisheng Zhang Acked-by: Arnd Bergmann Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sdhci-pxav3.c b/drivers/mmc/host/sdhci-pxav3.c index c7f27fe..aca439d 100644 --- a/drivers/mmc/host/sdhci-pxav3.c +++ b/drivers/mmc/host/sdhci-pxav3.c @@ -132,7 +132,7 @@ static int armada_38x_quirks(struct platform_device *pdev, { struct device_node *np = pdev->dev.of_node; struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct sdhci_pxa *pxa = pltfm_host->priv; + struct sdhci_pxa *pxa = sdhci_pltfm_priv(pltfm_host); struct resource *res; host->quirks &= ~SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN; @@ -203,7 +203,7 @@ static void pxav3_reset(struct sdhci_host *host, u8 mask) static void pxav3_gen_init_74_clocks(struct sdhci_host *host, u8 power_mode) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct sdhci_pxa *pxa = pltfm_host->priv; + struct sdhci_pxa *pxa = sdhci_pltfm_priv(pltfm_host); u16 tmp; int count; @@ -252,7 +252,7 @@ static void pxav3_gen_init_74_clocks(struct sdhci_host *host, u8 power_mode) static void pxav3_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct sdhci_pxa *pxa = pltfm_host->priv; + struct sdhci_pxa *pxa = sdhci_pltfm_priv(pltfm_host); u16 ctrl_2; /* @@ -372,16 +372,12 @@ static int sdhci_pxav3_probe(struct platform_device *pdev) const struct of_device_id *match; int ret; - pxa = devm_kzalloc(&pdev->dev, sizeof(struct sdhci_pxa), GFP_KERNEL); - if (!pxa) - return -ENOMEM; - - host = sdhci_pltfm_init(pdev, &sdhci_pxav3_pdata, 0); + host = sdhci_pltfm_init(pdev, &sdhci_pxav3_pdata, sizeof(*pxa)); if (IS_ERR(host)) return PTR_ERR(host); pltfm_host = sdhci_priv(host); - pltfm_host->priv = pxa; + pxa = sdhci_pltfm_priv(pltfm_host); pxa->clk_io = devm_clk_get(dev, "io"); if (IS_ERR(pxa->clk_io)) @@ -488,7 +484,7 @@ 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; + struct sdhci_pxa *pxa = sdhci_pltfm_priv(pltfm_host); pm_runtime_get_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); @@ -537,7 +533,7 @@ 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; + struct sdhci_pxa *pxa = sdhci_pltfm_priv(pltfm_host); int ret; ret = sdhci_runtime_suspend_host(host); @@ -555,7 +551,7 @@ 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; + struct sdhci_pxa *pxa = sdhci_pltfm_priv(pltfm_host); clk_prepare_enable(pxa->clk_io); if (!IS_ERR(pxa->clk_core)) -- cgit v0.10.2 From 1531675269c8339866fc49fdb1d1142966aedabe Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Tue, 16 Feb 2016 21:08:28 +0800 Subject: mmc: sdhci-st: use sdhci_pltfm_init for private allocation Commit 0e748234293f ("mmc: sdhci: Add size for caller in init+register") allows users of sdhci_pltfm to allocate private space in calls to sdhci_pltfm_init+sdhci_pltfm_register. This patch migrates sdhci-st to this allocation. Signed-off-by: Jisheng Zhang Acked-by: Arnd Bergmann Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sdhci-st.c b/drivers/mmc/host/sdhci-st.c index 969c2b0..320e1c2 100644 --- a/drivers/mmc/host/sdhci-st.c +++ b/drivers/mmc/host/sdhci-st.c @@ -251,7 +251,7 @@ static int sdhci_st_set_dll_for_clock(struct sdhci_host *host) { int ret = 0; struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct st_mmc_platform_data *pdata = pltfm_host->priv; + struct st_mmc_platform_data *pdata = sdhci_pltfm_priv(pltfm_host); if (host->clock > CLK_TO_CHECK_DLL_LOCK) { st_mmcss_set_dll(pdata->top_ioaddr); @@ -265,7 +265,7 @@ static void sdhci_st_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct st_mmc_platform_data *pdata = pltfm_host->priv; + struct st_mmc_platform_data *pdata = sdhci_pltfm_priv(pltfm_host); u16 ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2); int ret = 0; @@ -357,10 +357,7 @@ static int sdhci_st_probe(struct platform_device *pdev) int ret = 0; u16 host_version; struct resource *res; - - pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); - if (!pdata) - return -ENOMEM; + struct reset_control *rstc; clk = devm_clk_get(&pdev->dev, "mmc"); if (IS_ERR(clk)) { @@ -368,19 +365,23 @@ static int sdhci_st_probe(struct platform_device *pdev) return PTR_ERR(clk); } - pdata->rstc = devm_reset_control_get(&pdev->dev, NULL); - if (IS_ERR(pdata->rstc)) - pdata->rstc = NULL; + rstc = devm_reset_control_get(&pdev->dev, NULL); + if (IS_ERR(rstc)) + rstc = NULL; else - reset_control_deassert(pdata->rstc); + reset_control_deassert(rstc); - host = sdhci_pltfm_init(pdev, &sdhci_st_pdata, 0); + host = sdhci_pltfm_init(pdev, &sdhci_st_pdata, sizeof(*pdata)); if (IS_ERR(host)) { dev_err(&pdev->dev, "Failed sdhci_pltfm_init\n"); ret = PTR_ERR(host); goto err_pltfm_init; } + pltfm_host = sdhci_priv(host); + pdata = sdhci_pltfm_priv(pltfm_host); + pdata->rstc = rstc; + ret = mmc_of_parse(host->mmc); if (ret) { dev_err(&pdev->dev, "Failed mmc_of_parse\n"); @@ -398,8 +399,6 @@ static int sdhci_st_probe(struct platform_device *pdev) pdata->top_ioaddr = NULL; } - pltfm_host = sdhci_priv(host); - pltfm_host->priv = pdata; pltfm_host->clk = clk; /* Configure the Arasan HC inside the flashSS */ @@ -427,8 +426,8 @@ err_out: err_of: sdhci_pltfm_free(pdev); err_pltfm_init: - if (pdata->rstc) - reset_control_assert(pdata->rstc); + if (rstc) + reset_control_assert(rstc); return ret; } @@ -437,13 +436,14 @@ static int sdhci_st_remove(struct platform_device *pdev) { struct sdhci_host *host = platform_get_drvdata(pdev); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct st_mmc_platform_data *pdata = pltfm_host->priv; + struct st_mmc_platform_data *pdata = sdhci_pltfm_priv(pltfm_host); + struct reset_control *rstc = pdata->rstc; int ret; ret = sdhci_pltfm_unregister(pdev); - if (pdata->rstc) - reset_control_assert(pdata->rstc); + if (rstc) + reset_control_assert(rstc); return ret; } @@ -453,7 +453,7 @@ static int sdhci_st_suspend(struct device *dev) { struct sdhci_host *host = dev_get_drvdata(dev); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct st_mmc_platform_data *pdata = pltfm_host->priv; + struct st_mmc_platform_data *pdata = sdhci_pltfm_priv(pltfm_host); int ret = sdhci_suspend_host(host); if (ret) @@ -471,7 +471,7 @@ static int sdhci_st_resume(struct device *dev) { struct sdhci_host *host = dev_get_drvdata(dev); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct st_mmc_platform_data *pdata = pltfm_host->priv; + struct st_mmc_platform_data *pdata = sdhci_pltfm_priv(pltfm_host); struct device_node *np = dev->of_node; clk_prepare_enable(pltfm_host->clk); -- cgit v0.10.2 From 0734e79c0552f944cee8bf4f12fd849eae235554 Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Tue, 16 Feb 2016 21:08:29 +0800 Subject: mmc: sdhci-tegra: use sdhci_pltfm_init for private allocation Commit 0e748234293f ("mmc: sdhci: Add size for caller in init+register") allows users of sdhci_pltfm to allocate private space in calls to sdhci_pltfm_init+sdhci_pltfm_register. This patch migrates sdhci-tegra to this allocation. Signed-off-by: Jisheng Zhang Acked-by: Arnd Bergmann Tested-by: Thierry Reding Acked-by: Thierry Reding Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c index 83c4bf7..2c3c57b 100644 --- a/drivers/mmc/host/sdhci-tegra.c +++ b/drivers/mmc/host/sdhci-tegra.c @@ -63,7 +63,7 @@ struct sdhci_tegra { static u16 tegra_sdhci_readw(struct sdhci_host *host, int reg) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct sdhci_tegra *tegra_host = pltfm_host->priv; + struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); const struct sdhci_tegra_soc_data *soc_data = tegra_host->soc_data; if (unlikely((soc_data->nvquirks & NVQUIRK_FORCE_SDHCI_SPEC_200) && @@ -99,7 +99,7 @@ static void tegra_sdhci_writew(struct sdhci_host *host, u16 val, int reg) static void tegra_sdhci_writel(struct sdhci_host *host, u32 val, int reg) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct sdhci_tegra *tegra_host = pltfm_host->priv; + struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); const struct sdhci_tegra_soc_data *soc_data = tegra_host->soc_data; /* Seems like we're getting spurious timeout and crc errors, so @@ -131,7 +131,7 @@ static unsigned int tegra_sdhci_get_ro(struct sdhci_host *host) static void tegra_sdhci_reset(struct sdhci_host *host, u8 mask) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct sdhci_tegra *tegra_host = pltfm_host->priv; + struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); const struct sdhci_tegra_soc_data *soc_data = tegra_host->soc_data; u32 misc_ctrl, clk_ctrl; @@ -184,7 +184,7 @@ static void tegra_sdhci_set_bus_width(struct sdhci_host *host, int bus_width) static void tegra_sdhci_set_clock(struct sdhci_host *host, unsigned int clock) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct sdhci_tegra *tegra_host = pltfm_host->priv; + struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); unsigned long host_clk; if (!clock) @@ -201,7 +201,7 @@ static void tegra_sdhci_set_uhs_signaling(struct sdhci_host *host, unsigned timing) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct sdhci_tegra *tegra_host = pltfm_host->priv; + struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); if (timing == MMC_TIMING_UHS_DDR50) tegra_host->ddr_signaling = true; @@ -380,20 +380,14 @@ static int sdhci_tegra_probe(struct platform_device *pdev) return -EINVAL; soc_data = match->data; - host = sdhci_pltfm_init(pdev, soc_data->pdata, 0); + host = sdhci_pltfm_init(pdev, soc_data->pdata, sizeof(*tegra_host)); if (IS_ERR(host)) return PTR_ERR(host); pltfm_host = sdhci_priv(host); - tegra_host = devm_kzalloc(&pdev->dev, sizeof(*tegra_host), GFP_KERNEL); - if (!tegra_host) { - dev_err(mmc_dev(host->mmc), "failed to allocate tegra_host\n"); - rc = -ENOMEM; - goto err_alloc_tegra_host; - } + tegra_host = sdhci_pltfm_priv(pltfm_host); tegra_host->ddr_signaling = false; tegra_host->soc_data = soc_data; - pltfm_host->priv = tegra_host; rc = mmc_of_parse(host->mmc); if (rc) @@ -429,7 +423,6 @@ err_add_host: err_clk_get: err_power_req: err_parse_dt: -err_alloc_tegra_host: sdhci_pltfm_free(pdev); return rc; } -- cgit v0.10.2 From dc99471418549634ac072578233589c8a92249fb Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Tue, 16 Feb 2016 21:08:30 +0800 Subject: mmc: sdhci-pxav2: remove unnecessary assignment of pltfm_host->priv The sdhci_pltfm_init() function has initialized the priv member as NULL, so there's no need to do it again. Signed-off-by: Jisheng Zhang Acked-by: Arnd Bergmann Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sdhci-pxav2.c b/drivers/mmc/host/sdhci-pxav2.c index beffd86..1d8dd35 100644 --- a/drivers/mmc/host/sdhci-pxav2.c +++ b/drivers/mmc/host/sdhci-pxav2.c @@ -177,7 +177,6 @@ static int sdhci_pxav2_probe(struct platform_device *pdev) return PTR_ERR(host); pltfm_host = sdhci_priv(host); - pltfm_host->priv = NULL; clk = clk_get(dev, "PXA-SDHCLK"); if (IS_ERR(clk)) { -- cgit v0.10.2 From 887171c730752e26218ed210717df60173d58426 Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Tue, 16 Feb 2016 21:08:31 +0800 Subject: mmc: sdhci-pltfm: remove priv variable from sdhci_pltfm_host Now all clients migration to use sdhci_pltfm_init for private allocation is done and there's no users of the priv variable, so we can remove it from the sdhci_pltfm_host structure. Signed-off-by: Jisheng Zhang Acked-by: Arnd Bergmann Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sdhci-pltfm.h b/drivers/mmc/host/sdhci-pltfm.h index 04bc248..d38053b 100644 --- a/drivers/mmc/host/sdhci-pltfm.h +++ b/drivers/mmc/host/sdhci-pltfm.h @@ -23,7 +23,6 @@ struct sdhci_pltfm_data { struct sdhci_pltfm_host { struct clk *clk; - void *priv; /* to handle quirks across io-accessor calls */ /* migrate from sdhci_of_host */ unsigned int clock; -- cgit v0.10.2 From 7bf037d6ac4768e228e337afd7b6c6d98f947f9f Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Fri, 26 Feb 2016 09:34:17 +0000 Subject: mmc: tegra: Disable UHS-I modes for tegra114 SD card support for Tegra114 started failing after commit a8e326a911d3 ("mmc: tegra: implement module external clock change") was merged. This commit was part of a series to enable UHS-I modes for Tegra. To workaround this problem for now, disable UHS-I modes for Tegra114 by separating the soc data structures for Tegra114 and Tegra124 so that UHS-I is still enabled for Tegra124 but not Tegra114. Fixes: a8e326a911d3 ("mmc: tegra: implement module external clock change") Signed-off-by: Jon Hunter Reviewed-by: Lucas Stach Acked-by: Thierry Reding Acked-by: Adrian Hunter Cc: stable@vger.kernel.org Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c index 2c3c57b..8993db3 100644 --- a/drivers/mmc/host/sdhci-tegra.c +++ b/drivers/mmc/host/sdhci-tegra.c @@ -147,10 +147,16 @@ static void tegra_sdhci_reset(struct sdhci_host *host, u8 mask) /* Advertise UHS modes as supported by host */ if (soc_data->nvquirks & NVQUIRK_ENABLE_SDR50) misc_ctrl |= SDHCI_MISC_CTRL_ENABLE_SDR50; + else + misc_ctrl &= ~SDHCI_MISC_CTRL_ENABLE_SDR50; if (soc_data->nvquirks & NVQUIRK_ENABLE_DDR50) misc_ctrl |= SDHCI_MISC_CTRL_ENABLE_DDR50; + else + misc_ctrl &= ~SDHCI_MISC_CTRL_ENABLE_DDR50; if (soc_data->nvquirks & NVQUIRK_ENABLE_SDR104) misc_ctrl |= SDHCI_MISC_CTRL_ENABLE_SDR104; + else + misc_ctrl &= ~SDHCI_MISC_CTRL_ENABLE_SDR104; sdhci_writel(host, misc_ctrl, SDHCI_TEGRA_VENDOR_MISC_CTRL); clk_ctrl = sdhci_readl(host, SDHCI_TEGRA_VENDOR_CLOCK_CTRL); @@ -335,6 +341,10 @@ static const struct sdhci_pltfm_data sdhci_tegra114_pdata = { static const struct sdhci_tegra_soc_data soc_data_tegra114 = { .pdata = &sdhci_tegra114_pdata, +}; + +static const struct sdhci_tegra_soc_data soc_data_tegra124 = { + .pdata = &sdhci_tegra114_pdata, .nvquirks = NVQUIRK_ENABLE_SDR50 | NVQUIRK_ENABLE_DDR50 | NVQUIRK_ENABLE_SDR104, @@ -357,7 +367,7 @@ static const struct sdhci_tegra_soc_data soc_data_tegra210 = { static const struct of_device_id sdhci_tegra_dt_match[] = { { .compatible = "nvidia,tegra210-sdhci", .data = &soc_data_tegra210 }, - { .compatible = "nvidia,tegra124-sdhci", .data = &soc_data_tegra114 }, + { .compatible = "nvidia,tegra124-sdhci", .data = &soc_data_tegra124 }, { .compatible = "nvidia,tegra114-sdhci", .data = &soc_data_tegra114 }, { .compatible = "nvidia,tegra30-sdhci", .data = &soc_data_tegra30 }, { .compatible = "nvidia,tegra20-sdhci", .data = &soc_data_tegra20 }, -- cgit v0.10.2 From bcdc9f260bdce09913db1464be9817170d51044a Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Tue, 16 Feb 2016 13:06:41 +0900 Subject: mmc: mmc_spi: Add Card Detect comments and fix CD GPIO case This patch fixes the MMC SPI driver from doing polling card detect when a CD GPIO that supports interrupts is specified using the gpios DT property. Without this patch the DT node below results in the following output: spi_gpio: spi-gpio { /* SD2 @ CN12 */ compatible = "spi-gpio"; #address-cells = <1>; #size-cells = <0>; gpio-sck = <&gpio6 16 GPIO_ACTIVE_HIGH>; gpio-mosi = <&gpio6 17 GPIO_ACTIVE_HIGH>; gpio-miso = <&gpio6 18 GPIO_ACTIVE_HIGH>; num-chipselects = <1>; cs-gpios = <&gpio6 21 GPIO_ACTIVE_LOW>; status = "okay"; spi@0 { compatible = "mmc-spi-slot"; reg = <0>; voltage-ranges = <3200 3400>; spi-max-frequency = <25000000>; gpios = <&gpio6 22 GPIO_ACTIVE_LOW>; /* CD */ }; }; # dmesg | grep mmc mmc_spi spi32766.0: SD/MMC host mmc0, no WP, no poweroff, cd polling mmc0: host does not support reading read-only switch, assuming write-enable mmc0: new SDHC card on SPI mmcblk0: mmc0:0000 SU04G 3.69 GiB mmcblk0: p1 With this patch applied the "cd polling" portion above disappears. Signed-off-by: Magnus Damm Cc: stable@vger.kernel.org # v3.18+ Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/mmc_spi.c b/drivers/mmc/host/mmc_spi.c index 3446097..e77d79c 100644 --- a/drivers/mmc/host/mmc_spi.c +++ b/drivers/mmc/host/mmc_spi.c @@ -1442,6 +1442,12 @@ static int mmc_spi_probe(struct spi_device *spi) host->pdata->cd_debounce); if (status != 0) goto fail_add_host; + + /* The platform has a CD GPIO signal that may support + * interrupts, so let mmc_gpiod_request_cd_irq() decide + * if polling is needed or not. + */ + mmc->caps &= ~MMC_CAP_NEEDS_POLL; mmc_gpiod_request_cd_irq(mmc); } -- cgit v0.10.2 From 3491b69045b1926a198ba70dc1296ca253f2fbdd Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Mon, 29 Feb 2016 21:56:24 +0100 Subject: mmc: tegra: properly disable card clock The new code to do the clock rate setting externally to the SDMMC module has a shortcut to not propagate changes with a 0 rate to the CAR by simply bailing out. This breaks proper cutting of the card clock. Fix it by directly calling the correct sdhci function. Fixes: a8e326a911d3 "mmc: tegra: implement module external clock change" Signed-off-by: Lucas Stach Acked-by: Adrian Hunter Cc: stable@vger.kernel.org Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c index 8993db3..79c2a2b 100644 --- a/drivers/mmc/host/sdhci-tegra.c +++ b/drivers/mmc/host/sdhci-tegra.c @@ -194,7 +194,7 @@ static void tegra_sdhci_set_clock(struct sdhci_host *host, unsigned int clock) unsigned long host_clk; if (!clock) - return; + return sdhci_set_clock(host, clock); host_clk = tegra_host->ddr_signaling ? clock * 2 : clock; clk_set_rate(pltfm_host->clk, host_clk); -- cgit v0.10.2 From 49312c1f3287b052af518bdfe06dbb317defc9d4 Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Wed, 24 Feb 2016 11:39:33 +0900 Subject: mmc: sh_mmcif, tmio: Use ARCH_RENESAS Make use of ARCH_RENESAS in place of ARCH_SHMOBILE. This is part of an ongoing process to migrate from ARCH_SHMOBILE to ARCH_RENESAS the motivation for which being that RENESAS seems to be a more appropriate name than SHMOBILE for the majority of Renesas ARM based SoCs. Signed-off-by: Simon Horman Acked-by: Geert Uytterhoeven Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index d9a9d92..04feea8 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -561,7 +561,7 @@ config MMC_TMIO config MMC_SDHI tristate "SH-Mobile SDHI SD/SDIO controller support" depends on SUPERH || ARM || ARM64 - depends on SUPERH || ARCH_SHMOBILE || COMPILE_TEST + depends on SUPERH || ARCH_RENESAS || COMPILE_TEST select MMC_TMIO_CORE help This provides support for the SDHI SD/SDIO controller found in @@ -674,7 +674,7 @@ config MMC_DW_ROCKCHIP config MMC_SH_MMCIF tristate "SuperH Internal MMCIF support" depends on HAS_DMA - depends on SUPERH || ARCH_SHMOBILE || COMPILE_TEST + depends on SUPERH || ARCH_RENESAS || COMPILE_TEST help This selects the MMC Host Interface controller (MMCIF). -- cgit v0.10.2 From f9bab9d2b169a9e80c1a710b19d792974787e899 Mon Sep 17 00:00:00 2001 From: Nicolas Boichat Date: Thu, 3 Mar 2016 18:19:44 +0800 Subject: mmc: mediatek: Change signal voltage error to dev_dbg() In commit ceae98f20e36 ("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: Nicolas Boichat Reviewed-by: Douglas Anderson Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c index f01972e..07809f4 100644 --- a/drivers/mmc/host/mtk-sd.c +++ b/drivers/mmc/host/mtk-sd.c @@ -1038,7 +1038,7 @@ static int msdc_ops_switch_volt(struct mmc_host *mmc, struct mmc_ios *ios) ret = regulator_set_voltage(mmc->supply.vqmmc, min_uv, max_uv); if (ret) { - dev_err(host->dev, + dev_dbg(host->dev, "Regulator set error %d: %d - %d\n", ret, min_uv, max_uv); } else { -- cgit v0.10.2 From fac49ce575cd86dc5e91049f274750923dfb6840 Mon Sep 17 00:00:00 2001 From: Nicolas Boichat Date: Thu, 3 Mar 2016 18:19:45 +0800 Subject: mmc: mediatek: Use mmc_regulator_set_vqmmc in start_signal_voltage_switch We've introduced a new helper in the MMC core: mmc_regulator_set_vqmmc(). Let's use this in mtk-sd. Using this new helper has some advantages: 1. We get the mmc_regulator_set_vqmmc() behavior of trying to match VQMMC and VMMC when the signal voltage is 3.3V. This ensures max compatibility. 2. We get rid of a few more warnings when probing unsupported voltages. 3. We get rid of some non-mediatek specific code in mtk-sd. Signed-off-by: Nicolas Boichat Reviewed-by: Douglas Anderson Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c index 07809f4..b17f30d 100644 --- a/drivers/mmc/host/mtk-sd.c +++ b/drivers/mmc/host/mtk-sd.c @@ -1021,26 +1021,19 @@ static void msdc_set_buswidth(struct msdc_host *host, u32 width) static int msdc_ops_switch_volt(struct mmc_host *mmc, struct mmc_ios *ios) { struct msdc_host *host = mmc_priv(mmc); - int min_uv, max_uv; int ret = 0; if (!IS_ERR(mmc->supply.vqmmc)) { - if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) { - min_uv = 3300000; - max_uv = 3300000; - } else if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_180) { - min_uv = 1800000; - max_uv = 1800000; - } else { + if (ios->signal_voltage != MMC_SIGNAL_VOLTAGE_330 && + ios->signal_voltage != MMC_SIGNAL_VOLTAGE_180) { dev_err(host->dev, "Unsupported signal voltage!\n"); return -EINVAL; } - ret = regulator_set_voltage(mmc->supply.vqmmc, min_uv, max_uv); + ret = mmc_regulator_set_vqmmc(mmc, ios); if (ret) { - dev_dbg(host->dev, - "Regulator set error %d: %d - %d\n", - ret, min_uv, max_uv); + dev_dbg(host->dev, "Regulator set error %d (%d)\n", + ret, ios->signal_voltage); } else { /* Apply different pinctrl settings for different signal voltage */ if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_180) -- cgit v0.10.2 From e5c63d91cdf6a0d02f080bc8ab5b75c6e280a046 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Mon, 29 Feb 2016 21:56:25 +0100 Subject: mmc: tegra: implement memcomp pad calibration The Tegra30+ SDMMC module has memcomp pads that are used to automatically find and set the correct drive strength settings to the sdmmc pads. The calibration needs to be manually kicked off when the card signal voltage is changed, after the card clock is supplied again. Signed-off-by: Lucas Stach Acked-by: Adrian Hunter [Ulf: Rebased to fix a trivial compile error] Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c index 79c2a2b..f8c4762 100644 --- a/drivers/mmc/host/sdhci-tegra.c +++ b/drivers/mmc/host/sdhci-tegra.c @@ -12,6 +12,7 @@ * */ +#include #include #include #include @@ -42,12 +43,17 @@ #define SDHCI_MISC_CTRL_ENABLE_SDHCI_SPEC_300 0x20 #define SDHCI_MISC_CTRL_ENABLE_DDR50 0x200 +#define SDHCI_TEGRA_AUTO_CAL_CONFIG 0x1e4 +#define SDHCI_AUTO_CAL_START BIT(31) +#define SDHCI_AUTO_CAL_ENABLE BIT(29) + #define NVQUIRK_FORCE_SDHCI_SPEC_200 BIT(0) #define NVQUIRK_ENABLE_BLOCK_GAP_DET BIT(1) #define NVQUIRK_ENABLE_SDHCI_SPEC_300 BIT(2) #define NVQUIRK_ENABLE_SDR50 BIT(3) #define NVQUIRK_ENABLE_SDR104 BIT(4) #define NVQUIRK_ENABLE_DDR50 BIT(5) +#define NVQUIRK_HAS_PADCALIB BIT(6) struct sdhci_tegra_soc_data { const struct sdhci_pltfm_data *pdata; @@ -58,6 +64,7 @@ struct sdhci_tegra { const struct sdhci_tegra_soc_data *soc_data; struct gpio_desc *power_gpio; bool ddr_signaling; + bool pad_calib_required; }; static u16 tegra_sdhci_readw(struct sdhci_host *host, int reg) @@ -165,6 +172,9 @@ static void tegra_sdhci_reset(struct sdhci_host *host, u8 mask) clk_ctrl |= SDHCI_CLOCK_CTRL_SDR50_TUNING_OVERRIDE; sdhci_writel(host, clk_ctrl, SDHCI_TEGRA_VENDOR_CLOCK_CTRL); + if (soc_data->nvquirks & NVQUIRK_HAS_PADCALIB) + tegra_host->pad_calib_required = true; + tegra_host->ddr_signaling = false; } @@ -187,6 +197,17 @@ static void tegra_sdhci_set_bus_width(struct sdhci_host *host, int bus_width) sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); } +static void tegra_sdhci_pad_autocalib(struct sdhci_host *host) +{ + u32 val; + + mdelay(1); + + val = sdhci_readl(host, SDHCI_TEGRA_AUTO_CAL_CONFIG); + val |= SDHCI_AUTO_CAL_ENABLE | SDHCI_AUTO_CAL_START; + sdhci_writel(host,val, SDHCI_TEGRA_AUTO_CAL_CONFIG); +} + static void tegra_sdhci_set_clock(struct sdhci_host *host, unsigned int clock) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); @@ -200,7 +221,12 @@ static void tegra_sdhci_set_clock(struct sdhci_host *host, unsigned int clock) clk_set_rate(pltfm_host->clk, host_clk); host->max_clk = clk_get_rate(pltfm_host->clk); - return sdhci_set_clock(host, clock); + sdhci_set_clock(host, clock); + + if (tegra_host->pad_calib_required) { + tegra_sdhci_pad_autocalib(host); + tegra_host->pad_calib_required = false; + } } static void tegra_sdhci_set_uhs_signaling(struct sdhci_host *host, @@ -270,6 +296,16 @@ static int tegra_sdhci_execute_tuning(struct sdhci_host *host, u32 opcode) return mmc_send_tuning(host->mmc, opcode, NULL); } +static void tegra_sdhci_voltage_switch(struct sdhci_host *host) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); + const struct sdhci_tegra_soc_data *soc_data = tegra_host->soc_data; + + if (soc_data->nvquirks & NVQUIRK_HAS_PADCALIB) + tegra_host->pad_calib_required = true; +} + static const struct sdhci_ops tegra_sdhci_ops = { .get_ro = tegra_sdhci_get_ro, .read_w = tegra_sdhci_readw, @@ -279,6 +315,7 @@ static const struct sdhci_ops tegra_sdhci_ops = { .reset = tegra_sdhci_reset, .platform_execute_tuning = tegra_sdhci_execute_tuning, .set_uhs_signaling = tegra_sdhci_set_uhs_signaling, + .voltage_switch = tegra_sdhci_voltage_switch, .get_max_clock = tegra_sdhci_get_max_clock, }; @@ -312,7 +349,8 @@ static const struct sdhci_tegra_soc_data soc_data_tegra30 = { .pdata = &sdhci_tegra30_pdata, .nvquirks = NVQUIRK_ENABLE_SDHCI_SPEC_300 | NVQUIRK_ENABLE_SDR50 | - NVQUIRK_ENABLE_SDR104, + NVQUIRK_ENABLE_SDR104 | + NVQUIRK_HAS_PADCALIB, }; static const struct sdhci_ops tegra114_sdhci_ops = { @@ -325,6 +363,7 @@ static const struct sdhci_ops tegra114_sdhci_ops = { .reset = tegra_sdhci_reset, .platform_execute_tuning = tegra_sdhci_execute_tuning, .set_uhs_signaling = tegra_sdhci_set_uhs_signaling, + .voltage_switch = tegra_sdhci_voltage_switch, .get_max_clock = tegra_sdhci_get_max_clock, }; @@ -347,7 +386,8 @@ static const struct sdhci_tegra_soc_data soc_data_tegra124 = { .pdata = &sdhci_tegra114_pdata, .nvquirks = NVQUIRK_ENABLE_SDR50 | NVQUIRK_ENABLE_DDR50 | - NVQUIRK_ENABLE_SDR104, + NVQUIRK_ENABLE_SDR104 | + NVQUIRK_HAS_PADCALIB, }; static const struct sdhci_pltfm_data sdhci_tegra210_pdata = { @@ -397,6 +437,7 @@ static int sdhci_tegra_probe(struct platform_device *pdev) tegra_host = sdhci_pltfm_priv(pltfm_host); tegra_host->ddr_signaling = false; + tegra_host->pad_calib_required = false; tegra_host->soc_data = soc_data; rc = mmc_of_parse(host->mmc); -- cgit v0.10.2 From 70cce2af73f1a37b00e8c8147325c8aca9d58ebe Mon Sep 17 00:00:00 2001 From: Philip Elcan Date: Thu, 3 Mar 2016 11:38:46 -0500 Subject: mmc: sdhci-acpi: add QCOM controllers This adds the HIDs for Qualcomm Technologies Inc SDHC controllers: QCOM8051: non-removable device that does not support 1.8v QCOM8052: non-removable device that does support 1.8v Signed-off-by: Philip Elcan Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sdhci-acpi.c b/drivers/mmc/host/sdhci-acpi.c index 195ff08..4e94684 100644 --- a/drivers/mmc/host/sdhci-acpi.c +++ b/drivers/mmc/host/sdhci-acpi.c @@ -264,6 +264,17 @@ static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sd = { .probe_slot = sdhci_acpi_sd_probe_slot, }; +static const struct sdhci_acpi_slot sdhci_acpi_slot_qcom_sd_3v = { + .quirks = SDHCI_QUIRK_BROKEN_CARD_DETECTION, + .quirks2 = SDHCI_QUIRK2_NO_1_8_V, + .caps = MMC_CAP_NONREMOVABLE, +}; + +static const struct sdhci_acpi_slot sdhci_acpi_slot_qcom_sd = { + .quirks = SDHCI_QUIRK_BROKEN_CARD_DETECTION, + .caps = MMC_CAP_NONREMOVABLE, +}; + struct sdhci_acpi_uid_slot { const char *hid; const char *uid; @@ -284,6 +295,8 @@ static const struct sdhci_acpi_uid_slot sdhci_acpi_uids[] = { { "INT344D" , NULL, &sdhci_acpi_slot_int_sdio }, { "PNP0FFF" , "3" , &sdhci_acpi_slot_int_sd }, { "PNP0D40" }, + { "QCOM8051", NULL, &sdhci_acpi_slot_qcom_sd_3v }, + { "QCOM8052", NULL, &sdhci_acpi_slot_qcom_sd }, { }, }; @@ -298,6 +311,8 @@ static const struct acpi_device_id sdhci_acpi_ids[] = { { "INT3436" }, { "INT344D" }, { "PNP0D40" }, + { "QCOM8051" }, + { "QCOM8052" }, { }, }; MODULE_DEVICE_TABLE(acpi, sdhci_acpi_ids); -- cgit v0.10.2 From 0743bbf0bc9028f9057703940e0fa96215949a38 Mon Sep 17 00:00:00 2001 From: Wang Hongcheng Date: Mon, 14 Mar 2016 13:44:33 +0800 Subject: mmc: mmci: Remove unnecessary header file The header file asm/sizes.h is unnecessary, let's remove it. This also allows to compile under X86 arch. Signed-off-by: Wang Hongcheng Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 0d6ca41..2e6c968 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -40,7 +40,6 @@ #include #include -#include #include "mmci.h" #include "mmci_qcom_dml.h" -- cgit v0.10.2 From 995136247915c5cee633d55ba23f6eebf67aa567 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Mon, 7 Mar 2016 13:33:55 +0200 Subject: mmc: sdhci: Fix override of timeout clk wrt max_busy_timeout Normally the timeout clock frequency is read from the capabilities register. It is also possible to set the value prior to calling sdhci_add_host() in which case that value will override the capabilities register value. However that was being done after calculating max_busy_timeout so that max_busy_timeout was being calculated using the wrong value of timeout_clk. Fix that by moving the override before max_busy_timeout is calculated. The result is that the max_busy_timeout and max_discard increase for BSW devices so that, for example, the time for mkfs.ext4 on a 64GB eMMC drops from about 1 minute 40 seconds to about 20 seconds. Note, in the future, the capabilities setting will be tidied up and this override won't be used anymore. However this fix is needed for stable. Signed-off-by: Adrian Hunter Cc: stable@vger.kernel.org # v3.18+ Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 03fbb36..4ae394e 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -3016,14 +3016,14 @@ int sdhci_add_host(struct sdhci_host *host) if (caps[0] & SDHCI_TIMEOUT_CLK_UNIT) host->timeout_clk *= 1000; + if (override_timeout_clk) + host->timeout_clk = override_timeout_clk; + mmc->max_busy_timeout = host->ops->get_max_timeout_count ? host->ops->get_max_timeout_count(host) : 1 << 27; mmc->max_busy_timeout /= host->timeout_clk; } - if (override_timeout_clk) - host->timeout_clk = override_timeout_clk; - mmc->caps |= MMC_CAP_SDIO_IRQ | MMC_CAP_ERASE | MMC_CAP_CMD23; mmc->caps2 |= MMC_CAP2_SDIO_IRQ_NOTHREAD; -- cgit v0.10.2 From 18e8d812dd93e90e470c62938291f7f9a4bed6f0 Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Mon, 7 Mar 2016 23:38:42 +0800 Subject: Documentation: bindings: add description of phy for sdhci-of-arasan This patch adds phys and phy-names for sdhci-of-arasan as required properties for arasan,sdhci-5.1, and details the example as well. Signed-off-by: Shawn Lin Acked-by: Rob Herring Signed-off-by: Ulf Hansson diff --git a/Documentation/devicetree/bindings/mmc/arasan,sdhci.txt b/Documentation/devicetree/bindings/mmc/arasan,sdhci.txt index da541c3..31b35c3 100644 --- a/Documentation/devicetree/bindings/mmc/arasan,sdhci.txt +++ b/Documentation/devicetree/bindings/mmc/arasan,sdhci.txt @@ -1,11 +1,12 @@ Device Tree Bindings for the Arasan SDHCI Controller - The bindings follow the mmc[1], clock[2] and interrupt[3] bindings. Only - deviations are documented here. + The bindings follow the mmc[1], clock[2], interrupt[3] and phy[4] bindings. + Only deviations are documented here. [1] Documentation/devicetree/bindings/mmc/mmc.txt [2] Documentation/devicetree/bindings/clock/clock-bindings.txt [3] Documentation/devicetree/bindings/interrupt-controller/interrupts.txt + [4] Documentation/devicetree/bindings/phy/phy-bindings.txt Required Properties: - compatible: Compatibility string. Must be 'arasan,sdhci-8.9a' or @@ -17,6 +18,10 @@ Required Properties: - interrupt-parent: Phandle for the interrupt controller that services interrupts for this device. +Required Properties for "arasan,sdhci-5.1": + - phys: From PHY bindings: Phandle for the Generic PHY for arasan. + - phy-names: MUST be "phy_arasan". + Example: sdhci@e0100000 { compatible = "arasan,sdhci-8.9a"; @@ -26,3 +31,14 @@ Example: interrupt-parent = <&gic>; interrupts = <0 24 4>; } ; + + sdhci@e2800000 { + compatible = "arasan,sdhci-5.1"; + reg = <0xe2800000 0x1000>; + clock-names = "clk_xin", "clk_ahb"; + clocks = <&cru 8>, <&cru 18>; + interrupt-parent = <&gic>; + interrupts = <0 24 4>; + phys = <&emmc_phy>; + phy-names = "phy_arasan"; + } ; -- cgit v0.10.2 From 842750488de659ffd12a28e5f5328c9f15ea08e1 Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Mon, 7 Mar 2016 23:38:56 +0800 Subject: mmc: sdhci-of-arasan: remove disable clk_ahb from sdhci_arasan_resume We don't really need disable clk_ahb when failing to resume. Otherwise we may take risk of bus error for accessing register without clk_ahb. Signed-off-by: Shawn Lin Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sdhci-of-arasan.c b/drivers/mmc/host/sdhci-of-arasan.c index 1e4b5e0..ae8052d 100644 --- a/drivers/mmc/host/sdhci-of-arasan.c +++ b/drivers/mmc/host/sdhci-of-arasan.c @@ -118,7 +118,6 @@ static int sdhci_arasan_resume(struct device *dev) ret = clk_enable(pltfm_host->clk); if (ret) { dev_err(dev, "Cannot enable SD clock.\n"); - clk_disable(sdhci_arasan->clk_ahb); return ret; } -- cgit v0.10.2 From 278d09624eda94d82ff385b1c40ecc3db99c73d3 Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Mon, 7 Mar 2016 23:39:08 +0800 Subject: mmc: sdhci-of-arasan: fix missing sdhci_pltfm_free for err handling Currently, some err handling of sdhci_arasan_probe return directly without calling sdhci_pltfm_free. This patch fixes them. Signed-off-by: Shawn Lin Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sdhci-of-arasan.c b/drivers/mmc/host/sdhci-of-arasan.c index ae8052d..91b7c62 100644 --- a/drivers/mmc/host/sdhci-of-arasan.c +++ b/drivers/mmc/host/sdhci-of-arasan.c @@ -147,19 +147,21 @@ static int sdhci_arasan_probe(struct platform_device *pdev) sdhci_arasan->clk_ahb = devm_clk_get(&pdev->dev, "clk_ahb"); if (IS_ERR(sdhci_arasan->clk_ahb)) { dev_err(&pdev->dev, "clk_ahb clock not found.\n"); - return PTR_ERR(sdhci_arasan->clk_ahb); + ret = PTR_ERR(sdhci_arasan->clk_ahb); + goto err_pltfm_free; } clk_xin = devm_clk_get(&pdev->dev, "clk_xin"); if (IS_ERR(clk_xin)) { dev_err(&pdev->dev, "clk_xin clock not found.\n"); - return PTR_ERR(clk_xin); + ret = PTR_ERR(clk_xin); + goto err_pltfm_free; } ret = clk_prepare_enable(sdhci_arasan->clk_ahb); if (ret) { dev_err(&pdev->dev, "Unable to enable AHB clock.\n"); - return ret; + goto err_pltfm_free; } ret = clk_prepare_enable(clk_xin); @@ -179,17 +181,16 @@ static int sdhci_arasan_probe(struct platform_device *pdev) ret = sdhci_add_host(host); if (ret) - goto err_pltfm_free; + goto clk_disable_all; return 0; -err_pltfm_free: - sdhci_pltfm_free(pdev); clk_disable_all: clk_disable_unprepare(clk_xin); clk_dis_ahb: clk_disable_unprepare(sdhci_arasan->clk_ahb); - +err_pltfm_free: + sdhci_pltfm_free(pdev); return ret; } -- cgit v0.10.2 From 91aa366109e801ef4755096248d7c66136f6e380 Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Mon, 7 Mar 2016 23:39:19 +0800 Subject: mmc: sdhci-of-arasan: add phy support for sdhci-of-arasan This patch adds Generic PHY access for sdhci-of-arasan. Driver can get PHY handler from dt-binding, and power-on/init the PHY. Currently, it's just mandatory for arasan,sdhci-5.1. Signed-off-by: Shawn Lin Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sdhci-of-arasan.c b/drivers/mmc/host/sdhci-of-arasan.c index 91b7c62..2e482b1 100644 --- a/drivers/mmc/host/sdhci-of-arasan.c +++ b/drivers/mmc/host/sdhci-of-arasan.c @@ -21,6 +21,7 @@ #include #include +#include #include "sdhci-pltfm.h" #define SDHCI_ARASAN_CLK_CTRL_OFFSET 0x2c @@ -32,9 +33,11 @@ /** * struct sdhci_arasan_data * @clk_ahb: Pointer to the AHB clock + * @phy: Pointer to the generic phy */ struct sdhci_arasan_data { struct clk *clk_ahb; + struct phy *phy; }; static unsigned int sdhci_arasan_get_timeout_clock(struct sdhci_host *host) @@ -88,6 +91,15 @@ static int sdhci_arasan_suspend(struct device *dev) if (ret) return ret; + if (!IS_ERR(sdhci_arasan->phy)) { + ret = phy_power_off(sdhci_arasan->phy); + if (ret) { + dev_err(dev, "Cannot power off phy.\n"); + sdhci_resume_host(host); + return ret; + } + } + clk_disable(pltfm_host->clk); clk_disable(sdhci_arasan->clk_ahb); @@ -121,6 +133,14 @@ static int sdhci_arasan_resume(struct device *dev) return ret; } + if (!IS_ERR(sdhci_arasan->phy)) { + ret = phy_power_on(sdhci_arasan->phy); + if (ret) { + dev_err(dev, "Cannot power on phy.\n"); + return ret; + } + } + return sdhci_resume_host(host); } #endif /* ! CONFIG_PM_SLEEP */ @@ -179,12 +199,42 @@ static int sdhci_arasan_probe(struct platform_device *pdev) goto clk_disable_all; } + sdhci_arasan->phy = ERR_PTR(-ENODEV); + if (of_device_is_compatible(pdev->dev.of_node, + "arasan,sdhci-5.1")) { + sdhci_arasan->phy = devm_phy_get(&pdev->dev, + "phy_arasan"); + if (IS_ERR(sdhci_arasan->phy)) { + ret = PTR_ERR(sdhci_arasan->phy); + dev_err(&pdev->dev, "No phy for arasan,sdhci-5.1.\n"); + goto clk_disable_all; + } + + ret = phy_init(sdhci_arasan->phy); + if (ret < 0) { + dev_err(&pdev->dev, "phy_init err.\n"); + goto clk_disable_all; + } + + ret = phy_power_on(sdhci_arasan->phy); + if (ret < 0) { + dev_err(&pdev->dev, "phy_power_on err.\n"); + goto err_phy_power; + } + } + ret = sdhci_add_host(host); if (ret) - goto clk_disable_all; + goto err_add_host; return 0; +err_add_host: + if (!IS_ERR(sdhci_arasan->phy)) + phy_power_off(sdhci_arasan->phy); +err_phy_power: + if (!IS_ERR(sdhci_arasan->phy)) + phy_exit(sdhci_arasan->phy); clk_disable_all: clk_disable_unprepare(clk_xin); clk_dis_ahb: @@ -202,6 +252,11 @@ static int sdhci_arasan_remove(struct platform_device *pdev) struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host); struct clk *clk_ahb = sdhci_arasan->clk_ahb; + if (!IS_ERR(sdhci_arasan->phy)) { + phy_power_off(sdhci_arasan->phy); + phy_exit(sdhci_arasan->phy); + } + ret = sdhci_pltfm_unregister(pdev); clk_disable_unprepare(clk_ahb); -- cgit v0.10.2 From 96466fcb6c2a19da5c7abe38433688a5b73648c1 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Mon, 7 Mar 2016 15:36:39 -0800 Subject: mmc: of_mmc_spi: fix unused warning drivers/mmc/host/of_mmc_spi.c: In function 'mmc_spi_get_pdata': drivers/mmc/host/of_mmc_spi.c:77:6: warning: variable 'ret' set but not used [-Wunused-but-set-variable] int ret = -EINVAL; ^ Signed-off-by: Brian Norris Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/of_mmc_spi.c b/drivers/mmc/host/of_mmc_spi.c index 660170c..85bbebf 100644 --- a/drivers/mmc/host/of_mmc_spi.c +++ b/drivers/mmc/host/of_mmc_spi.c @@ -74,7 +74,6 @@ struct mmc_spi_platform_data *mmc_spi_get_pdata(struct spi_device *spi) const u32 *voltage_ranges; int num_ranges; int i; - int ret = -EINVAL; if (dev->platform_data || !np) return dev->platform_data; @@ -97,7 +96,6 @@ struct mmc_spi_platform_data *mmc_spi_get_pdata(struct spi_device *spi) mask = mmc_vddrange_to_ocrmask(be32_to_cpu(voltage_ranges[j]), be32_to_cpu(voltage_ranges[j + 1])); if (!mask) { - ret = -EINVAL; dev_err(dev, "OF: voltage-range #%d is invalid\n", i); goto err_ocr; } -- cgit v0.10.2 From 0076c71e37cc9f3f0b1c0c83f9f26f31a47222b0 Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Sat, 12 Mar 2016 00:35:45 +0800 Subject: mmc: core: remove redundant memset of mmc_decode_cid When initializing sd or sdio card, we get struct mmc_card from mmc_alloc_card which allocates it by kzalloc. So we don't need another memset while decoding cid. Signed-off-by: Shawn Lin Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index bb39a29..b95bd24 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -74,8 +74,6 @@ void mmc_decode_cid(struct mmc_card *card) { u32 *resp = card->raw_cid; - memset(&card->cid, 0, sizeof(struct mmc_cid)); - /* * SD doesn't currently have a version field so we will * have to assume we can parse this. -- cgit v0.10.2 From a0747eb81c1d106b1408d60452af75cd17a67621 Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Mon, 14 Mar 2016 12:41:33 +0800 Subject: mmc: core: remove redundant memset of sdio_read_cccr When initializing sdio card, we get struct mmc_card from mmc_alloc_card which allocates it by kzalloc. So we don't need another memset while reading cccr. Signed-off-by: Shawn Lin Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index 467b3cf..bd44ba8 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -106,8 +106,6 @@ static int sdio_read_cccr(struct mmc_card *card, u32 ocr) unsigned char data; unsigned char speed; - memset(&card->cccr, 0, sizeof(struct sdio_cccr)); - ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_CCCR, 0, &data); if (ret) goto out; -- cgit v0.10.2 From 93c77d2999b09f2084b033ea6489915e0104ad9c Mon Sep 17 00:00:00 2001 From: Brent Taylor Date: Sun, 13 Mar 2016 00:25:31 -0600 Subject: mmc: atmel-mci: Check pdata for NULL before dereferencing it at DMA config Using an at91sam9g20ek development board with DTS configuration may trigger a kernel panic because of a NULL pointer dereference exception, while configuring DMA. Let's fix this by adding a check for pdata before dereferencing it. Signed-off-by: Brent Taylor Cc: stable@vger.kernel.org Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c index 7f9d3de..9268c41 100644 --- a/drivers/mmc/host/atmel-mci.c +++ b/drivers/mmc/host/atmel-mci.c @@ -2438,7 +2438,7 @@ static int atmci_configure_dma(struct atmel_mci *host) struct mci_platform_data *pdata = host->pdev->dev.platform_data; dma_cap_mask_t mask; - if (!pdata->dma_filter) + if (!pdata || !pdata->dma_filter) return -ENODEV; dma_cap_zero(mask); -- cgit v0.10.2 From 83c742c344c08c2bbe338d45c6ec63110e9d5e3d Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Wed, 16 Mar 2016 18:15:47 +0800 Subject: mmc: block: fix ABI regression of mmc_blk_ioctl If mmc_blk_ioctl returns -EINVAL, blkdev_ioctl continues to work without returning err to user-space. But now we check CAP_SYS_RAWIO firstly, so we return -EPERM to blkdev_ioctl, which make blkdev_ioctl return -EPERM to user-space directly. So this will break all the ioctl with BLKROSET. Now we find Android-adb suffer it for the following log: remount of /system failed; couldn't make block device writable: Operation not permitted openat(AT_FDCWD, "/dev/block/platform/ff420000.dwmmc/by-name/system", O_RDONLY) = 3 ioctl(3, BLKROSET, 0) = -1 EPERM (Operation not permitted) Fixes: a5f5774c55a2 ("mmc: block: Add new ioctl to send multi commands") Cc: stable@vger.kernel.org Signed-off-by: Shawn Lin Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index 47bc87d..3bdbe50 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -589,6 +589,14 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev, struct mmc_card *card; int err = 0, ioc_err = 0; + /* + * The caller must have CAP_SYS_RAWIO, and must be calling this on the + * whole block device, not on a partition. This prevents overspray + * between sibling partitions. + */ + if ((!capable(CAP_SYS_RAWIO)) || (bdev != bdev->bd_contains)) + return -EPERM; + idata = mmc_blk_ioctl_copy_from_user(ic_ptr); if (IS_ERR(idata)) return PTR_ERR(idata); @@ -631,6 +639,14 @@ static int mmc_blk_ioctl_multi_cmd(struct block_device *bdev, int i, err = 0, ioc_err = 0; __u64 num_of_cmds; + /* + * The caller must have CAP_SYS_RAWIO, and must be calling this on the + * whole block device, not on a partition. This prevents overspray + * between sibling partitions. + */ + if ((!capable(CAP_SYS_RAWIO)) || (bdev != bdev->bd_contains)) + return -EPERM; + if (copy_from_user(&num_of_cmds, &user->num_of_cmds, sizeof(num_of_cmds))) return -EFAULT; @@ -688,14 +704,6 @@ cmd_err: static int mmc_blk_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, unsigned long arg) { - /* - * The caller must have CAP_SYS_RAWIO, and must be calling this on the - * whole block device, not on a partition. This prevents overspray - * between sibling partitions. - */ - if ((!capable(CAP_SYS_RAWIO)) || (bdev != bdev->bd_contains)) - return -EPERM; - switch (cmd) { case MMC_IOC_CMD: return mmc_blk_ioctl_cmd(bdev, -- cgit v0.10.2 From 7b91369b46559dcc90e8d414e31c0257972e0cbb Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Mon, 7 Mar 2016 11:07:55 +0900 Subject: mmc: sdhci: Set DMA mask when adding host Set the DMA mask in sdhci_add_host() after we determined the capabilities of the device. 64-bit devices in particular are given the proper mask that ensures bounce buffers are not used. Also disable DMA if no proper DMA mask can be set, as the DMA-API documentation specifies. Signed-off-by: Alexandre Courbot Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 4ae394e..8670f16 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -2804,6 +2804,36 @@ struct sdhci_host *sdhci_alloc_host(struct device *dev, EXPORT_SYMBOL_GPL(sdhci_alloc_host); +static int sdhci_set_dma_mask(struct sdhci_host *host) +{ + struct mmc_host *mmc = host->mmc; + struct device *dev = mmc_dev(mmc); + int ret = -EINVAL; + + if (host->quirks2 & SDHCI_QUIRK2_BROKEN_64_BIT_DMA) + host->flags &= ~SDHCI_USE_64_BIT_DMA; + + /* Try 64-bit mask if hardware is capable of it */ + if (host->flags & SDHCI_USE_64_BIT_DMA) { + ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)); + if (ret) { + pr_warn("%s: Failed to set 64-bit DMA mask.\n", + mmc_hostname(mmc)); + host->flags &= ~SDHCI_USE_64_BIT_DMA; + } + } + + /* 32-bit mask as default & fallback */ + if (ret) { + ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32)); + if (ret) + pr_warn("%s: Failed to set 32-bit DMA mask.\n", + mmc_hostname(mmc)); + } + + return ret; +} + int sdhci_add_host(struct sdhci_host *host) { struct mmc_host *mmc; @@ -2879,13 +2909,17 @@ int sdhci_add_host(struct sdhci_host *host) 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)) { - pr_warn("%s: No suitable DMA available - falling back to PIO\n", - mmc_hostname(mmc)); - host->flags &= - ~(SDHCI_USE_SDMA | SDHCI_USE_ADMA); - } + ret = sdhci_set_dma_mask(host); + + if (!ret && host->ops->enable_dma) + ret = host->ops->enable_dma(host); + + if (ret) { + pr_warn("%s: No suitable DMA available - falling back to PIO\n", + mmc_hostname(mmc)); + host->flags &= ~(SDHCI_USE_SDMA | SDHCI_USE_ADMA); + + ret = 0; } } -- cgit v0.10.2 From 741b48f4f39730fdf74bc5892fca2de2fe798b63 Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Mon, 7 Mar 2016 11:07:56 +0900 Subject: mmc: sdhci-acpi: Remove enable_dma() hook This hook was solely used to set the DMA mask, which is now done by the newly-added sdhci_set_dma_mask() function. The use of a flag to ensure the mask is only set once is a strong hint that it should not have been done there anyway. Signed-off-by: Alexandre Courbot Acked-by: Arnd Bergmann Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sdhci-acpi.c b/drivers/mmc/host/sdhci-acpi.c index 4e94684..6839e41 100644 --- a/drivers/mmc/host/sdhci-acpi.c +++ b/drivers/mmc/host/sdhci-acpi.c @@ -75,7 +75,6 @@ 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) @@ -83,33 +82,6 @@ static inline bool sdhci_acpi_flag(struct sdhci_acpi_host *c, unsigned int flag) return c->slot && (c->slot->flags & flag); } -static int sdhci_acpi_enable_dma(struct sdhci_host *host) -{ - 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) { u8 reg; @@ -127,7 +99,6 @@ static void sdhci_acpi_int_hw_reset(struct sdhci_host *host) static const struct sdhci_ops sdhci_acpi_ops_dflt = { .set_clock = sdhci_set_clock, - .enable_dma = sdhci_acpi_enable_dma, .set_bus_width = sdhci_set_bus_width, .reset = sdhci_reset, .set_uhs_signaling = sdhci_set_uhs_signaling, @@ -135,7 +106,6 @@ static const struct sdhci_ops sdhci_acpi_ops_dflt = { static const struct sdhci_ops sdhci_acpi_ops_int = { .set_clock = sdhci_set_clock, - .enable_dma = sdhci_acpi_enable_dma, .set_bus_width = sdhci_set_bus_width, .reset = sdhci_reset, .set_uhs_signaling = sdhci_set_uhs_signaling, -- cgit v0.10.2 From bd9ff18bffcd1861ff0c7dc3fd06d0df2510cc42 Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Mon, 7 Mar 2016 11:07:57 +0900 Subject: mmc: sdhci-pci: Do not set DMA mask in enable_dma() DMA mask will already be set by sdhci_set_dma_mask(), which is equivalent to the removed code since pci_set_dma_mask() expands to its DMA-API counterpart. There should also be no reason to set the DMA mask after probe. Signed-off-by: Alexandre Courbot Acked-by: Arnd Bergmann Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sdhci-pci-core.c b/drivers/mmc/host/sdhci-pci-core.c index df3b8ec..62aa5d0 100644 --- a/drivers/mmc/host/sdhci-pci-core.c +++ b/drivers/mmc/host/sdhci-pci-core.c @@ -1302,7 +1302,6 @@ static int sdhci_pci_enable_dma(struct sdhci_host *host) { struct sdhci_pci_slot *slot; struct pci_dev *pdev; - int ret = -1; slot = sdhci_priv(host); pdev = slot->chip->pdev; @@ -1314,20 +1313,6 @@ static int sdhci_pci_enable_dma(struct sdhci_host *host) "doesn't fully claim to support it.\n"); } - 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; - pci_set_master(pdev); return 0; -- cgit v0.10.2 From 64e5cd723120643a4c8bef0880a03a60161d3ccb Mon Sep 17 00:00:00 2001 From: "ludovic.desroches@atmel.com" Date: Thu, 17 Mar 2016 14:54:34 +0100 Subject: mmc: sdhci-of-at91: fix wake-up issue when using runtime pm It is impossible to wake-up on card detect event because when sdhci controller is runtime suspended, it is assumed that all clocks are disabled so we can't get irqs. If the device is removable and there is no gpio to manage the card detection then polling is used. It doesn't mean card detection is broken. It is curently we only way to wake-up on card event if using runtime pm. Signed-off-by: Ludovic Desroches Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sdhci-of-at91.c b/drivers/mmc/host/sdhci-of-at91.c index 35c02fc..2703aa9 100644 --- a/drivers/mmc/host/sdhci-of-at91.c +++ b/drivers/mmc/host/sdhci-of-at91.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -204,6 +205,25 @@ static int sdhci_at91_probe(struct platform_device *pdev) if (ret) goto pm_runtime_disable; + /* + * When calling sdhci_runtime_suspend_host(), the sdhci layer makes + * the assumption that all the clocks of the controller are disabled. + * It means we can't get irq from it when it is runtime suspended. + * For that reason, it is not planned to wake-up on a card detect irq + * from the controller. + * If we want to use runtime PM and to be able to wake-up on card + * insertion, we have to use a GPIO for the card detection or we can + * use polling. Be aware that using polling will resume/suspend the + * controller between each attempt. + * Disable SDHCI_QUIRK_BROKEN_CARD_DETECTION to be sure nobody tries + * to enable polling via device tree with broken-cd property. + */ + if (!(host->mmc->caps & MMC_CAP_NONREMOVABLE) && + IS_ERR_VALUE(mmc_gpio_get_cd(host->mmc))) { + host->mmc->caps |= MMC_CAP_NEEDS_POLL; + host->quirks &= ~SDHCI_QUIRK_BROKEN_CARD_DETECTION; + } + pm_runtime_put_autosuspend(&pdev->dev); return 0; -- cgit v0.10.2