diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2022-03-23 14:39:51 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2022-03-23 14:39:51 -0700 |
commit | 5bebe2c9ae0e0d3c6b25b8e1048bf66b1a3df621 (patch) | |
tree | 219e677918916f132a81adde49cfa3b98413bade /drivers | |
parent | c7d4b15372bde442059c7d6415afeba073a09474 (diff) | |
parent | dc3d879c6ffa25e90875237265898e49b2cabb7e (diff) | |
download | linux-5bebe2c9ae0e0d3c6b25b8e1048bf66b1a3df621.tar.bz2 |
Merge tag 'mmc-v5.18' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc
Pull MMC updates from Ulf Hansson:
"MMC core:
- Convert to sysfs_emit() in favor of sprintf()
- Improve fallback to speed modes if eMMC HS200 fails
MMC host:
- dw_mmc: Allow variants to set minimal supported clock rate
- dw-mmc-rockchip: Fix problems with invalid clock rates
- litex_mmc: Add new DT based driver for the LiteX's LiteSDCard
interface
- litex_mmc: Add Gabriel Somlo and Joel Stanley as co-maintainers for
LiteX
- mtk-sd: Add support for the Mediatek MT8186 variant
- renesas_sdhi: Add support for RZ/G2UL variant
- renesas_sdhi: Add support for RZ/V2L variant
- rtsx_pci: Adjust power-on sequence to conform to the SD spec
- sdhci-am654: Add support for TI's AM62 variant
- sdhci_am654: Fixup support for TI's AM64 variant
- sdhci-esdhc-imx: Add support for the imx93 variant
- sdhci-msm: Add support for the msm8953 variant
- sdhci-pci-gli: Add support for runtime PM for the GL9763E variant
- sdhci-pci-gli: Adjustments of the SSC function for the GL975x
variants
- sdhci-tegra: Add support for wake on SD card event
- sunxi-mmc: Add support for Allwinner's F1c100s variant
- sunxi-mmc: Add support for D1 MMC variant"
* tag 'mmc-v5.18' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc: (37 commits)
dt-bindings: mmc: renesas,sdhi: Document RZ/G2UL SoC
mmc: tmio: remove outdated members from host struct
mmc: mtk-sd: Silence delay phase calculation debug log
mmc: davinci_mmc: Handle error for clk_enable
mmc: sdhci-pci-gli: Add runtime PM for GL9763E
mmc: core: Drop HS400 caps unless 8-bit bus is supported too
mmc: host: Return an error when ->enable_sdio_irq() ops is missing
mmc: core: Improve fallback to speed modes if eMMC HS200 fails
dt-bindings: mmc: sunxi: add Allwinner F1c100s compatible
mmc: dw-mmc-rockchip: Fix handling invalid clock rates
mmc: dw_mmc: Support setting f_min from host drivers
mmc: host: Drop commas after SoC match table sentinels
mmc: rtsx: add 74 Clocks in power on flow
dt-bindings: mmc: renesas,sdhi: Document RZ/V2L SoC
mmc: sh_mmcif: Simplify division/shift logic
mmc: sdhci_am654: Add Support for TI's AM62 SoC
dt-bindings: mmc: imx-esdhc: Add imx93 compatible string
dt-bindings: mmc: sdhci-am654: Add compatible string for AM62 SoC
mmc: sdhci_am654: Fix the driver data of AM64 SoC
mmc: core: use sysfs_emit() instead of sprintf()
...
Diffstat (limited to 'drivers')
26 files changed, 972 insertions, 120 deletions
diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c index 096ae624be9a..58a60afa650b 100644 --- a/drivers/mmc/core/bus.c +++ b/drivers/mmc/core/bus.c @@ -15,6 +15,7 @@ #include <linux/stat.h> #include <linux/of.h> #include <linux/pm_runtime.h> +#include <linux/sysfs.h> #include <linux/mmc/card.h> #include <linux/mmc/host.h> @@ -34,13 +35,13 @@ static ssize_t type_show(struct device *dev, switch (card->type) { case MMC_TYPE_MMC: - return sprintf(buf, "MMC\n"); + return sysfs_emit(buf, "MMC\n"); case MMC_TYPE_SD: - return sprintf(buf, "SD\n"); + return sysfs_emit(buf, "SD\n"); case MMC_TYPE_SDIO: - return sprintf(buf, "SDIO\n"); + return sysfs_emit(buf, "SDIO\n"); case MMC_TYPE_SD_COMBO: - return sprintf(buf, "SDcombo\n"); + return sysfs_emit(buf, "SDcombo\n"); default: return -EFAULT; } diff --git a/drivers/mmc/core/bus.h b/drivers/mmc/core/bus.h index 8105852c4b62..3996b191b68d 100644 --- a/drivers/mmc/core/bus.h +++ b/drivers/mmc/core/bus.h @@ -9,6 +9,7 @@ #define _MMC_CORE_BUS_H #include <linux/device.h> +#include <linux/sysfs.h> struct mmc_host; struct mmc_card; @@ -17,7 +18,7 @@ struct mmc_card; static ssize_t mmc_##name##_show (struct device *dev, struct device_attribute *attr, char *buf) \ { \ struct mmc_card *card = mmc_dev_to_card(dev); \ - return sprintf(buf, fmt, args); \ + return sysfs_emit(buf, fmt, args); \ } \ static DEVICE_ATTR(name, S_IRUGO, mmc_##name##_show, NULL) diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index cf140f4ec864..2ed2b4d5e5a5 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -588,6 +588,25 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev) EXPORT_SYMBOL(mmc_alloc_host); +static int mmc_validate_host_caps(struct mmc_host *host) +{ + struct device *dev = host->parent; + u32 caps = host->caps, caps2 = host->caps2; + + if (caps & MMC_CAP_SDIO_IRQ && !host->ops->enable_sdio_irq) { + dev_warn(dev, "missing ->enable_sdio_irq() ops\n"); + return -EINVAL; + } + + if (caps2 & (MMC_CAP2_HS400_ES | MMC_CAP2_HS400) && + !(caps & MMC_CAP_8_BIT_DATA)) { + dev_warn(dev, "drop HS400 support since no 8-bit bus\n"); + host->caps2 = caps2 & ~MMC_CAP2_HS400_ES & ~MMC_CAP2_HS400; + } + + return 0; +} + /** * mmc_add_host - initialise host hardware * @host: mmc host @@ -600,8 +619,9 @@ int mmc_add_host(struct mmc_host *host) { int err; - WARN_ON((host->caps & MMC_CAP_SDIO_IRQ) && - !host->ops->enable_sdio_irq); + err = mmc_validate_host_caps(host); + if (err) + return err; err = device_add(&host->class_dev); if (err) diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 8421519c2a98..e7ea45386c22 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -12,6 +12,7 @@ #include <linux/slab.h> #include <linux/stat.h> #include <linux/pm_runtime.h> +#include <linux/sysfs.h> #include <linux/mmc/host.h> #include <linux/mmc/card.h> @@ -812,12 +813,11 @@ static ssize_t mmc_fwrev_show(struct device *dev, { struct mmc_card *card = mmc_dev_to_card(dev); - if (card->ext_csd.rev < 7) { - return sprintf(buf, "0x%x\n", card->cid.fwrev); - } else { - return sprintf(buf, "0x%*phN\n", MMC_FIRMWARE_LEN, - card->ext_csd.fwrev); - } + if (card->ext_csd.rev < 7) + return sysfs_emit(buf, "0x%x\n", card->cid.fwrev); + else + return sysfs_emit(buf, "0x%*phN\n", MMC_FIRMWARE_LEN, + card->ext_csd.fwrev); } static DEVICE_ATTR(fwrev, S_IRUGO, mmc_fwrev_show, NULL); @@ -830,10 +830,10 @@ static ssize_t mmc_dsr_show(struct device *dev, struct mmc_host *host = card->host; if (card->csd.dsr_imp && host->dsr_req) - return sprintf(buf, "0x%x\n", host->dsr); + return sysfs_emit(buf, "0x%x\n", host->dsr); else /* return default DSR value */ - return sprintf(buf, "0x%x\n", 0x404); + return sysfs_emit(buf, "0x%x\n", 0x404); } static DEVICE_ATTR(dsr, S_IRUGO, mmc_dsr_show, NULL); @@ -1355,11 +1355,6 @@ static int mmc_select_hs400es(struct mmc_card *card) int err = -EINVAL; u8 val; - if (!(host->caps & MMC_CAP_8_BIT_DATA)) { - err = -ENOTSUPP; - goto out_err; - } - if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400_1_2V) err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120); @@ -1523,13 +1518,23 @@ static int mmc_select_timing(struct mmc_card *card) if (!mmc_can_ext_csd(card)) goto bus_speed; - if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400ES) + if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400ES) { err = mmc_select_hs400es(card); - else if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200) + goto out; + } + + if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200) { err = mmc_select_hs200(card); - else if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS) + if (err == -EBADMSG) + card->mmc_avail_type &= ~EXT_CSD_CARD_TYPE_HS200; + else + goto out; + } + + if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS) err = mmc_select_hs(card); +out: if (err && err != -EBADMSG) return err; diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index bfbfed30dc4d..68df6b2f49cc 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -13,6 +13,7 @@ #include <linux/stat.h> #include <linux/pm_runtime.h> #include <linux/scatterlist.h> +#include <linux/sysfs.h> #include <linux/mmc/host.h> #include <linux/mmc/card.h> @@ -708,18 +709,16 @@ MMC_DEV_ATTR(ocr, "0x%08x\n", card->ocr); MMC_DEV_ATTR(rca, "0x%04x\n", card->rca); -static ssize_t mmc_dsr_show(struct device *dev, - struct device_attribute *attr, - char *buf) +static ssize_t mmc_dsr_show(struct device *dev, struct device_attribute *attr, + char *buf) { - struct mmc_card *card = mmc_dev_to_card(dev); - struct mmc_host *host = card->host; - - if (card->csd.dsr_imp && host->dsr_req) - return sprintf(buf, "0x%x\n", host->dsr); - else - /* return default DSR value */ - return sprintf(buf, "0x%x\n", 0x404); + struct mmc_card *card = mmc_dev_to_card(dev); + struct mmc_host *host = card->host; + + if (card->csd.dsr_imp && host->dsr_req) + return sysfs_emit(buf, "0x%x\n", host->dsr); + /* return default DSR value */ + return sysfs_emit(buf, "0x%x\n", 0x404); } static DEVICE_ATTR(dsr, S_IRUGO, mmc_dsr_show, NULL); @@ -735,9 +734,9 @@ static ssize_t info##num##_show(struct device *dev, struct device_attribute *att \ if (num > card->num_info) \ return -ENODATA; \ - if (!card->info[num-1][0]) \ + if (!card->info[num - 1][0]) \ return 0; \ - return sprintf(buf, "%s\n", card->info[num-1]); \ + return sysfs_emit(buf, "%s\n", card->info[num - 1]); \ } \ static DEVICE_ATTR_RO(info##num) diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index 41164748723d..25799accf8a0 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -7,6 +7,7 @@ #include <linux/err.h> #include <linux/pm_runtime.h> +#include <linux/sysfs.h> #include <linux/mmc/host.h> #include <linux/mmc/card.h> @@ -40,9 +41,9 @@ static ssize_t info##num##_show(struct device *dev, struct device_attribute *att \ if (num > card->num_info) \ return -ENODATA; \ - if (!card->info[num-1][0]) \ + if (!card->info[num - 1][0]) \ return 0; \ - return sprintf(buf, "%s\n", card->info[num-1]); \ + return sysfs_emit(buf, "%s\n", card->info[num - 1]); \ } \ static DEVICE_ATTR_RO(info##num) diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c index fda03b35c14a..c6268c38c69e 100644 --- a/drivers/mmc/core/sdio_bus.c +++ b/drivers/mmc/core/sdio_bus.c @@ -14,6 +14,7 @@ #include <linux/pm_runtime.h> #include <linux/pm_domain.h> #include <linux/acpi.h> +#include <linux/sysfs.h> #include <linux/mmc/card.h> #include <linux/mmc/host.h> @@ -35,7 +36,7 @@ field##_show(struct device *dev, struct device_attribute *attr, char *buf) \ struct sdio_func *func; \ \ func = dev_to_sdio_func (dev); \ - return sprintf(buf, format_string, args); \ + return sysfs_emit(buf, format_string, args); \ } \ static DEVICE_ATTR_RO(field) @@ -52,9 +53,9 @@ static ssize_t info##num##_show(struct device *dev, struct device_attribute *att \ if (num > func->num_info) \ return -ENODATA; \ - if (!func->info[num-1][0]) \ + if (!func->info[num - 1][0]) \ return 0; \ - return sprintf(buf, "%s\n", func->info[num-1]); \ + return sysfs_emit(buf, "%s\n", func->info[num - 1]); \ } \ static DEVICE_ATTR_RO(info##num) diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index 52b0b27a6839..af6c3c329076 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -1094,3 +1094,16 @@ config MMC_OWL config MMC_SDHCI_EXTERNAL_DMA bool + +config MMC_LITEX + tristate "LiteX MMC Host Controller support" + depends on ((PPC_MICROWATT || LITEX) && OF && HAVE_CLK) || COMPILE_TEST + select REGULATOR + select REGULATOR_FIXED_VOLTAGE + help + This selects support for the MMC Host Controller found in LiteX SoCs. + + To compile this driver as a module, choose M here: the + module will be called litex_mmc. + + If unsure, say N. diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile index ea36d379bd3c..4e4ceb32c4b4 100644 --- a/drivers/mmc/host/Makefile +++ b/drivers/mmc/host/Makefile @@ -101,6 +101,7 @@ obj-$(CONFIG_MMC_CQHCI) += cqhci.o cqhci-y += cqhci-core.o cqhci-$(CONFIG_MMC_CRYPTO) += cqhci-crypto.o obj-$(CONFIG_MMC_HSQ) += mmc_hsq.o +obj-$(CONFIG_MMC_LITEX) += litex_mmc.o ifeq ($(CONFIG_CB710_DEBUG),y) CFLAGS-cb710-mmc += -DDEBUG diff --git a/drivers/mmc/host/davinci_mmc.c b/drivers/mmc/host/davinci_mmc.c index 2a757c88f9d2..7138dfa065bf 100644 --- a/drivers/mmc/host/davinci_mmc.c +++ b/drivers/mmc/host/davinci_mmc.c @@ -1189,7 +1189,6 @@ static int mmc_davinci_parse_pdata(struct mmc_host *mmc) static int davinci_mmcsd_probe(struct platform_device *pdev) { - const struct of_device_id *match; struct mmc_davinci_host *host = NULL; struct mmc_host *mmc = NULL; struct resource *r, *mem = NULL; @@ -1235,9 +1234,8 @@ static int davinci_mmcsd_probe(struct platform_device *pdev) host->mmc_input_clk = clk_get_rate(host->clk); - match = of_match_device(davinci_mmc_dt_ids, &pdev->dev); - if (match) { - pdev->id_entry = match->data; + pdev->id_entry = of_device_get_match_data(&pdev->dev); + if (pdev->id_entry) { ret = mmc_of_parse(mmc); if (ret) { dev_err_probe(&pdev->dev, ret, @@ -1375,8 +1373,12 @@ static int davinci_mmcsd_suspend(struct device *dev) static int davinci_mmcsd_resume(struct device *dev) { struct mmc_davinci_host *host = dev_get_drvdata(dev); + int ret; + + ret = clk_enable(host->clk); + if (ret) + return ret; - clk_enable(host->clk); mmc_davinci_reset_ctrl(host, 0); return 0; diff --git a/drivers/mmc/host/dw_mmc-rockchip.c b/drivers/mmc/host/dw_mmc-rockchip.c index 95d0ec0f5f3a..f825487aa739 100644 --- a/drivers/mmc/host/dw_mmc-rockchip.c +++ b/drivers/mmc/host/dw_mmc-rockchip.c @@ -15,7 +15,9 @@ #include "dw_mmc.h" #include "dw_mmc-pltfm.h" -#define RK3288_CLKGEN_DIV 2 +#define RK3288_CLKGEN_DIV 2 + +static const unsigned int freqs[] = { 100000, 200000, 300000, 400000 }; struct dw_mci_rockchip_priv_data { struct clk *drv_clk; @@ -51,7 +53,7 @@ static void dw_mci_rk3288_set_ios(struct dw_mci *host, struct mmc_ios *ios) ret = clk_set_rate(host->ciu_clk, cclkin); if (ret) - dev_warn(host->dev, "failed to set rate %uHz\n", ios->clock); + dev_warn(host->dev, "failed to set rate %uHz err: %d\n", cclkin, ret); bus_hz = clk_get_rate(host->ciu_clk) / RK3288_CLKGEN_DIV; if (bus_hz != host->bus_hz) { @@ -290,13 +292,30 @@ static int dw_mci_rk3288_parse_dt(struct dw_mci *host) static int dw_mci_rockchip_init(struct dw_mci *host) { + int ret, i; + /* It is slot 8 on Rockchip SoCs */ host->sdio_id0 = 8; - if (of_device_is_compatible(host->dev->of_node, - "rockchip,rk3288-dw-mshc")) + if (of_device_is_compatible(host->dev->of_node, "rockchip,rk3288-dw-mshc")) { host->bus_hz /= RK3288_CLKGEN_DIV; + /* clock driver will fail if the clock is less than the lowest source clock + * divided by the internal clock divider. Test for the lowest available + * clock and set the minimum freq to clock / clock divider. + */ + + for (i = 0; i < ARRAY_SIZE(freqs); i++) { + ret = clk_round_rate(host->ciu_clk, freqs[i] * RK3288_CLKGEN_DIV); + if (ret > 0) { + host->minimum_speed = ret / RK3288_CLKGEN_DIV; + break; + } + } + if (ret < 0) + dev_warn(host->dev, "no valid minimum freq: %d\n", ret); + } + return 0; } diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 42bf8a2287ba..06dc56cbada8 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -2898,7 +2898,12 @@ static int dw_mci_init_slot_caps(struct dw_mci_slot *slot) if (host->pdata->caps2) mmc->caps2 = host->pdata->caps2; - mmc->f_min = DW_MCI_FREQ_MIN; + /* if host has set a minimum_freq, we should respect it */ + if (host->minimum_speed) + mmc->f_min = host->minimum_speed; + else + mmc->f_min = DW_MCI_FREQ_MIN; + if (!mmc->f_max) mmc->f_max = DW_MCI_FREQ_MAX; @@ -3057,8 +3062,7 @@ static void dw_mci_init_dma(struct dw_mci *host) dev_info(host->dev, "Using internal DMA controller.\n"); } else { /* TRANS_MODE_EDMAC: check dma bindings again */ - if ((device_property_read_string_array(dev, "dma-names", - NULL, 0) < 0) || + if ((device_property_string_array_count(dev, "dma-names") < 0) || !device_property_present(dev, "dmas")) { goto no_dma; } @@ -3568,7 +3572,7 @@ int dw_mci_runtime_resume(struct device *dev) mci_writel(host, CTRL, SDMMC_CTRL_INT_ENABLE); - if (host->slot->mmc->pm_flags & MMC_PM_KEEP_POWER) + if (host->slot && host->slot->mmc->pm_flags & MMC_PM_KEEP_POWER) dw_mci_set_ios(host->slot->mmc, &host->slot->mmc->ios); /* Force setup bus to guarantee available clock output */ diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h index 7f1e38621d13..4ed81f94f7ca 100644 --- a/drivers/mmc/host/dw_mmc.h +++ b/drivers/mmc/host/dw_mmc.h @@ -99,6 +99,7 @@ struct dw_mci_dma_slave { * @bus_hz: The rate of @mck in Hz. This forms the basis for MMC bus * rate and timeout calculations. * @current_speed: Configured rate of the controller. + * @minimum_speed: Stored minimum rate of the controller. * @fifoth_val: The value of FIFOTH register. * @verid: Denote Version ID. * @dev: Device associated with the MMC controller. @@ -201,6 +202,7 @@ struct dw_mci { u32 bus_hz; u32 current_speed; + u32 minimum_speed; u32 fifoth_val; u16 verid; struct device *dev; diff --git a/drivers/mmc/host/litex_mmc.c b/drivers/mmc/host/litex_mmc.c new file mode 100644 index 000000000000..6ba0d63b8c07 --- /dev/null +++ b/drivers/mmc/host/litex_mmc.c @@ -0,0 +1,661 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * LiteX LiteSDCard driver + * + * Copyright (C) 2019-2020 Antmicro <contact@antmicro.com> + * Copyright (C) 2019-2020 Kamil Rakoczy <krakoczy@antmicro.com> + * Copyright (C) 2019-2020 Maciej Dudek <mdudek@internships.antmicro.com> + * Copyright (C) 2020 Paul Mackerras <paulus@ozlabs.org> + * Copyright (C) 2020-2022 Gabriel Somlo <gsomlo@gmail.com> + */ + +#include <linux/bits.h> +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/dma-mapping.h> +#include <linux/interrupt.h> +#include <linux/iopoll.h> +#include <linux/litex.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/platform_device.h> + +#include <linux/mmc/host.h> +#include <linux/mmc/mmc.h> +#include <linux/mmc/sd.h> + +#define LITEX_PHY_CARDDETECT 0x00 +#define LITEX_PHY_CLOCKERDIV 0x04 +#define LITEX_PHY_INITIALIZE 0x08 +#define LITEX_PHY_WRITESTATUS 0x0C +#define LITEX_CORE_CMDARG 0x00 +#define LITEX_CORE_CMDCMD 0x04 +#define LITEX_CORE_CMDSND 0x08 +#define LITEX_CORE_CMDRSP 0x0C +#define LITEX_CORE_CMDEVT 0x1C +#define LITEX_CORE_DATEVT 0x20 +#define LITEX_CORE_BLKLEN 0x24 +#define LITEX_CORE_BLKCNT 0x28 +#define LITEX_BLK2MEM_BASE 0x00 +#define LITEX_BLK2MEM_LEN 0x08 +#define LITEX_BLK2MEM_ENA 0x0C +#define LITEX_BLK2MEM_DONE 0x10 +#define LITEX_BLK2MEM_LOOP 0x14 +#define LITEX_MEM2BLK_BASE 0x00 +#define LITEX_MEM2BLK_LEN 0x08 +#define LITEX_MEM2BLK_ENA 0x0C +#define LITEX_MEM2BLK_DONE 0x10 +#define LITEX_MEM2BLK_LOOP 0x14 +#define LITEX_MEM2BLK 0x18 +#define LITEX_IRQ_STATUS 0x00 +#define LITEX_IRQ_PENDING 0x04 +#define LITEX_IRQ_ENABLE 0x08 + +#define SD_CTL_DATA_XFER_NONE 0 +#define SD_CTL_DATA_XFER_READ 1 +#define SD_CTL_DATA_XFER_WRITE 2 + +#define SD_CTL_RESP_NONE 0 +#define SD_CTL_RESP_SHORT 1 +#define SD_CTL_RESP_LONG 2 +#define SD_CTL_RESP_SHORT_BUSY 3 + +#define SD_BIT_DONE BIT(0) +#define SD_BIT_WR_ERR BIT(1) +#define SD_BIT_TIMEOUT BIT(2) +#define SD_BIT_CRC_ERR BIT(3) + +#define SD_SLEEP_US 5 +#define SD_TIMEOUT_US 20000 + +#define SDIRQ_CARD_DETECT 1 +#define SDIRQ_SD_TO_MEM_DONE 2 +#define SDIRQ_MEM_TO_SD_DONE 4 +#define SDIRQ_CMD_DONE 8 + +struct litex_mmc_host { + struct mmc_host *mmc; + + void __iomem *sdphy; + void __iomem *sdcore; + void __iomem *sdreader; + void __iomem *sdwriter; + void __iomem *sdirq; + + void *buffer; + size_t buf_size; + dma_addr_t dma; + + struct completion cmd_done; + int irq; + + unsigned int ref_clk; + unsigned int sd_clk; + + u32 resp[4]; + u16 rca; + + bool is_bus_width_set; + bool app_cmd; +}; + +static int litex_mmc_sdcard_wait_done(void __iomem *reg, struct device *dev) +{ + u8 evt; + int ret; + + ret = readx_poll_timeout(litex_read8, reg, evt, evt & SD_BIT_DONE, + SD_SLEEP_US, SD_TIMEOUT_US); + if (ret) + return ret; + if (evt == SD_BIT_DONE) + return 0; + if (evt & SD_BIT_WR_ERR) + return -EIO; + if (evt & SD_BIT_TIMEOUT) + return -ETIMEDOUT; + if (evt & SD_BIT_CRC_ERR) + return -EILSEQ; + dev_err(dev, "%s: unknown error (evt=%x)\n", __func__, evt); + return -EINVAL; +} + +static int litex_mmc_send_cmd(struct litex_mmc_host *host, + u8 cmd, u32 arg, u8 response_len, u8 transfer) +{ + struct device *dev = mmc_dev(host->mmc); + void __iomem *reg; + int ret; + u8 evt; + + litex_write32(host->sdcore + LITEX_CORE_CMDARG, arg); + litex_write32(host->sdcore + LITEX_CORE_CMDCMD, + cmd << 8 | transfer << 5 | response_len); + litex_write8(host->sdcore + LITEX_CORE_CMDSND, 1); + + /* + * Wait for an interrupt if we have an interrupt and either there is + * data to be transferred, or if the card can report busy via DAT0. + */ + if (host->irq > 0 && + (transfer != SD_CTL_DATA_XFER_NONE || + response_len == SD_CTL_RESP_SHORT_BUSY)) { + reinit_completion(&host->cmd_done); + litex_write32(host->sdirq + LITEX_IRQ_ENABLE, + SDIRQ_CMD_DONE | SDIRQ_CARD_DETECT); + wait_for_completion(&host->cmd_done); + } + + ret = litex_mmc_sdcard_wait_done(host->sdcore + LITEX_CORE_CMDEVT, dev); + if (ret) { + dev_err(dev, "Command (cmd %d) error, status %d\n", cmd, ret); + return ret; + } + + if (response_len != SD_CTL_RESP_NONE) { + /* + * NOTE: this matches the semantics of litex_read32() + * regardless of underlying arch endianness! + */ + memcpy_fromio(host->resp, + host->sdcore + LITEX_CORE_CMDRSP, 0x10); + } + + if (!host->app_cmd && cmd == SD_SEND_RELATIVE_ADDR) + host->rca = (host->resp[3] >> 16); + + host->app_cmd = (cmd == MMC_APP_CMD); + + if (transfer == SD_CTL_DATA_XFER_NONE) + return ret; /* OK from prior litex_mmc_sdcard_wait_done() */ + + ret = litex_mmc_sdcard_wait_done(host->sdcore + LITEX_CORE_DATEVT, dev); + if (ret) { + dev_err(dev, "Data xfer (cmd %d) error, status %d\n", cmd, ret); + return ret; + } + + /* Wait for completion of (read or write) DMA transfer */ + reg = (transfer == SD_CTL_DATA_XFER_READ) ? + host->sdreader + LITEX_BLK2MEM_DONE : + host->sdwriter + LITEX_MEM2BLK_DONE; + ret = readx_poll_timeout(litex_read8, reg, evt, evt & SD_BIT_DONE, + SD_SLEEP_US, SD_TIMEOUT_US); + if (ret) + dev_err(dev, "DMA timeout (cmd %d)\n", cmd); + + return ret; +} + +static int litex_mmc_send_app_cmd(struct litex_mmc_host *host) +{ + return litex_mmc_send_cmd(host, MMC_APP_CMD, host->rca << 16, + SD_CTL_RESP_SHORT, SD_CTL_DATA_XFER_NONE); +} + +static int litex_mmc_send_set_bus_w_cmd(struct litex_mmc_host *host, u32 width) +{ + return litex_mmc_send_cmd(host, SD_APP_SET_BUS_WIDTH, width, + SD_CTL_RESP_SHORT, SD_CTL_DATA_XFER_NONE); +} + +static int litex_mmc_set_bus_width(struct litex_mmc_host *host) +{ + bool app_cmd_sent; + int ret; + + if (host->is_bus_width_set) + return 0; + + /* Ensure 'app_cmd' precedes 'app_set_bus_width_cmd' */ + app_cmd_sent = host->app_cmd; /* was preceding command app_cmd? */ + if (!app_cmd_sent) { + ret = litex_mmc_send_app_cmd(host); + if (ret) + return ret; + } + + /* LiteSDCard only supports 4-bit bus width */ + ret = litex_mmc_send_set_bus_w_cmd(host, MMC_BUS_WIDTH_4); + if (ret) + return ret; + + /* Re-send 'app_cmd' if necessary */ + if (app_cmd_sent) { + ret = litex_mmc_send_app_cmd(host); + if (ret) + return ret; + } + + host->is_bus_width_set = true; + + return 0; +} + +static int litex_mmc_get_cd(struct mmc_host *mmc) +{ + struct litex_mmc_host *host = mmc_priv(mmc); + int ret; + + if (!mmc_card_is_removable(mmc)) + return 1; + + ret = !litex_read8(host->sdphy + LITEX_PHY_CARDDETECT); + if (ret) + return ret; + + /* Ensure bus width will be set (again) upon card (re)insertion */ + host->is_bus_width_set = false; + + return 0; +} + +static irqreturn_t litex_mmc_interrupt(int irq, void *arg) +{ + struct mmc_host *mmc = arg; + struct litex_mmc_host *host = mmc_priv(mmc); + u32 pending = litex_read32(host->sdirq + LITEX_IRQ_PENDING); + irqreturn_t ret = IRQ_NONE; + + /* Check for card change interrupt */ + if (pending & SDIRQ_CARD_DETECT) { + litex_write32(host->sdirq + LITEX_IRQ_PENDING, + SDIRQ_CARD_DETECT); + mmc_detect_change(mmc, msecs_to_jiffies(10)); + ret = IRQ_HANDLED; + } + + /* Check for command completed */ + if (pending & SDIRQ_CMD_DONE) { + /* Disable it so it doesn't keep interrupting */ + litex_write32(host->sdirq + LITEX_IRQ_ENABLE, + SDIRQ_CARD_DETECT); + complete(&host->cmd_done); + ret = IRQ_HANDLED; + } + + return ret; +} + +static u32 litex_mmc_response_len(struct mmc_command *cmd) +{ + if (cmd->flags & MMC_RSP_136) + return SD_CTL_RESP_LONG; + if (!(cmd->flags & MMC_RSP_PRESENT)) + return SD_CTL_RESP_NONE; + if (cmd->flags & MMC_RSP_BUSY) + return SD_CTL_RESP_SHORT_BUSY; + return SD_CTL_RESP_SHORT; +} + +static void litex_mmc_do_dma(struct litex_mmc_host *host, struct mmc_data *data, + unsigned int *len, bool *direct, u8 *transfer) +{ + struct device *dev = mmc_dev(host->mmc); + dma_addr_t dma; + int sg_count; + + /* + * Try to DMA directly to/from the data buffer. + * We can do that if the buffer can be mapped for DMA + * in one contiguous chunk. + */ + dma = host->dma; + *len = data->blksz * data->blocks; + sg_count = dma_map_sg(dev, data->sg, data->sg_len, + mmc_get_dma_dir(data)); + if (sg_count == 1) { + dma = sg_dma_address(data->sg); + *len = sg_dma_len(data->sg); + *direct = true; + } else if (*len > host->buf_size) + *len = host->buf_size; + + if (data->flags & MMC_DATA_READ) { + litex_write8(host->sdreader + LITEX_BLK2MEM_ENA, 0); + litex_write64(host->sdreader + LITEX_BLK2MEM_BASE, dma); + litex_write32(host->sdreader + LITEX_BLK2MEM_LEN, *len); + litex_write8(host->sdreader + LITEX_BLK2MEM_ENA, 1); + *transfer = SD_CTL_DATA_XFER_READ; + } else if (data->flags & MMC_DATA_WRITE) { + if (!*direct) + sg_copy_to_buffer(data->sg, data->sg_len, + host->buffer, *len); + litex_write8(host->sdwriter + LITEX_MEM2BLK_ENA, 0); + litex_write64(host->sdwriter + LITEX_MEM2BLK_BASE, dma); + litex_write32(host->sdwriter + LITEX_MEM2BLK_LEN, *len); + litex_write8(host->sdwriter + LITEX_MEM2BLK_ENA, 1); + *transfer = SD_CTL_DATA_XFER_WRITE; + } else { + dev_warn(dev, "Data present w/o read or write flag.\n"); + /* Continue: set cmd status, mark req done */ + } + + litex_write16(host->sdcore + LITEX_CORE_BLKLEN, data->blksz); + litex_write32(host->sdcore + LITEX_CORE_BLKCNT, data->blocks); +} + +static void litex_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq) +{ + struct litex_mmc_host *host = mmc_priv(mmc); + struct device *dev = mmc_dev(mmc); + struct mmc_command *cmd = mrq->cmd; + struct mmc_command *sbc = mrq->sbc; + struct mmc_data *data = mrq->data; + struct mmc_command *stop = mrq->stop; + unsigned int retries = cmd->retries; + unsigned int len = 0; + bool direct = false; + u32 response_len = litex_mmc_response_len(cmd); + u8 transfer = SD_CTL_DATA_XFER_NONE; + + /* First check that the card is still there */ + if (!litex_mmc_get_cd(mmc)) { + cmd->error = -ENOMEDIUM; + mmc_request_done(mmc, mrq); + return; + } + + /* Send set-block-count command if needed */ + if (sbc) { + sbc->error = litex_mmc_send_cmd(host, sbc->opcode, sbc->arg, + litex_mmc_response_len(sbc), + SD_CTL_DATA_XFER_NONE); + if (sbc->error) { + host->is_bus_width_set = false; + mmc_request_done(mmc, mrq); + return; + } + } + + if (data) { + /* + * LiteSDCard only supports 4-bit bus width; therefore, we MUST + * inject a SET_BUS_WIDTH (acmd6) before the very first data + * transfer, earlier than when the mmc subsystem would normally + * get around to it! + */ + cmd->error = litex_mmc_set_bus_width(host); + if (cmd->error) { + dev_err(dev, "Can't set bus width!\n"); + mmc_request_done(mmc, mrq); + return; + } + + litex_mmc_do_dma(host, data, &len, &direct, &transfer); + } + + do { + cmd->error = litex_mmc_send_cmd(host, cmd->opcode, cmd->arg, + response_len, transfer); + } while (cmd->error && retries-- > 0); + + if (cmd->error) { + /* Card may be gone; don't assume bus width is still set */ + host->is_bus_width_set = false; + } + + if (response_len == SD_CTL_RESP_SHORT) { + /* Pull short response fields from appropriate host registers */ + cmd->resp[0] = host->resp[3]; + cmd->resp[1] = host->resp[2] & 0xFF; + } else if (response_len == SD_CTL_RESP_LONG) { + cmd->resp[0] = host->resp[0]; + cmd->resp[1] = host->resp[1]; + cmd->resp[2] = host->resp[2]; + cmd->resp[3] = host->resp[3]; + } + + /* Send stop-transmission command if required */ + if (stop && (cmd->error || !sbc)) { + stop->error = litex_mmc_send_cmd(host, stop->opcode, stop->arg, + litex_mmc_response_len(stop), + SD_CTL_DATA_XFER_NONE); + if (stop->error) + host->is_bus_width_set = false; + } + + if (data) { + dma_unmap_sg(dev, data->sg, data->sg_len, + mmc_get_dma_dir(data)); + } + + if (!cmd->error && transfer != SD_CTL_DATA_XFER_NONE) { + data->bytes_xfered = min(len, mmc->max_req_size); + if (transfer == SD_CTL_DATA_XFER_READ && !direct) { + sg_copy_from_buffer(data->sg, sg_nents(data->sg), + host->buffer, data->bytes_xfered); + } + } + + mmc_request_done(mmc, mrq); +} + +static void litex_mmc_setclk(struct litex_mmc_host *host, unsigned int freq) +{ + struct device *dev = mmc_dev(host->mmc); + u32 div; + + div = freq ? host->ref_clk / freq : 256U; + div = roundup_pow_of_two(div); + div = clamp(div, 2U, 256U); + dev_dbg(dev, "sd_clk_freq=%d: set to %d via div=%d\n", + freq, host->ref_clk / div, div); + litex_write16(host->sdphy + LITEX_PHY_CLOCKERDIV, div); + host->sd_clk = freq; +} + +static void litex_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) +{ + struct litex_mmc_host *host = mmc_priv(mmc); + + /* + * NOTE: Ignore any ios->bus_width updates; they occur right after + * the mmc core sends its own acmd6 bus-width change notification, + * which is redundant since we snoop on the command flow and inject + * an early acmd6 before the first data transfer command is sent! + */ + + /* Update sd_clk */ + if (ios->clock != host->sd_clk) + litex_mmc_setclk(host, ios->clock); +} + +static const struct mmc_host_ops litex_mmc_ops = { + .get_cd = litex_mmc_get_cd, + .request = litex_mmc_request, + .set_ios = litex_mmc_set_ios, +}; + +static int litex_mmc_irq_init(struct platform_device *pdev, + struct litex_mmc_host *host) +{ + struct device *dev = mmc_dev(host->mmc); + int ret; + + ret = platform_get_irq_optional(pdev, 0); + if (ret < 0 && ret != -ENXIO) + return ret; + if (ret > 0) + host->irq = ret; + else { + dev_warn(dev, "Failed to get IRQ, using polling\n"); + goto use_polling; + } + + host->sdirq = devm_platform_ioremap_resource_byname(pdev, "irq"); + if (IS_ERR(host->sdirq)) + return PTR_ERR(host->sdirq); + + ret = devm_request_irq(dev, host->irq, litex_mmc_interrupt, 0, + "litex-mmc", host->mmc); + if (ret < 0) { + dev_warn(dev, "IRQ request error %d, using polling\n", ret); + goto use_polling; + } + + /* Clear & enable card-change interrupts */ + litex_write32(host->sdirq + LITEX_IRQ_PENDING, SDIRQ_CARD_DETECT); + litex_write32(host->sdirq + LITEX_IRQ_ENABLE, SDIRQ_CARD_DETECT); + + return 0; + +use_polling: + host->mmc->caps |= MMC_CAP_NEEDS_POLL; + return 0; +} + +static void litex_mmc_free_host_wrapper(void *mmc) +{ + mmc_free_host(mmc); +} + +static int litex_mmc_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct litex_mmc_host *host; + struct mmc_host *mmc; + struct clk *clk; + int ret; + + /* + * NOTE: defaults to max_[req,seg]_size=PAGE_SIZE, max_blk_size=512, + * and max_blk_count accordingly set to 8; + * If for some reason we need to modify max_blk_count, we must also + * re-calculate `max_[req,seg]_size = max_blk_size * max_blk_count;` + */ + mmc = mmc_alloc_host(sizeof(struct litex_mmc_host), dev); + if (!mmc) + return -ENOMEM; + + ret = devm_add_action_or_reset(dev, litex_mmc_free_host_wrapper, mmc); + if (ret) + return dev_err_probe(dev, ret, + "Can't register mmc_free_host action\n"); + + host = mmc_priv(mmc); + host->mmc = mmc; + + /* Initialize clock source */ + clk = devm_clk_get(dev, NULL); + if (IS_ERR(clk)) + return dev_err_probe(dev, PTR_ERR(clk), "can't get clock\n"); + host->ref_clk = clk_get_rate(clk); + host->sd_clk = 0; + + /* + * LiteSDCard only supports 4-bit bus width; therefore, we MUST inject + * a SET_BUS_WIDTH (acmd6) before the very first data transfer, earlier + * than when the mmc subsystem would normally get around to it! + */ + host->is_bus_width_set = false; + host->app_cmd = false; + + /* LiteSDCard can support 64-bit DMA addressing */ + ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)); + if (ret) + return ret; + + host->buf_size = mmc->max_req_size * 2; + host->buffer = dmam_alloc_coherent(dev, host->buf_size, + &host->dma, GFP_KERNEL); + if (host->buffer == NULL) + return -ENOMEM; + + host->sdphy = devm_platform_ioremap_resource_byname(pdev, "phy"); + if (IS_ERR(host->sdphy)) + return PTR_ERR(host->sdphy); + + host->sdcore = devm_platform_ioremap_resource_byname(pdev, "core"); + if (IS_ERR(host->sdcore)) + return PTR_ERR(host->sdcore); + + host->sdreader = devm_platform_ioremap_resource_byname(pdev, "reader"); + if (IS_ERR(host->sdreader)) + return PTR_ERR(host->sdreader); + + host->sdwriter = devm_platform_ioremap_resource_byname(pdev, "writer"); + if (IS_ERR(host->sdwriter)) + return PTR_ERR(host->sdwriter); + + /* Ensure DMA bus masters are disabled */ + litex_write8(host->sdreader + LITEX_BLK2MEM_ENA, 0); + litex_write8(host->sdwriter + LITEX_MEM2BLK_ENA, 0); + + init_completion(&host->cmd_done); + ret = litex_mmc_irq_init(pdev, host); + if (ret) + return ret; + + mmc->ops = &litex_mmc_ops; + + ret = mmc_regulator_get_supply(mmc); + if (ret || mmc->ocr_avail == 0) { + dev_warn(dev, "can't get voltage, defaulting to 3.3V\n"); + mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; + } + + /* + * Set default sd_clk frequency range based on empirical observations + * of LiteSDCard gateware behavior on typical SDCard media + */ + mmc->f_min = 12.5e6; + mmc->f_max = 50e6; + + ret = mmc_of_parse(mmc); + if (ret) + return ret; + + /* Force 4-bit bus_width (only width supported by hardware) */ + mmc->caps &= ~MMC_CAP_8_BIT_DATA; + mmc->caps |= MMC_CAP_4_BIT_DATA; + + /* Set default capabilities */ + mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY | + MMC_CAP_DRIVER_TYPE_D | + MMC_CAP_CMD23; + mmc->caps2 |= MMC_CAP2_NO_WRITE_PROTECT | + MMC_CAP2_NO_SDIO | + MMC_CAP2_NO_MMC; + + platform_set_drvdata(pdev, host); + + ret = mmc_add_host(mmc); + if (ret) + return ret; + + dev_info(dev, "LiteX MMC controller initialized.\n"); + return 0; +} + +static int litex_mmc_remove(struct platform_device *pdev) +{ + struct litex_mmc_host *host = platform_get_drvdata(pdev); + + mmc_remove_host(host->mmc); + return 0; +} + +static const struct of_device_id litex_match[] = { + { .compatible = "litex,mmc" }, + { } +}; +MODULE_DEVICE_TABLE(of, litex_match); + +static struct platform_driver litex_mmc_driver = { + .probe = litex_mmc_probe, + .remove = litex_mmc_remove, + .driver = { + .name = "litex-mmc", + .of_match_table = litex_match, + }, +}; +module_platform_driver(litex_mmc_driver); + +MODULE_DESCRIPTION("LiteX SDCard driver"); +MODULE_AUTHOR("Antmicro <contact@antmicro.com>"); +MODULE_AUTHOR("Kamil Rakoczy <krakoczy@antmicro.com>"); +MODULE_AUTHOR("Maciej Dudek <mdudek@internships.antmicro.com>"); +MODULE_AUTHOR("Paul Mackerras <paulus@ozlabs.org>"); +MODULE_AUTHOR("Gabriel Somlo <gsomlo@gmail.com>"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c index 65037e1d7723..e61b0b98065a 100644 --- a/drivers/mmc/host/mtk-sd.c +++ b/drivers/mmc/host/mtk-sd.c @@ -1911,8 +1911,8 @@ static struct msdc_delay_phase get_best_delay(struct msdc_host *host, u32 delay) final_phase = (start_final + len_final / 3) % PAD_DELAY_MAX; else final_phase = (start_final + len_final / 2) % PAD_DELAY_MAX; - dev_info(host->dev, "phase: [map:%x] [maxlen:%d] [final:%d]\n", - delay, len_final, final_phase); + dev_dbg(host->dev, "phase: [map:%x] [maxlen:%d] [final:%d]\n", + delay, len_final, final_phase); delay_phase.maxlen = len_final; delay_phase.start = start_final; diff --git a/drivers/mmc/host/renesas_sdhi_internal_dmac.c b/drivers/mmc/host/renesas_sdhi_internal_dmac.c index 9d2c600fd4ce..1685df00863b 100644 --- a/drivers/mmc/host/renesas_sdhi_internal_dmac.c +++ b/drivers/mmc/host/renesas_sdhi_internal_dmac.c @@ -212,7 +212,7 @@ static const struct soc_device_attribute sdhi_quirks_match[] = { { .soc_id = "r8a7795", .revision = "ES2.0", .data = &sdhi_quirks_4tap }, { .soc_id = "r8a7796", .revision = "ES1.[012]", .data = &sdhi_quirks_4tap_nohs400 }, { .soc_id = "r8a7796", .revision = "ES1.*", .data = &sdhi_quirks_r8a7796_es13 }, - { /* Sentinel. */ }, + { /* Sentinel. */ } }; static const struct renesas_sdhi_of_data_with_quirks of_r8a7795_compatible = { diff --git a/drivers/mmc/host/rtsx_pci_sdmmc.c b/drivers/mmc/host/rtsx_pci_sdmmc.c index 58cfaffa3c2d..219029224727 100644 --- a/drivers/mmc/host/rtsx_pci_sdmmc.c +++ b/drivers/mmc/host/rtsx_pci_sdmmc.c @@ -38,10 +38,7 @@ struct realtek_pci_sdmmc { bool double_clk; bool eject; bool initial_mode; - int power_state; -#define SDMMC_POWER_ON 1 -#define SDMMC_POWER_OFF 0 - + int prev_power_state; int sg_count; s32 cookie; int cookie_sg_count; @@ -905,7 +902,7 @@ static int sd_set_bus_width(struct realtek_pci_sdmmc *host, return err; } -static int sd_power_on(struct realtek_pci_sdmmc *host) +static int sd_power_on(struct realtek_pci_sdmmc *host, unsigned char power_mode) { struct rtsx_pcr *pcr = host->pcr; struct mmc_host *mmc = host->mmc; @@ -913,9 +910,14 @@ static int sd_power_on(struct realtek_pci_sdmmc *host) u32 val; u8 test_mode; - if (host->power_state == SDMMC_POWER_ON) + if (host->prev_power_state == MMC_POWER_ON) return 0; + if (host->prev_power_state == MMC_POWER_UP) { + rtsx_pci_write_register(pcr, SD_BUS_STAT, SD_CLK_TOGGLE_EN, 0); + goto finish; + } + msleep(100); rtsx_pci_init_cmd(pcr); @@ -936,10 +938,15 @@ static int sd_power_on(struct realtek_pci_sdmmc *host) if (err < 0) return err; + mdelay(1); + err = rtsx_pci_write_register(pcr, CARD_OE, SD_OUTPUT_EN, SD_OUTPUT_EN); if (err < 0) return err; + /* send at least 74 clocks */ + rtsx_pci_write_register(pcr, SD_BUS_STAT, SD_CLK_TOGGLE_EN, SD_CLK_TOGGLE_EN); + if (PCI_PID(pcr) == PID_5261) { /* * If test mode is set switch to SD Express mandatorily, @@ -964,7 +971,8 @@ static int sd_power_on(struct realtek_pci_sdmmc *host) } } - host->power_state = SDMMC_POWER_ON; +finish: + host->prev_power_state = power_mode; return 0; } @@ -973,7 +981,7 @@ static int sd_power_off(struct realtek_pci_sdmmc *host) struct rtsx_pcr *pcr = host->pcr; int err; - host->power_state = SDMMC_POWER_OFF; + host->prev_power_state = MMC_POWER_OFF; rtsx_pci_init_cmd(pcr); @@ -999,7 +1007,7 @@ static int sd_set_power_mode(struct realtek_pci_sdmmc *host, if (power_mode == MMC_POWER_OFF) err = sd_power_off(host); else - err = sd_power_on(host); + err = sd_power_on(host, power_mode); return err; } @@ -1482,10 +1490,11 @@ static int rtsx_pci_sdmmc_drv_probe(struct platform_device *pdev) host = mmc_priv(mmc); host->pcr = pcr; + mmc->ios.power_delay_ms = 5; host->mmc = mmc; host->pdev = pdev; host->cookie = -1; - host->power_state = SDMMC_POWER_OFF; + host->prev_power_state = MMC_POWER_OFF; INIT_WORK(&host->work, sd_request); platform_set_drvdata(pdev, host); pcr->slots[RTSX_SD_CARD].p_dev = pdev; diff --git a/drivers/mmc/host/sdhci-of-at91.c b/drivers/mmc/host/sdhci-of-at91.c index d1a1c548c515..10fb4cb2c731 100644 --- a/drivers/mmc/host/sdhci-of-at91.c +++ b/drivers/mmc/host/sdhci-of-at91.c @@ -308,17 +308,15 @@ static const struct dev_pm_ops sdhci_at91_dev_pm_ops = { static int sdhci_at91_probe(struct platform_device *pdev) { - const struct of_device_id *match; const struct sdhci_at91_soc_data *soc_data; struct sdhci_host *host; struct sdhci_pltfm_host *pltfm_host; struct sdhci_at91_priv *priv; int ret; - match = of_match_device(sdhci_at91_dt_match, &pdev->dev); - if (!match) + soc_data = of_device_get_match_data(&pdev->dev); + if (!soc_data) return -EINVAL; - soc_data = match->data; host = sdhci_pltfm_init(pdev, soc_data->pdata, sizeof(*priv)); if (IS_ERR(host)) diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c index 0f3658b36513..d9dc41143bb3 100644 --- a/drivers/mmc/host/sdhci-of-esdhc.c +++ b/drivers/mmc/host/sdhci-of-esdhc.c @@ -934,7 +934,7 @@ static struct soc_device_attribute soc_tuning_erratum_type1[] = { { .family = "QorIQ T1040", }, { .family = "QorIQ T2080", }, { .family = "QorIQ LS1021A", }, - { }, + { /* sentinel */ } }; static struct soc_device_attribute soc_tuning_erratum_type2[] = { @@ -944,7 +944,7 @@ static struct soc_device_attribute soc_tuning_erratum_type2[] = { { .family = "QorIQ LS1080A", }, { .family = "QorIQ LS2080A", }, { .family = "QorIQ LA1575A", }, - { }, + { /* sentinel */ } }; static void esdhc_tuning_block_enable(struct sdhci_host *host, bool enable) @@ -1316,21 +1316,21 @@ static const struct sdhci_pltfm_data sdhci_esdhc_le_pdata = { static struct soc_device_attribute soc_incorrect_hostver[] = { { .family = "QorIQ T4240", .revision = "1.0", }, { .family = "QorIQ T4240", .revision = "2.0", }, - { }, + { /* sentinel */ } }; static struct soc_device_attribute soc_fixup_sdhc_clkdivs[] = { { .family = "QorIQ LX2160A", .revision = "1.0", }, { .family = "QorIQ LX2160A", .revision = "2.0", }, { .family = "QorIQ LS1028A", .revision = "1.0", }, - { }, + { /* sentinel */ } }; static struct soc_device_attribute soc_unreliable_pulse_detection[] = { { .family = "QorIQ LX2160A", .revision = "1.0", }, { .family = "QorIQ LX2160A", .revision = "2.0", }, { .family = "QorIQ LS1028A", .revision = "1.0", }, - { }, + { /* sentinel */ } }; static void esdhc_init(struct platform_device *pdev, struct sdhci_host *host) diff --git a/drivers/mmc/host/sdhci-pci-gli.c b/drivers/mmc/host/sdhci-pci-gli.c index 97035d77c18c..d09728c37d03 100644 --- a/drivers/mmc/host/sdhci-pci-gli.c +++ b/drivers/mmc/host/sdhci-pci-gli.c @@ -13,6 +13,7 @@ #include <linux/mmc/mmc.h> #include <linux/delay.h> #include <linux/of.h> +#include <linux/iopoll.h> #include "sdhci.h" #include "sdhci-pci.h" #include "cqhci.h" @@ -63,6 +64,7 @@ #define GLI_9750_MISC_RX_INV_OFF 0x0 #define GLI_9750_MISC_RX_INV_VALUE GLI_9750_MISC_RX_INV_OFF #define GLI_9750_MISC_TX1_DLY_VALUE 0x5 +#define SDHCI_GLI_9750_MISC_SSC_OFF BIT(26) #define SDHCI_GLI_9750_TUNING_CONTROL 0x540 #define SDHCI_GLI_9750_TUNING_CONTROL_EN BIT(4) @@ -137,6 +139,9 @@ #define PCI_GLI_9755_SerDes 0x70 #define PCI_GLI_9755_SCP_DIS BIT(19) +#define PCI_GLI_9755_MISC 0x78 +#define PCI_GLI_9755_MISC_SSC_OFF BIT(26) + #define GLI_MAX_TUNING_LOOP 40 /* Genesys Logic chipset */ @@ -371,6 +376,19 @@ static void gl9750_set_pll(struct sdhci_host *host, u8 dir, u16 ldiv, u8 pdiv) mdelay(1); } +static bool gl9750_ssc_enable(struct sdhci_host *host) +{ + u32 misc; + u8 off; + + gl9750_wt_on(host); + misc = sdhci_readl(host, SDHCI_GLI_9750_MISC); + off = FIELD_GET(SDHCI_GLI_9750_MISC_SSC_OFF, misc); + gl9750_wt_off(host); + + return !off; +} + static void gl9750_set_ssc(struct sdhci_host *host, u8 enable, u8 step, u16 ppm) { u32 pll; @@ -392,11 +410,31 @@ static void gl9750_set_ssc(struct sdhci_host *host, u8 enable, u8 step, u16 ppm) static void gl9750_set_ssc_pll_205mhz(struct sdhci_host *host) { - /* set pll to 205MHz and enable ssc */ - gl9750_set_ssc(host, 0x1, 0x1F, 0xFFE7); + bool enable = gl9750_ssc_enable(host); + + /* set pll to 205MHz and ssc */ + gl9750_set_ssc(host, enable, 0xF, 0x5A1D); gl9750_set_pll(host, 0x1, 0x246, 0x0); } +static void gl9750_set_ssc_pll_100mhz(struct sdhci_host *host) +{ + bool enable = gl9750_ssc_enable(host); + + /* set pll to 100MHz and ssc */ + gl9750_set_ssc(host, enable, 0xE, 0x51EC); + gl9750_set_pll(host, 0x1, 0x244, 0x1); +} + +static void gl9750_set_ssc_pll_50mhz(struct sdhci_host *host) +{ + bool enable = gl9750_ssc_enable(host); + + /* set pll to 50MHz and ssc */ + gl9750_set_ssc(host, enable, 0xE, 0x51EC); + gl9750_set_pll(host, 0x1, 0x244, 0x3); +} + static void sdhci_gl9750_set_clock(struct sdhci_host *host, unsigned int clock) { struct mmc_ios *ios = &host->mmc->ios; @@ -414,6 +452,10 @@ static void sdhci_gl9750_set_clock(struct sdhci_host *host, unsigned int clock) if (clock == 200000000 && ios->timing == MMC_TIMING_UHS_SDR104) { host->mmc->actual_clock = 205000000; gl9750_set_ssc_pll_205mhz(host); + } else if (clock == 100000000) { + gl9750_set_ssc_pll_100mhz(host); + } else if (clock == 50000000) { + gl9750_set_ssc_pll_50mhz(host); } sdhci_enable_clk(host, clk); @@ -514,6 +556,19 @@ static void gl9755_set_pll(struct pci_dev *pdev, u8 dir, u16 ldiv, u8 pdiv) mdelay(1); } +static bool gl9755_ssc_enable(struct pci_dev *pdev) +{ + u32 misc; + u8 off; + + gl9755_wt_on(pdev); + pci_read_config_dword(pdev, PCI_GLI_9755_MISC, &misc); + off = FIELD_GET(PCI_GLI_9755_MISC_SSC_OFF, misc); + gl9755_wt_off(pdev); + + return !off; +} + static void gl9755_set_ssc(struct pci_dev *pdev, u8 enable, u8 step, u16 ppm) { u32 pll; @@ -535,11 +590,31 @@ static void gl9755_set_ssc(struct pci_dev *pdev, u8 enable, u8 step, u16 ppm) static void gl9755_set_ssc_pll_205mhz(struct pci_dev *pdev) { - /* set pll to 205MHz and enable ssc */ - gl9755_set_ssc(pdev, 0x1, 0x1F, 0xFFE7); + bool enable = gl9755_ssc_enable(pdev); + + /* set pll to 205MHz and ssc */ + gl9755_set_ssc(pdev, enable, 0xF, 0x5A1D); gl9755_set_pll(pdev, 0x1, 0x246, 0x0); } +static void gl9755_set_ssc_pll_100mhz(struct pci_dev *pdev) +{ + bool enable = gl9755_ssc_enable(pdev); + + /* set pll to 100MHz and ssc */ + gl9755_set_ssc(pdev, enable, 0xE, 0x51EC); + gl9755_set_pll(pdev, 0x1, 0x244, 0x1); +} + +static void gl9755_set_ssc_pll_50mhz(struct pci_dev *pdev) +{ + bool enable = gl9755_ssc_enable(pdev); + + /* set pll to 50MHz and ssc */ + gl9755_set_ssc(pdev, enable, 0xE, 0x51EC); + gl9755_set_pll(pdev, 0x1, 0x244, 0x3); +} + static void sdhci_gl9755_set_clock(struct sdhci_host *host, unsigned int clock) { struct sdhci_pci_slot *slot = sdhci_priv(host); @@ -560,6 +635,10 @@ static void sdhci_gl9755_set_clock(struct sdhci_host *host, unsigned int clock) if (clock == 200000000 && ios->timing == MMC_TIMING_UHS_SDR104) { host->mmc->actual_clock = 205000000; gl9755_set_ssc_pll_205mhz(pdev); + } else if (clock == 100000000) { + gl9755_set_ssc_pll_100mhz(pdev); + } else if (clock == 50000000) { + gl9755_set_ssc_pll_50mhz(pdev); } sdhci_enable_clk(host, clk); @@ -873,6 +952,47 @@ static void gli_set_gl9763e(struct sdhci_pci_slot *slot) pci_write_config_dword(pdev, PCIE_GLI_9763E_VHS, value); } +#ifdef CONFIG_PM +static int gl9763e_runtime_suspend(struct sdhci_pci_chip *chip) +{ + struct sdhci_pci_slot *slot = chip->slots[0]; + struct sdhci_host *host = slot->host; + u16 clock; + + clock = sdhci_readw(host, SDHCI_CLOCK_CONTROL); + clock &= ~(SDHCI_CLOCK_PLL_EN | SDHCI_CLOCK_CARD_EN); + sdhci_writew(host, clock, SDHCI_CLOCK_CONTROL); + + return 0; +} + +static int gl9763e_runtime_resume(struct sdhci_pci_chip *chip) +{ + struct sdhci_pci_slot *slot = chip->slots[0]; + struct sdhci_host *host = slot->host; + u16 clock; + + clock = sdhci_readw(host, SDHCI_CLOCK_CONTROL); + + clock |= SDHCI_CLOCK_PLL_EN; + clock &= ~SDHCI_CLOCK_INT_STABLE; + sdhci_writew(host, clock, SDHCI_CLOCK_CONTROL); + + /* Wait max 150 ms */ + if (read_poll_timeout(sdhci_readw, clock, (clock & SDHCI_CLOCK_INT_STABLE), + 1000, 150000, false, host, SDHCI_CLOCK_CONTROL)) { + pr_err("%s: PLL clock never stabilised.\n", + mmc_hostname(host->mmc)); + sdhci_dumpregs(host); + } + + clock |= SDHCI_CLOCK_CARD_EN; + sdhci_writew(host, clock, SDHCI_CLOCK_CONTROL); + + return 0; +} +#endif + static int gli_probe_slot_gl9763e(struct sdhci_pci_slot *slot) { struct pci_dev *pdev = slot->chip->pdev; @@ -983,5 +1103,10 @@ const struct sdhci_pci_fixes sdhci_gl9763e = { .resume = sdhci_cqhci_gli_resume, .suspend = sdhci_cqhci_gli_suspend, #endif +#ifdef CONFIG_PM + .runtime_suspend = gl9763e_runtime_suspend, + .runtime_resume = gl9763e_runtime_resume, + .allow_runtime_pm = true, +#endif .add_host = gl9763e_add_host, }; diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c index 35ebba067e87..2d2d8260c681 100644 --- a/drivers/mmc/host/sdhci-tegra.c +++ b/drivers/mmc/host/sdhci-tegra.c @@ -1618,7 +1618,6 @@ cleanup: static int sdhci_tegra_probe(struct platform_device *pdev) { - const struct of_device_id *match; const struct sdhci_tegra_soc_data *soc_data; struct sdhci_host *host; struct sdhci_pltfm_host *pltfm_host; @@ -1626,10 +1625,9 @@ static int sdhci_tegra_probe(struct platform_device *pdev) struct clk *clk; int rc; - match = of_match_device(sdhci_tegra_dt_match, &pdev->dev); - if (!match) + soc_data = of_device_get_match_data(&pdev->dev); + if (!soc_data) return -EINVAL; - soc_data = match->data; host = sdhci_pltfm_init(pdev, soc_data->pdata, sizeof(*tegra_host)); if (IS_ERR(host)) @@ -1673,6 +1671,9 @@ static int sdhci_tegra_probe(struct platform_device *pdev) /* HW busy detection is supported, but R1B responses are required. */ host->mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_NEED_RSP_BUSY; + /* GPIO CD can be set as a wakeup source */ + host->mmc->caps |= MMC_CAP_CD_WAKE; + tegra_sdhci_parse_dt(host); tegra_host->power_gpio = devm_gpiod_get_optional(&pdev->dev, "power", @@ -1840,7 +1841,7 @@ static int sdhci_tegra_suspend(struct device *dev) return ret; } - return 0; + return mmc_gpio_set_cd_wake(host->mmc, true); } static int sdhci_tegra_resume(struct device *dev) @@ -1848,6 +1849,10 @@ static int sdhci_tegra_resume(struct device *dev) struct sdhci_host *host = dev_get_drvdata(dev); int ret; + ret = mmc_gpio_set_cd_wake(host->mmc, false); + if (ret) + return ret; + ret = pm_runtime_force_resume(dev); if (ret) return ret; diff --git a/drivers/mmc/host/sdhci_am654.c b/drivers/mmc/host/sdhci_am654.c index f654afbe8e83..e54fe24d47e7 100644 --- a/drivers/mmc/host/sdhci_am654.c +++ b/drivers/mmc/host/sdhci_am654.c @@ -514,26 +514,6 @@ static const struct sdhci_am654_driver_data sdhci_j721e_4bit_drvdata = { .flags = IOMUX_PRESENT, }; -static const struct sdhci_pltfm_data sdhci_am64_8bit_pdata = { - .ops = &sdhci_j721e_8bit_ops, - .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN, -}; - -static const struct sdhci_am654_driver_data sdhci_am64_8bit_drvdata = { - .pdata = &sdhci_am64_8bit_pdata, - .flags = DLL_PRESENT | DLL_CALIB, -}; - -static const struct sdhci_pltfm_data sdhci_am64_4bit_pdata = { - .ops = &sdhci_j721e_4bit_ops, - .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN, -}; - -static const struct sdhci_am654_driver_data sdhci_am64_4bit_drvdata = { - .pdata = &sdhci_am64_4bit_pdata, - .flags = IOMUX_PRESENT, -}; - static const struct soc_device_attribute sdhci_am654_devices[] = { { .family = "AM65X", .revision = "SR1.0", @@ -759,11 +739,15 @@ static const struct of_device_id sdhci_am654_of_match[] = { }, { .compatible = "ti,am64-sdhci-8bit", - .data = &sdhci_am64_8bit_drvdata, + .data = &sdhci_j721e_8bit_drvdata, }, { .compatible = "ti,am64-sdhci-4bit", - .data = &sdhci_am64_4bit_drvdata, + .data = &sdhci_j721e_4bit_drvdata, + }, + { + .compatible = "ti,am62-sdhci", + .data = &sdhci_j721e_4bit_drvdata, }, { /* sentinel */ } }; diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c index 104dcd702870..5f9ebf045b1c 100644 --- a/drivers/mmc/host/sh_mmcif.c +++ b/drivers/mmc/host/sh_mmcif.c @@ -521,8 +521,7 @@ static void sh_mmcif_clock_control(struct sh_mmcif_host *host, unsigned int clk) } dev_dbg(dev, "clk %u/%u (%u, 0x%x)\n", - (best_freq / (1 << (clkdiv + 1))), clk, - best_freq, clkdiv); + (best_freq >> (clkdiv + 1)), clk, best_freq, clkdiv); clk_set_rate(host->clk, best_freq); clkdiv = clkdiv << 16; @@ -1012,8 +1011,8 @@ static void sh_mmcif_clk_setup(struct sh_mmcif_host *host) */ host->clkdiv_map = 0x3ff; - host->mmc->f_max = f_max / (1 << ffs(host->clkdiv_map)); - host->mmc->f_min = f_min / (1 << fls(host->clkdiv_map)); + host->mmc->f_max = f_max >> ffs(host->clkdiv_map); + host->mmc->f_min = f_min >> fls(host->clkdiv_map); } else { unsigned int clk = clk_get_rate(host->clk); diff --git a/drivers/mmc/host/sunxi-mmc.c b/drivers/mmc/host/sunxi-mmc.c index 2702736a1c57..c62afd212692 100644 --- a/drivers/mmc/host/sunxi-mmc.c +++ b/drivers/mmc/host/sunxi-mmc.c @@ -1167,6 +1167,14 @@ static const struct sunxi_mmc_cfg sun9i_a80_cfg = { .can_calibrate = false, }; +static const struct sunxi_mmc_cfg sun20i_d1_cfg = { + .idma_des_size_bits = 13, + .idma_des_shift = 2, + .can_calibrate = true, + .mask_data0 = true, + .needs_new_timings = true, +}; + static const struct sunxi_mmc_cfg sun50i_a64_cfg = { .idma_des_size_bits = 16, .clk_delays = NULL, @@ -1205,6 +1213,7 @@ static const struct of_device_id sunxi_mmc_of_match[] = { { .compatible = "allwinner,sun7i-a20-mmc", .data = &sun7i_a20_cfg }, { .compatible = "allwinner,sun8i-a83t-emmc", .data = &sun8i_a83t_emmc_cfg }, { .compatible = "allwinner,sun9i-a80-mmc", .data = &sun9i_a80_cfg }, + { .compatible = "allwinner,sun20i-d1-mmc", .data = &sun20i_d1_cfg }, { .compatible = "allwinner,sun50i-a64-mmc", .data = &sun50i_a64_cfg }, { .compatible = "allwinner,sun50i-a64-emmc", .data = &sun50i_a64_emmc_cfg }, { .compatible = "allwinner,sun50i-a100-mmc", .data = &sun50i_a100_cfg }, diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h index f936aad945ce..e754bb3f5c32 100644 --- a/drivers/mmc/host/tmio_mmc.h +++ b/drivers/mmc/host/tmio_mmc.h @@ -186,10 +186,6 @@ struct tmio_mmc_host { void (*fixup_request)(struct tmio_mmc_host *host, struct mmc_request *mrq); unsigned int (*get_timeout_cycles)(struct tmio_mmc_host *host); - void (*prepare_hs400_tuning)(struct tmio_mmc_host *host); - void (*hs400_downgrade)(struct tmio_mmc_host *host); - void (*hs400_complete)(struct tmio_mmc_host *host); - const struct tmio_mmc_dma_ops *dma_ops; }; diff --git a/drivers/mmc/host/wmt-sdmmc.c b/drivers/mmc/host/wmt-sdmmc.c index cf10949fb0ac..163ac9df8cca 100644 --- a/drivers/mmc/host/wmt-sdmmc.c +++ b/drivers/mmc/host/wmt-sdmmc.c @@ -751,19 +751,16 @@ static int wmt_mci_probe(struct platform_device *pdev) struct mmc_host *mmc; struct wmt_mci_priv *priv; struct device_node *np = pdev->dev.of_node; - const struct of_device_id *of_id = - of_match_device(wmt_mci_dt_ids, &pdev->dev); const struct wmt_mci_caps *wmt_caps; int ret; int regular_irq, dma_irq; - if (!of_id || !of_id->data) { + wmt_caps = of_device_get_match_data(&pdev->dev); + if (!wmt_caps) { dev_err(&pdev->dev, "Controller capabilities data missing\n"); return -EFAULT; } - wmt_caps = of_id->data; - if (!np) { dev_err(&pdev->dev, "Missing SDMMC description in devicetree\n"); return -EFAULT; |