Commit 01e5d183 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'mmc-v5.2' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc

Pull MMC updates from Ulf Hansson:
 "MMC core:
   - Fix a few memoryleaks
   - Minor improvements to the card initialization sequence
   - Partially support sleepy GPIO controllers for pwrseq eMMC

  MMC host:
   - alcor: Work with multiple-entry sglists
   - alcor: Enable DMA for writes
   - meson-gx: Improve tuning support
   - meson-gx: Avoid clock glitch when switching to DDR modes
   - meson-gx: Disable unreliable HS400 mode
   - mmci: Minor updates for support of HW busy detection
   - mmci: Support data transfers for the stm32_sdmmc variant
   - mmci: Restructure code to better support different variants
   - mtk-sd: Add support for version found on MT7620 family SOCs
   - mtk-sd: Add support for the MT8516 version
   - mtk-sd: Add Chaotian Jing as the maintainer
   - sdhci: Reorganize request-code to convert from tasklet to workqueue
   - sdhci_am654: Stabilize support for lower speed modes
   - sdhci-esdhc-imx: Add HS400 support for iMX7ULP
   - sdhci-esdhc-imx: Add support for iMX7ULP version
   - sdhci-of-arasan: Allow to disable DCMDs via DT for CQE
   - sdhci-of-esdhc: Add support for the ls1028a version
   - sdhci-of-esdhc: Several fixups for errata
   - sdhci-pci: Fix BYT OCP setting
   - sdhci-pci: Add support for Intel CML
   - sdhci-tegra: Add support for system suspend/resume
   - sdhci-tegra: Add CQE support for Tegra186 WAR
   - sdhci-tegra: Add support for Tegra194
   - sdhci-tegra: Update HW tuning process

  MEMSTICK:
   - I volunteered to help as a maintainer for the memstick subsystem,
     which is reflected by an update to the MAINTAINERS file. Changes
     are funneled through my MMC git and we will use the linux-mmc
     mailing list.

  MEMSTICK host:
   - A few minor cleanups"

* tag 'mmc-v5.2' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc: (87 commits)
  mmc: sdhci-pci: Fix BYT OCP setting
  dt-bindings: mmc: add DT bindings for ls1028a eSDHC host controller
  mmc: alcor: Drop pointer to mmc_host from alcor_sdmmc_host
  mmc: mtk-sd: select REGULATOR
  mmc: mtk-sd: enable internal card-detect logic.
  mmc: mtk-sd: add support for config found in mt7620 family SOCs.
  mmc: mtk-sd: don't hard-code interrupt trigger type
  mmc: core: Fix tag set memory leak
  dt-bindings: mmc: Add support for MT8516 to mtk-sd
  mmc: mmci: Prevent polling for busy detection in IRQ context
  mmc: mmci: Cleanup mmci_cmd_irq() for busy detect
  mmc: usdhi6rol0: mark expected switch fall-throughs
  mmc: core: Verify SD bus width
  mmc: sdhci-esdhc-imx: Add HS400 support for iMX7ULP
  mmc: sdhci-esdhc-imx: add pm_qos to interact with cpuidle
  dt-bindings: mmc: fsl-imx-esdhc: add imx7ulp compatible string
  mmc: meson-gx: add signal resampling tuning
  mmc: meson-gx: remove Rx phase tuning
  mmc: meson-gx: avoid clock glitch when switching to DDR modes
  mmc: meson-gx: disable HS400
  ...
parents b4b52b88 0a49a619
...@@ -17,6 +17,7 @@ Required properties: ...@@ -17,6 +17,7 @@ Required properties:
"fsl,t4240-esdhc" "fsl,t4240-esdhc"
Possible compatibles for ARM: Possible compatibles for ARM:
"fsl,ls1012a-esdhc" "fsl,ls1012a-esdhc"
"fsl,ls1028a-esdhc"
"fsl,ls1088a-esdhc" "fsl,ls1088a-esdhc"
"fsl,ls1043a-esdhc" "fsl,ls1043a-esdhc"
"fsl,ls1046a-esdhc" "fsl,ls1046a-esdhc"
......
...@@ -17,6 +17,7 @@ Required properties: ...@@ -17,6 +17,7 @@ Required properties:
"fsl,imx6sx-usdhc" "fsl,imx6sx-usdhc"
"fsl,imx6ull-usdhc" "fsl,imx6ull-usdhc"
"fsl,imx7d-usdhc" "fsl,imx7d-usdhc"
"fsl,imx7ulp-usdhc"
"fsl,imx8qxp-usdhc" "fsl,imx8qxp-usdhc"
Optional properties: Optional properties:
......
...@@ -64,6 +64,8 @@ Optional properties: ...@@ -64,6 +64,8 @@ Optional properties:
whether pwrseq-simple is used. Default to 10ms if no available. whether pwrseq-simple is used. Default to 10ms if no available.
- supports-cqe : The presence of this property indicates that the corresponding - supports-cqe : The presence of this property indicates that the corresponding
MMC host controller supports HW command queue feature. MMC host controller supports HW command queue feature.
- disable-cqe-dcmd: This property indicates that the MMC controller's command
queue engine (CQE) does not support direct commands (DCMDs).
*NOTE* on CD and WP polarity. To use common for all SD/MMC host controllers line *NOTE* on CD and WP polarity. To use common for all SD/MMC host controllers line
polarity properties, we have to fix the meaning of the "normal" and "inverted" polarity properties, we have to fix the meaning of the "normal" and "inverted"
......
...@@ -11,10 +11,12 @@ Required properties: ...@@ -11,10 +11,12 @@ Required properties:
"mediatek,mt8135-mmc": for mmc host ip compatible with mt8135 "mediatek,mt8135-mmc": for mmc host ip compatible with mt8135
"mediatek,mt8173-mmc": for mmc host ip compatible with mt8173 "mediatek,mt8173-mmc": for mmc host ip compatible with mt8173
"mediatek,mt8183-mmc": for mmc host ip compatible with mt8183 "mediatek,mt8183-mmc": for mmc host ip compatible with mt8183
"mediatek,mt8516-mmc": for mmc host ip compatible with mt8516
"mediatek,mt2701-mmc": for mmc host ip compatible with mt2701 "mediatek,mt2701-mmc": for mmc host ip compatible with mt2701
"mediatek,mt2712-mmc": for mmc host ip compatible with mt2712 "mediatek,mt2712-mmc": for mmc host ip compatible with mt2712
"mediatek,mt7622-mmc": for MT7622 SoC "mediatek,mt7622-mmc": for MT7622 SoC
"mediatek,mt7623-mmc", "mediatek,mt2701-mmc": for MT7623 SoC "mediatek,mt7623-mmc", "mediatek,mt2701-mmc": for MT7623 SoC
"mediatek,mt7620-mmc", for MT7621 SoC (and others)
- reg: physical base address of the controller and length - reg: physical base address of the controller and length
- interrupts: Should contain MSDC interrupt number - interrupts: Should contain MSDC interrupt number
......
...@@ -14,6 +14,7 @@ Required properties: ...@@ -14,6 +14,7 @@ Required properties:
- "nvidia,tegra124-sdhci": for Tegra124 and Tegra132 - "nvidia,tegra124-sdhci": for Tegra124 and Tegra132
- "nvidia,tegra210-sdhci": for Tegra210 - "nvidia,tegra210-sdhci": for Tegra210
- "nvidia,tegra186-sdhci": for Tegra186 - "nvidia,tegra186-sdhci": for Tegra186
- "nvidia,tegra194-sdhci": for Tegra194
- clocks : Must contain one entry, for the module clock. - clocks : Must contain one entry, for the module clock.
See ../clocks/clock-bindings.txt for details. See ../clocks/clock-bindings.txt for details.
- resets : Must contain an entry for each entry in reset-names. - resets : Must contain an entry for each entry in reset-names.
......
...@@ -9785,6 +9785,12 @@ F: drivers/media/platform/mtk-vpu/ ...@@ -9785,6 +9785,12 @@ F: drivers/media/platform/mtk-vpu/
F: Documentation/devicetree/bindings/media/mediatek-vcodec.txt F: Documentation/devicetree/bindings/media/mediatek-vcodec.txt
F: Documentation/devicetree/bindings/media/mediatek-vpu.txt F: Documentation/devicetree/bindings/media/mediatek-vpu.txt
MEDIATEK MMC/SD/SDIO DRIVER
M: Chaotian Jing <chaotian.jing@mediatek.com>
S: Maintained
F: drivers/mmc/host/mtk-sd.c
F: Documentation/devicetree/bindings/mmc/mtk-sd.txt
MEDIATEK MT76 WIRELESS LAN DRIVER MEDIATEK MT76 WIRELESS LAN DRIVER
M: Felix Fietkau <nbd@nbd.name> M: Felix Fietkau <nbd@nbd.name>
M: Lorenzo Bianconi <lorenzo.bianconi83@gmail.com> M: Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
...@@ -14484,16 +14490,15 @@ T: git git://linuxtv.org/media_tree.git ...@@ -14484,16 +14490,15 @@ T: git git://linuxtv.org/media_tree.git
S: Maintained S: Maintained
F: drivers/media/i2c/imx355.c F: drivers/media/i2c/imx355.c
SONY MEMORYSTICK CARD SUPPORT SONY MEMORYSTICK SUBSYSTEM
M: Alex Dubov <oakad@yahoo.com>
W: http://tifmxx.berlios.de/
S: Maintained
F: drivers/memstick/host/tifm_ms.c
SONY MEMORYSTICK STANDARD SUPPORT
M: Maxim Levitsky <maximlevitsky@gmail.com> M: Maxim Levitsky <maximlevitsky@gmail.com>
M: Alex Dubov <oakad@yahoo.com>
M: Ulf Hansson <ulf.hansson@linaro.org>
L: linux-mmc@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc.git
S: Maintained S: Maintained
F: drivers/memstick/core/ms_block.* F: drivers/memstick/
F: include/linux/memstick.h
SONY VAIO CONTROL DEVICE DRIVER SONY VAIO CONTROL DEVICE DRIVER
M: Mattia Dongili <malattia@linux.it> M: Mattia Dongili <malattia@linux.it>
...@@ -15518,9 +15523,11 @@ S: Maintained ...@@ -15518,9 +15523,11 @@ S: Maintained
F: drivers/net/ethernet/ti/cpsw* F: drivers/net/ethernet/ti/cpsw*
F: drivers/net/ethernet/ti/davinci* F: drivers/net/ethernet/ti/davinci*
TI FLASH MEDIA INTERFACE DRIVER TI FLASH MEDIA MEMORYSTICK/MMC DRIVERS
M: Alex Dubov <oakad@yahoo.com> M: Alex Dubov <oakad@yahoo.com>
S: Maintained S: Maintained
W: http://tifmxx.berlios.de/
F: drivers/memstick/host/tifm_ms.c
F: drivers/misc/tifm* F: drivers/misc/tifm*
F: drivers/mmc/host/tifm_sd.c F: drivers/mmc/host/tifm_sd.c
F: include/linux/tifm.h F: include/linux/tifm.h
......
...@@ -370,7 +370,6 @@ static int jmb38x_ms_transfer_data(struct jmb38x_ms_host *host) ...@@ -370,7 +370,6 @@ static int jmb38x_ms_transfer_data(struct jmb38x_ms_host *host)
static int jmb38x_ms_issue_cmd(struct memstick_host *msh) static int jmb38x_ms_issue_cmd(struct memstick_host *msh)
{ {
struct jmb38x_ms_host *host = memstick_priv(msh); struct jmb38x_ms_host *host = memstick_priv(msh);
unsigned char *data;
unsigned int data_len, cmd, t_val; unsigned int data_len, cmd, t_val;
if (!(STATUS_HAS_MEDIA & readl(host->addr + STATUS))) { if (!(STATUS_HAS_MEDIA & readl(host->addr + STATUS))) {
...@@ -402,8 +401,6 @@ static int jmb38x_ms_issue_cmd(struct memstick_host *msh) ...@@ -402,8 +401,6 @@ static int jmb38x_ms_issue_cmd(struct memstick_host *msh)
cmd |= TPC_WAIT_INT; cmd |= TPC_WAIT_INT;
} }
data = host->req->data;
if (!no_dma) if (!no_dma)
host->cmd_flags |= DMA_DATA; host->cmd_flags |= DMA_DATA;
......
...@@ -256,7 +256,6 @@ static unsigned int tifm_ms_transfer_data(struct tifm_ms *host) ...@@ -256,7 +256,6 @@ static unsigned int tifm_ms_transfer_data(struct tifm_ms *host)
static int tifm_ms_issue_cmd(struct tifm_ms *host) static int tifm_ms_issue_cmd(struct tifm_ms *host)
{ {
struct tifm_dev *sock = host->dev; struct tifm_dev *sock = host->dev;
unsigned char *data;
unsigned int data_len, cmd, sys_param; unsigned int data_len, cmd, sys_param;
host->cmd_flags = 0; host->cmd_flags = 0;
...@@ -265,8 +264,6 @@ static int tifm_ms_issue_cmd(struct tifm_ms *host) ...@@ -265,8 +264,6 @@ static int tifm_ms_issue_cmd(struct tifm_ms *host)
host->io_word = 0; host->io_word = 0;
host->cmd_flags = 0; host->cmd_flags = 0;
data = host->req->data;
host->use_dma = !no_dma; host->use_dma = !no_dma;
if (host->req->long_data) { if (host->req->long_data) {
......
...@@ -363,11 +363,11 @@ int mmc_of_parse_voltage(struct device_node *np, u32 *mask) ...@@ -363,11 +363,11 @@ int mmc_of_parse_voltage(struct device_node *np, u32 *mask)
int num_ranges, i; int num_ranges, i;
voltage_ranges = of_get_property(np, "voltage-ranges", &num_ranges); voltage_ranges = of_get_property(np, "voltage-ranges", &num_ranges);
num_ranges = num_ranges / sizeof(*voltage_ranges) / 2;
if (!voltage_ranges) { if (!voltage_ranges) {
pr_debug("%pOF: voltage-ranges unspecified\n", np); pr_debug("%pOF: voltage-ranges unspecified\n", np);
return 0; return 0;
} }
num_ranges = num_ranges / sizeof(*voltage_ranges) / 2;
if (!num_ranges) { if (!num_ranges) {
pr_err("%pOF: voltage-ranges empty\n", np); pr_err("%pOF: voltage-ranges empty\n", np);
return -EINVAL; return -EINVAL;
...@@ -429,8 +429,6 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev) ...@@ -429,8 +429,6 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
if (mmc_gpio_alloc(host)) { if (mmc_gpio_alloc(host)) {
put_device(&host->class_dev); put_device(&host->class_dev);
ida_simple_remove(&mmc_host_ida, host->index);
kfree(host);
return NULL; return NULL;
} }
......
...@@ -184,11 +184,7 @@ int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) ...@@ -184,11 +184,7 @@ int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
if (err) if (err)
break; break;
/* if we're just probing, do a single pass */ /* wait until reset completes */
if (ocr == 0)
break;
/* otherwise wait until reset completes */
if (mmc_host_is_spi(host)) { if (mmc_host_is_spi(host)) {
if (!(cmd.resp[0] & R1_SPI_IDLE)) if (!(cmd.resp[0] & R1_SPI_IDLE))
break; break;
...@@ -200,6 +196,16 @@ int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) ...@@ -200,6 +196,16 @@ int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
err = -ETIMEDOUT; err = -ETIMEDOUT;
mmc_delay(10); mmc_delay(10);
/*
* According to eMMC specification v5.1 section 6.4.3, we
* should issue CMD1 repeatedly in the idle state until
* the eMMC is ready. Otherwise some eMMC devices seem to enter
* the inactive mode after mmc_init_card() issued CMD0 when
* the eMMC device is busy.
*/
if (!ocr && !mmc_host_is_spi(host))
cmd.arg = cmd.resp[0] | BIT(30);
} }
if (rocr && !mmc_host_is_spi(host)) if (rocr && !mmc_host_is_spi(host))
......
...@@ -30,19 +30,14 @@ struct mmc_pwrseq_emmc { ...@@ -30,19 +30,14 @@ struct mmc_pwrseq_emmc {
#define to_pwrseq_emmc(p) container_of(p, struct mmc_pwrseq_emmc, pwrseq) #define to_pwrseq_emmc(p) container_of(p, struct mmc_pwrseq_emmc, pwrseq)
static void __mmc_pwrseq_emmc_reset(struct mmc_pwrseq_emmc *pwrseq)
{
gpiod_set_value(pwrseq->reset_gpio, 1);
udelay(1);
gpiod_set_value(pwrseq->reset_gpio, 0);
udelay(200);
}
static void mmc_pwrseq_emmc_reset(struct mmc_host *host) static void mmc_pwrseq_emmc_reset(struct mmc_host *host)
{ {
struct mmc_pwrseq_emmc *pwrseq = to_pwrseq_emmc(host->pwrseq); struct mmc_pwrseq_emmc *pwrseq = to_pwrseq_emmc(host->pwrseq);
__mmc_pwrseq_emmc_reset(pwrseq); gpiod_set_value_cansleep(pwrseq->reset_gpio, 1);
udelay(1);
gpiod_set_value_cansleep(pwrseq->reset_gpio, 0);
udelay(200);
} }
static int mmc_pwrseq_emmc_reset_nb(struct notifier_block *this, static int mmc_pwrseq_emmc_reset_nb(struct notifier_block *this,
...@@ -50,8 +45,11 @@ static int mmc_pwrseq_emmc_reset_nb(struct notifier_block *this, ...@@ -50,8 +45,11 @@ static int mmc_pwrseq_emmc_reset_nb(struct notifier_block *this,
{ {
struct mmc_pwrseq_emmc *pwrseq = container_of(this, struct mmc_pwrseq_emmc *pwrseq = container_of(this,
struct mmc_pwrseq_emmc, reset_nb); struct mmc_pwrseq_emmc, reset_nb);
gpiod_set_value(pwrseq->reset_gpio, 1);
udelay(1);
gpiod_set_value(pwrseq->reset_gpio, 0);
udelay(200);
__mmc_pwrseq_emmc_reset(pwrseq);
return NOTIFY_DONE; return NOTIFY_DONE;
} }
...@@ -72,14 +70,18 @@ static int mmc_pwrseq_emmc_probe(struct platform_device *pdev) ...@@ -72,14 +70,18 @@ static int mmc_pwrseq_emmc_probe(struct platform_device *pdev)
if (IS_ERR(pwrseq->reset_gpio)) if (IS_ERR(pwrseq->reset_gpio))
return PTR_ERR(pwrseq->reset_gpio); return PTR_ERR(pwrseq->reset_gpio);
/* if (!gpiod_cansleep(pwrseq->reset_gpio)) {
* register reset handler to ensure emmc reset also from /*
* emergency_reboot(), priority 255 is the highest priority * register reset handler to ensure emmc reset also from
* so it will be executed before any system reboot handler. * emergency_reboot(), priority 255 is the highest priority
*/ * so it will be executed before any system reboot handler.
pwrseq->reset_nb.notifier_call = mmc_pwrseq_emmc_reset_nb; */
pwrseq->reset_nb.priority = 255; pwrseq->reset_nb.notifier_call = mmc_pwrseq_emmc_reset_nb;
register_restart_handler(&pwrseq->reset_nb); pwrseq->reset_nb.priority = 255;
register_restart_handler(&pwrseq->reset_nb);
} else {
dev_notice(dev, "EMMC reset pin tied to a sleepy GPIO driver; reset on emergency-reboot disabled\n");
}
pwrseq->pwrseq.ops = &mmc_pwrseq_emmc_ops; pwrseq->pwrseq.ops = &mmc_pwrseq_emmc_ops;
pwrseq->pwrseq.dev = dev; pwrseq->pwrseq.dev = dev;
......
...@@ -472,6 +472,7 @@ void mmc_cleanup_queue(struct mmc_queue *mq) ...@@ -472,6 +472,7 @@ void mmc_cleanup_queue(struct mmc_queue *mq)
blk_mq_unquiesce_queue(q); blk_mq_unquiesce_queue(q);
blk_cleanup_queue(q); blk_cleanup_queue(q);
blk_mq_free_tag_set(&mq->tag_set);
/* /*
* A request can be completed before the next request, potentially * A request can be completed before the next request, potentially
......
...@@ -221,6 +221,14 @@ static int mmc_decode_scr(struct mmc_card *card) ...@@ -221,6 +221,14 @@ static int mmc_decode_scr(struct mmc_card *card)
if (scr->sda_spec3) if (scr->sda_spec3)
scr->cmds = UNSTUFF_BITS(resp, 32, 2); scr->cmds = UNSTUFF_BITS(resp, 32, 2);
/* SD Spec says: any SD Card shall set at least bits 0 and 2 */
if (!(scr->bus_widths & SD_SCR_BUS_WIDTH_1) ||
!(scr->bus_widths & SD_SCR_BUS_WIDTH_4)) {
pr_err("%s: invalid bus width\n", mmc_hostname(card->host));
return -EINVAL;
}
return 0; return 0;
} }
......
...@@ -92,6 +92,7 @@ config MMC_SDHCI_PCI ...@@ -92,6 +92,7 @@ config MMC_SDHCI_PCI
tristate "SDHCI support on PCI bus" tristate "SDHCI support on PCI bus"
depends on MMC_SDHCI && PCI depends on MMC_SDHCI && PCI
select MMC_CQHCI select MMC_CQHCI
select IOSF_MBI if X86
help help
This selects the PCI Secure Digital Host Controller Interface. This selects the PCI Secure Digital Host Controller Interface.
Most controllers found today are PCI devices. Most controllers found today are PCI devices.
...@@ -437,7 +438,7 @@ config MMC_WBSD ...@@ -437,7 +438,7 @@ config MMC_WBSD
depends on ISA_DMA_API depends on ISA_DMA_API
help help
This selects the Winbond(R) W83L51xD Secure digital and This selects the Winbond(R) W83L51xD Secure digital and
Multimedia card Interface. Multimedia card Interface.
If you have a machine with a integrated W83L518D or W83L519D If you have a machine with a integrated W83L518D or W83L519D
SD/MMC card reader, say Y or M here. SD/MMC card reader, say Y or M here.
...@@ -515,7 +516,7 @@ config MMC_TIFM_SD ...@@ -515,7 +516,7 @@ config MMC_TIFM_SD
'Misc devices: TI Flash Media PCI74xx/PCI76xx host adapter support 'Misc devices: TI Flash Media PCI74xx/PCI76xx host adapter support
(TIFM_7XX1)'. (TIFM_7XX1)'.
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called tifm_sd. module will be called tifm_sd.
config MMC_MVSDIO config MMC_MVSDIO
...@@ -531,12 +532,12 @@ config MMC_MVSDIO ...@@ -531,12 +532,12 @@ config MMC_MVSDIO
module will be called mvsdio. module will be called mvsdio.
config MMC_DAVINCI config MMC_DAVINCI
tristate "TI DAVINCI Multimedia Card Interface support" tristate "TI DAVINCI Multimedia Card Interface support"
depends on ARCH_DAVINCI depends on ARCH_DAVINCI
help help
This selects the TI DAVINCI Multimedia card Interface. This selects the TI DAVINCI Multimedia card Interface.
If you have an DAVINCI board with a Multimedia Card slot, If you have an DAVINCI board with a Multimedia Card slot,
say Y or M here. If unsure, say N. say Y or M here. If unsure, say N.
config MMC_GOLDFISH config MMC_GOLDFISH
tristate "goldfish qemu Multimedia Card Interface support" tristate "goldfish qemu Multimedia Card Interface support"
...@@ -565,18 +566,18 @@ config MMC_S3C ...@@ -565,18 +566,18 @@ config MMC_S3C
depends on S3C24XX_DMAC depends on S3C24XX_DMAC
help help
This selects a driver for the MCI interface found in This selects a driver for the MCI interface found in
Samsung's S3C2410, S3C2412, S3C2440, S3C2442 CPUs. Samsung's S3C2410, S3C2412, S3C2440, S3C2442 CPUs.
If you have a board based on one of those and a MMC/SD If you have a board based on one of those and a MMC/SD
slot, say Y or M here. slot, say Y or M here.
If unsure, say N. If unsure, say N.
config MMC_S3C_HW_SDIO_IRQ config MMC_S3C_HW_SDIO_IRQ
bool "Hardware support for SDIO IRQ" bool "Hardware support for SDIO IRQ"
depends on MMC_S3C depends on MMC_S3C
help help
Enable the hardware support for SDIO interrupts instead of using Enable the hardware support for SDIO interrupts instead of using
the generic polling code. the generic polling code.
choice choice
prompt "Samsung S3C SD/MMC transfer code" prompt "Samsung S3C SD/MMC transfer code"
...@@ -941,6 +942,7 @@ config MMC_BCM2835 ...@@ -941,6 +942,7 @@ config MMC_BCM2835
config MMC_MTK config MMC_MTK
tristate "MediaTek SD/MMC Card Interface support" tristate "MediaTek SD/MMC Card Interface support"
depends on HAS_DMA depends on HAS_DMA
select REGULATOR
help help
This selects the MediaTek(R) Secure digital and Multimedia card Interface. This selects the MediaTek(R) Secure digital and Multimedia card Interface.
If you have a machine with a integrated SD/MMC card reader, say Y or M here. If you have a machine with a integrated SD/MMC card reader, say Y or M here.
...@@ -948,15 +950,16 @@ config MMC_MTK ...@@ -948,15 +950,16 @@ config MMC_MTK
If unsure, say N. If unsure, say N.
config MMC_SDHCI_MICROCHIP_PIC32 config MMC_SDHCI_MICROCHIP_PIC32
tristate "Microchip PIC32MZDA SDHCI support" tristate "Microchip PIC32MZDA SDHCI support"
depends on MMC_SDHCI && PIC32MZDA && MMC_SDHCI_PLTFM depends on MMC_SDHCI && PIC32MZDA && MMC_SDHCI_PLTFM
help help
This selects the Secure Digital Host Controller Interface (SDHCI) This selects the Secure Digital Host Controller Interface (SDHCI)
for PIC32MZDA platform. for PIC32MZDA platform.
If you have a controller with this interface, say Y or M here. If you have a controller with this interface, say Y or M here.
If unsure, say N.
If unsure, say N.
config MMC_SDHCI_BRCMSTB config MMC_SDHCI_BRCMSTB
tristate "Broadcom SDIO/SD/MMC support" tristate "Broadcom SDIO/SD/MMC support"
depends on ARCH_BRCMSTB || BMIPS_GENERIC depends on ARCH_BRCMSTB || BMIPS_GENERIC
...@@ -993,6 +996,7 @@ config MMC_SDHCI_OMAP ...@@ -993,6 +996,7 @@ config MMC_SDHCI_OMAP
config MMC_SDHCI_AM654 config MMC_SDHCI_AM654
tristate "Support for the SDHCI Controller in TI's AM654 SOCs" tristate "Support for the SDHCI Controller in TI's AM654 SOCs"
depends on MMC_SDHCI_PLTFM && OF depends on MMC_SDHCI_PLTFM && OF
select MMC_SDHCI_IO_ACCESSORS
help help
This selects the Secure Digital Host Controller Interface (SDHCI) This selects the Secure Digital Host Controller Interface (SDHCI)
support present in TI's AM654 SOCs. The controller supports support present in TI's AM654 SOCs. The controller supports
......
...@@ -43,7 +43,6 @@ struct alcor_sdmmc_host { ...@@ -43,7 +43,6 @@ struct alcor_sdmmc_host {
struct device *dev; struct device *dev;
struct alcor_pci_priv *alcor_pci; struct alcor_pci_priv *alcor_pci;
struct mmc_host *mmc;
struct mmc_request *mrq; struct mmc_request *mrq;
struct mmc_command *cmd; struct mmc_command *cmd;
struct mmc_data *data; struct mmc_data *data;
...@@ -117,6 +116,9 @@ static void alcor_reset(struct alcor_sdmmc_host *host, u8 val) ...@@ -117,6 +116,9 @@ static void alcor_reset(struct alcor_sdmmc_host *host, u8 val)
dev_err(host->dev, "%s: timeout\n", __func__); dev_err(host->dev, "%s: timeout\n", __func__);
} }
/*
* Perform DMA I/O of a single page.
*/
static void alcor_data_set_dma(struct alcor_sdmmc_host *host) static void alcor_data_set_dma(struct alcor_sdmmc_host *host)
{ {
struct alcor_pci_priv *priv = host->alcor_pci; struct alcor_pci_priv *priv = host->alcor_pci;
...@@ -153,12 +155,26 @@ static void alcor_trigger_data_transfer(struct alcor_sdmmc_host *host) ...@@ -153,12 +155,26 @@ static void alcor_trigger_data_transfer(struct alcor_sdmmc_host *host)
ctrl |= AU6601_DATA_WRITE; ctrl |= AU6601_DATA_WRITE;
if (data->host_cookie == COOKIE_MAPPED) { if (data->host_cookie == COOKIE_MAPPED) {
/*
* For DMA transfers, this function is called just once,
* at the start of the operation. The hardware can only
* perform DMA I/O on a single page at a time, so here
* we kick off the transfer with the first page, and expect
* subsequent pages to be transferred upon IRQ events
* indicating that the single-page DMA was completed.
*/
alcor_data_set_dma(host); alcor_data_set_dma(host);
ctrl |= AU6601_DATA_DMA_MODE; ctrl |= AU6601_DATA_DMA_MODE;
host->dma_on = 1; host->dma_on = 1;
alcor_write32(priv, data->sg_count * 0x1000, alcor_write32(priv, data->sg_count * 0x1000,
AU6601_REG_BLOCK_SIZE); AU6601_REG_BLOCK_SIZE);
} else { } else {
/*
* For PIO transfers, we break down each operation
* into several sector-sized transfers. When one sector has
* complete, the IRQ handler will call this function again
* to kick off the transfer of the next sector.
*/
alcor_write32(priv, data->blksz, AU6601_REG_BLOCK_SIZE); alcor_write32(priv, data->blksz, AU6601_REG_BLOCK_SIZE);
} }
...@@ -276,7 +292,7 @@ static void alcor_send_cmd(struct alcor_sdmmc_host *host, ...@@ -276,7 +292,7 @@ static void alcor_send_cmd(struct alcor_sdmmc_host *host,
break; break;
default: default:
dev_err(host->dev, "%s: cmd->flag (0x%02x) is not valid\n", dev_err(host->dev, "%s: cmd->flag (0x%02x) is not valid\n",
mmc_hostname(host->mmc), mmc_resp_type(cmd)); mmc_hostname(mmc_from_priv(host)), mmc_resp_type(cmd));
break; break;
} }
...@@ -317,7 +333,7 @@ static void alcor_request_complete(struct alcor_sdmmc_host *host, ...@@ -317,7 +333,7 @@ static void alcor_request_complete(struct alcor_sdmmc_host *host,
host->data = NULL; host->data = NULL;
host->dma_on = 0; host->dma_on = 0;
mmc_request_done(host->mmc, mrq); mmc_request_done(mmc_from_priv(host), mrq);
} }
static void alcor_finish_data(struct alcor_sdmmc_host *host) static void alcor_finish_data(struct alcor_sdmmc_host *host)
...@@ -547,7 +563,7 @@ static void alcor_cd_irq(struct alcor_sdmmc_host *host, u32 intmask) ...@@ -547,7 +563,7 @@ static void alcor_cd_irq(struct alcor_sdmmc_host *host, u32 intmask)
alcor_request_complete(host, 1); alcor_request_complete(host, 1);
} }
mmc_detect_change(host->mmc, msecs_to_jiffies(1)); mmc_detect_change(mmc_from_priv(host), msecs_to_jiffies(1));
} }
static irqreturn_t alcor_irq_thread(int irq, void *d) static irqreturn_t alcor_irq_thread(int irq, void *d)
...@@ -771,12 +787,17 @@ static void alcor_pre_req(struct mmc_host *mmc, ...@@ -771,12 +787,17 @@ static void alcor_pre_req(struct mmc_host *mmc,
data->host_cookie = COOKIE_UNMAPPED; data->host_cookie = COOKIE_UNMAPPED;
/* FIXME: looks like the DMA engine works only with CMD18 */ /* FIXME: looks like the DMA engine works only with CMD18 */
if (cmd->opcode != 18) if (cmd->opcode != MMC_READ_MULTIPLE_BLOCK
&& cmd->opcode != MMC_WRITE_MULTIPLE_BLOCK)
return; return;
/* /*
* We don't do DMA on "complex" transfers, i.e. with * We don't do DMA on "complex" transfers, i.e. with
* non-word-aligned buffers or lengths. Also, we don't bother * non-word-aligned buffers or lengths. A future improvement
* with all the DMA setup overhead for short transfers. * could be made to use temporary DMA bounce-buffers when these
* requirements are not met.
*
* Also, we don't bother with all the DMA setup overhead for
* short transfers.
*/ */
if (data->blocks * data->blksz < AU6601_MAX_DMA_BLOCK_SIZE) if (data->blocks * data->blksz < AU6601_MAX_DMA_BLOCK_SIZE)
return; return;
...@@ -787,6 +808,8 @@ static void alcor_pre_req(struct mmc_host *mmc, ...@@ -787,6 +808,8 @@ static void alcor_pre_req(struct mmc_host *mmc,
for_each_sg(data->sg, sg, data->sg_len, i) { for_each_sg(data->sg, sg, data->sg_len, i) {
if (sg->length != AU6601_MAX_DMA_BLOCK_SIZE) if (sg->length != AU6601_MAX_DMA_BLOCK_SIZE)
return; return;
if (sg->offset != 0)
return;
} }
/* This data might be unmapped at this time */ /* This data might be unmapped at this time */
...@@ -1024,7 +1047,7 @@ static void alcor_hw_uninit(struct alcor_sdmmc_host *host) ...@@ -1024,7 +1047,7 @@ static void alcor_hw_uninit(struct alcor_sdmmc_host *host)
static void alcor_init_mmc(struct alcor_sdmmc_host *host) static void alcor_init_mmc(struct alcor_sdmmc_host *host)
{ {
struct mmc_host *mmc = host->mmc; struct mmc_host *mmc = mmc_from_priv(host);
mmc->f_min = AU6601_MIN_CLOCK; mmc->f_min = AU6601_MIN_CLOCK;
mmc->f_max = AU6601_MAX_CLOCK; mmc->f_max = AU6601_MAX_CLOCK;
...@@ -1036,26 +1059,21 @@ static void alcor_init_mmc(struct alcor_sdmmc_host *host) ...@@ -1036,26 +1059,21 @@ static void alcor_init_mmc(struct alcor_sdmmc_host *host)
mmc->ops = &alcor_sdc_ops; mmc->ops = &alcor_sdc_ops;
/* The hardware does DMA data transfer of 4096 bytes to/from a single /* The hardware does DMA data transfer of 4096 bytes to/from a single
* buffer address. Scatterlists are not supported, but upon DMA * buffer address. Scatterlists are not supported at the hardware
* completion (signalled via IRQ), the original vendor driver does * level, however we can work with them at the driver level,
* then immediately set up another DMA transfer of the next 4096 * provided that each segment is exactly 4096 bytes in size.
* bytes. * Upon DMA completion of a single segment (signalled via IRQ), we
* * immediately proceed to transfer the next segment from the
* This means that we need to handle the I/O in 4096 byte chunks. * scatterlist.
* Lacking a way to limit the sglist entries to 4096 bytes, we instead
* impose that only one segment is provided, with maximum size 4096,
* which also happens to be the minimum size. This means that the
* single-entry sglist handled by this driver can be handed directly
* to the hardware, nice and simple.
* *
* Unfortunately though, that means we only do 4096 bytes I/O per * The overall request is limited to 240 sectors, matching the
* MMC command. A future improvement would be to make the driver * original vendor driver.
* accept sg lists and entries of any size, and simply iterate
* through them 4096 bytes at a time.
*/ */
mmc->max_segs = AU6601_MAX_DMA_SEGMENTS; mmc->max_segs = AU6601_MAX_DMA_SEGMENTS;
mmc->max_seg_size = AU6601_MAX_DMA_BLOCK_SIZE; mmc->max_seg_size = AU6601_MAX_DMA_BLOCK_SIZE;
mmc->max_req_size = mmc->max_seg_size; mmc->max_blk_count = 240;
mmc->max_req_size = mmc->max_blk_count * mmc->max_blk_size;
dma_set_max_seg_size(host->dev, mmc->max_seg_size);
} }
static int alcor_pci_sdmmc_drv_probe(struct platform_device *pdev) static int alcor_pci_sdmmc_drv_probe(struct platform_device *pdev)
...@@ -1072,7 +1090,6 @@ static int alcor_pci_sdmmc_drv_probe(struct platform_device *pdev) ...@@ -1072,7 +1090,6 @@ static int alcor_pci_sdmmc_drv_probe(struct platform_device *pdev)
} }
host = mmc_priv(mmc); host = mmc_priv(mmc);
host->mmc = mmc;
host->dev = &pdev->dev; host->dev = &pdev->dev;
host->cur_power_mode = MMC_POWER_UNDEFINED; host->cur_power_mode = MMC_POWER_UNDEFINED;
host->alcor_pci = priv; host->alcor_pci = priv;
...@@ -1104,13 +1121,14 @@ static int alcor_pci_sdmmc_drv_probe(struct platform_device *pdev) ...@@ -1104,13 +1121,14 @@ static int alcor_pci_sdmmc_drv_probe(struct platform_device *pdev)
static int alcor_pci_sdmmc_drv_remove(struct platform_device *pdev) static int alcor_pci_sdmmc_drv_remove(struct platform_device *pdev)
{ {
struct alcor_sdmmc_host *host = dev_get_drvdata(&pdev->dev); struct alcor_sdmmc_host *host = dev_get_drvdata(&pdev->dev);
struct mmc_host *mmc = mmc_from_priv(host);
if (cancel_delayed_work_sync(&host->timeout_work)) if (cancel_delayed_work_sync(&host->timeout_work))
alcor_request_complete(host, 0); alcor_request_complete(host, 0);
alcor_hw_uninit(host); alcor_hw_uninit(host);
mmc_remove_host(host->mmc); mmc_remove_host(mmc);
mmc_free_host(host->mmc); mmc_free_host(mmc);
return 0; return 0;
} }
......
...@@ -537,6 +537,8 @@ static void cqhci_prep_dcmd_desc(struct mmc_host *mmc, ...@@ -537,6 +537,8 @@ static void cqhci_prep_dcmd_desc(struct mmc_host *mmc,
CQHCI_ACT(0x5) | CQHCI_ACT(0x5) |
CQHCI_CMD_INDEX(mrq->cmd->opcode) | CQHCI_CMD_INDEX(mrq->cmd->opcode) |
CQHCI_CMD_TIMING(timing) | CQHCI_RESP_TYPE(resp_type)); CQHCI_CMD_TIMING(timing) | CQHCI_RESP_TYPE(resp_type));
if (cq_host->ops->update_dcmd_desc)
cq_host->ops->update_dcmd_desc(mmc, mrq, &data);
*task_desc |= data; *task_desc |= data;
desc = (u8 *)task_desc; desc = (u8 *)task_desc;
pr_debug("%s: cqhci: dcmd: cmd: %d timing: %d resp: %d\n", pr_debug("%s: cqhci: dcmd: cmd: %d timing: %d resp: %d\n",
......
...@@ -88,6 +88,7 @@ ...@@ -88,6 +88,7 @@
/* send status config 1 */ /* send status config 1 */
#define CQHCI_SSC1 0x40 #define CQHCI_SSC1 0x40
#define CQHCI_SSC1_CBC_MASK GENMASK(19, 16)
/* send status config 2 */ /* send status config 2 */
#define CQHCI_SSC2 0x44 #define CQHCI_SSC2 0x44
...@@ -147,6 +148,7 @@ ...@@ -147,6 +148,7 @@
struct cqhci_host_ops; struct cqhci_host_ops;
struct mmc_host; struct mmc_host;
struct mmc_request;
struct cqhci_slot; struct cqhci_slot;
struct cqhci_host { struct cqhci_host {
...@@ -210,6 +212,8 @@ struct cqhci_host_ops { ...@@ -210,6 +212,8 @@ struct cqhci_host_ops {
u32 (*read_l)(struct cqhci_host *host, int reg); u32 (*read_l)(struct cqhci_host *host, int reg);
void (*enable)(struct mmc_host *mmc); void (*enable)(struct mmc_host *mmc);
void (*disable)(struct mmc_host *mmc, bool recovery); void (*disable)(struct mmc_host *mmc, bool recovery);
void (*update_dcmd_desc)(struct mmc_host *mmc, struct mmc_request *mrq,
u64 *data);
}; };
static inline void cqhci_writel(struct cqhci_host *host, u32 val, int reg) static inline void cqhci_writel(struct cqhci_host *host, u32 val, int reg)
......
This diff is collapsed.
// SPDX-License-Identifier: GPL-2.0-or-later
/* /*
* mmc_spi.c - Access SD/MMC cards through SPI master controllers * Access SD/MMC cards through SPI master controllers
* *
* (C) Copyright 2005, Intec Automation, * (C) Copyright 2005, Intec Automation,
* Mike Lavender (mike@steroidmicros) * Mike Lavender (mike@steroidmicros)
...@@ -8,21 +9,6 @@ ...@@ -8,21 +9,6 @@
* Hans-Peter Nilsson (hp@axis.com) * Hans-Peter Nilsson (hp@axis.com)
* (C) Copyright 2007, ATRON electronic GmbH, * (C) Copyright 2007, ATRON electronic GmbH,
* Jan Nikitenko <jan.nikitenko@gmail.com> * Jan Nikitenko <jan.nikitenko@gmail.com>
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ */
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/delay.h> #include <linux/delay.h>
...@@ -197,7 +183,7 @@ mmc_spi_readbytes(struct mmc_spi_host *host, unsigned len) ...@@ -197,7 +183,7 @@ mmc_spi_readbytes(struct mmc_spi_host *host, unsigned len)
static int mmc_spi_skip(struct mmc_spi_host *host, unsigned long timeout, static int mmc_spi_skip(struct mmc_spi_host *host, unsigned long timeout,
unsigned n, u8 byte) unsigned n, u8 byte)
{ {
u8 *cp = host->data->status; u8 *cp = host->data->status;
unsigned long start = jiffies; unsigned long start = jiffies;
while (1) { while (1) {
...@@ -220,7 +206,7 @@ static int mmc_spi_skip(struct mmc_spi_host *host, unsigned long timeout, ...@@ -220,7 +206,7 @@ static int mmc_spi_skip(struct mmc_spi_host *host, unsigned long timeout,
* We use jiffies here because we want to have a relation * We use jiffies here because we want to have a relation
* between elapsed time and the blocking of the scheduler. * between elapsed time and the blocking of the scheduler.
*/ */
if (time_is_before_jiffies(start+1)) if (time_is_before_jiffies(start + 1))
schedule(); schedule();
} }
return -ETIMEDOUT; return -ETIMEDOUT;
...@@ -415,7 +401,7 @@ static int mmc_spi_response_get(struct mmc_spi_host *host, ...@@ -415,7 +401,7 @@ static int mmc_spi_response_get(struct mmc_spi_host *host,
default: default:
dev_dbg(&host->spi->dev, "bad response type %04x\n", dev_dbg(&host->spi->dev, "bad response type %04x\n",
mmc_spi_resp_type(cmd)); mmc_spi_resp_type(cmd));
if (value >= 0) if (value >= 0)
value = -EINVAL; value = -EINVAL;
goto done; goto done;
...@@ -467,8 +453,8 @@ mmc_spi_command_send(struct mmc_spi_host *host, ...@@ -467,8 +453,8 @@ mmc_spi_command_send(struct mmc_spi_host *host,
memset(cp, 0xff, sizeof(data->status)); memset(cp, 0xff, sizeof(data->status));
cp[1] = 0x40 | cmd->opcode; cp[1] = 0x40 | cmd->opcode;
put_unaligned_be32(cmd->arg, cp+2); put_unaligned_be32(cmd->arg, cp + 2);
cp[6] = crc7_be(0, cp+1, 5) | 0x01; cp[6] = crc7_be(0, cp + 1, 5) | 0x01;
cp += 7; cp += 7;
/* Then, read up to 13 bytes (while writing all-ones): /* Then, read up to 13 bytes (while writing all-ones):
...@@ -642,9 +628,7 @@ mmc_spi_setup_data_message( ...@@ -642,9 +628,7 @@ mmc_spi_setup_data_message(
if (multiple || direction == DMA_TO_DEVICE) { if (multiple || direction == DMA_TO_DEVICE) {
t = &host->early_status; t = &host->early_status;
memset(t, 0, sizeof(*t)); memset(t, 0, sizeof(*t));
t->len = (direction == DMA_TO_DEVICE) t->len = (direction == DMA_TO_DEVICE) ? sizeof(scratch->status) : 1;
? sizeof(scratch->status)
: 1;
t->tx_buf = host->ones; t->tx_buf = host->ones;
t->tx_dma = host->ones_dma; t->tx_dma = host->ones_dma;
t->rx_buf = scratch->status; t->rx_buf = scratch->status;
...@@ -677,8 +661,7 @@ mmc_spi_writeblock(struct mmc_spi_host *host, struct spi_transfer *t, ...@@ -677,8 +661,7 @@ mmc_spi_writeblock(struct mmc_spi_host *host, struct spi_transfer *t,
u32 pattern; u32 pattern;
if (host->mmc->use_spi_crc) if (host->mmc->use_spi_crc)
scratch->crc_val = cpu_to_be16( scratch->crc_val = cpu_to_be16(crc_itu_t(0, t->tx_buf, t->len));
crc_itu_t(0, t->tx_buf, t->len));
if (host->dma_dev) if (host->dma_dev)
dma_sync_single_for_device(host->dma_dev, dma_sync_single_for_device(host->dma_dev,
host->data_dma, sizeof(*scratch), host->data_dma, sizeof(*scratch),
...@@ -819,6 +802,10 @@ mmc_spi_readblock(struct mmc_spi_host *host, struct spi_transfer *t, ...@@ -819,6 +802,10 @@ mmc_spi_readblock(struct mmc_spi_host *host, struct spi_transfer *t,
} }
status = spi_sync_locked(spi, &host->m); status = spi_sync_locked(spi, &host->m);
if (status < 0) {
dev_dbg(&spi->dev, "read error %d\n", status);
return status;
}
if (host->dma_dev) { if (host->dma_dev) {
dma_sync_single_for_cpu(host->dma_dev, dma_sync_single_for_cpu(host->dma_dev,
...@@ -855,9 +842,9 @@ mmc_spi_readblock(struct mmc_spi_host *host, struct spi_transfer *t, ...@@ -855,9 +842,9 @@ mmc_spi_readblock(struct mmc_spi_host *host, struct spi_transfer *t,
be16_to_cpus(&scratch->crc_val); be16_to_cpus(&scratch->crc_val);
if (scratch->crc_val != crc) { if (scratch->crc_val != crc) {
dev_dbg(&spi->dev, "read - crc error: crc_val=0x%04x, " dev_dbg(&spi->dev,
"computed=0x%04x len=%d\n", "read - crc error: crc_val=0x%04x, computed=0x%04x len=%d\n",
scratch->crc_val, crc, t->len); scratch->crc_val, crc, t->len);
return -EILSEQ; return -EILSEQ;
} }
} }
...@@ -945,9 +932,7 @@ mmc_spi_data_do(struct mmc_spi_host *host, struct mmc_command *cmd, ...@@ -945,9 +932,7 @@ mmc_spi_data_do(struct mmc_spi_host *host, struct mmc_command *cmd,
dev_dbg(&host->spi->dev, dev_dbg(&host->spi->dev,
" mmc_spi: %s block, %d bytes\n", " mmc_spi: %s block, %d bytes\n",
(direction == DMA_TO_DEVICE) (direction == DMA_TO_DEVICE) ? "write" : "read",
? "write"
: "read",
t->len); t->len);
if (direction == DMA_TO_DEVICE) if (direction == DMA_TO_DEVICE)
...@@ -974,8 +959,7 @@ mmc_spi_data_do(struct mmc_spi_host *host, struct mmc_command *cmd, ...@@ -974,8 +959,7 @@ mmc_spi_data_do(struct mmc_spi_host *host, struct mmc_command *cmd,
if (status < 0) { if (status < 0) {
data->error = status; data->error = status;
dev_dbg(&spi->dev, "%s status %d\n", dev_dbg(&spi->dev, "%s status %d\n",
(direction == DMA_TO_DEVICE) (direction == DMA_TO_DEVICE) ? "write" : "read",
? "write" : "read",
status); status);
break; break;
} }
...@@ -1249,8 +1233,7 @@ static void mmc_spi_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) ...@@ -1249,8 +1233,7 @@ static void mmc_spi_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
mres = spi_setup(host->spi); mres = spi_setup(host->spi);
if (mres < 0) if (mres < 0)
dev_dbg(&host->spi->dev, dev_dbg(&host->spi->dev,
"switch back to SPI mode 3" "switch back to SPI mode 3 failed\n");
" failed\n");
} }
} }
...@@ -1470,7 +1453,7 @@ static int mmc_spi_probe(struct spi_device *spi) ...@@ -1470,7 +1453,7 @@ static int mmc_spi_probe(struct spi_device *spi)
return 0; return 0;
fail_add_host: fail_add_host:
mmc_remove_host (mmc); mmc_remove_host(mmc);
fail_glue_init: fail_glue_init:
if (host->dma_dev) if (host->dma_dev)
dma_unmap_single(host->dma_dev, host->data_dma, dma_unmap_single(host->dma_dev, host->data_dma,
...@@ -1485,7 +1468,6 @@ static int mmc_spi_probe(struct spi_device *spi) ...@@ -1485,7 +1468,6 @@ static int mmc_spi_probe(struct spi_device *spi)
fail_nobuf1: fail_nobuf1:
mmc_free_host(mmc); mmc_free_host(mmc);
mmc_spi_put_pdata(spi); mmc_spi_put_pdata(spi);
dev_set_drvdata(&spi->dev, NULL);
nomem: nomem:
kfree(ones); kfree(ones);
...@@ -1496,32 +1478,27 @@ static int mmc_spi_probe(struct spi_device *spi) ...@@ -1496,32 +1478,27 @@ static int mmc_spi_probe(struct spi_device *spi)
static int mmc_spi_remove(struct spi_device *spi) static int mmc_spi_remove(struct spi_device *spi)
{ {
struct mmc_host *mmc = dev_get_drvdata(&spi->dev); struct mmc_host *mmc = dev_get_drvdata(&spi->dev);
struct mmc_spi_host *host; struct mmc_spi_host *host = mmc_priv(mmc);
if (mmc) {
host = mmc_priv(mmc);
/* prevent new mmc_detect_change() calls */ /* prevent new mmc_detect_change() calls */
if (host->pdata && host->pdata->exit) if (host->pdata && host->pdata->exit)
host->pdata->exit(&spi->dev, mmc); host->pdata->exit(&spi->dev, mmc);
mmc_remove_host(mmc); mmc_remove_host(mmc);
if (host->dma_dev) { if (host->dma_dev) {
dma_unmap_single(host->dma_dev, host->ones_dma, dma_unmap_single(host->dma_dev, host->ones_dma,
MMC_SPI_BLOCKSIZE, DMA_TO_DEVICE); MMC_SPI_BLOCKSIZE, DMA_TO_DEVICE);
dma_unmap_single(host->dma_dev, host->data_dma, dma_unmap_single(host->dma_dev, host->data_dma,
sizeof(*host->data), DMA_BIDIRECTIONAL); sizeof(*host->data), DMA_BIDIRECTIONAL);
} }
kfree(host->data); kfree(host->data);
kfree(host->ones); kfree(host->ones);
spi->max_speed_hz = mmc->f_max; spi->max_speed_hz = mmc->f_max;
mmc_free_host(mmc); mmc_free_host(mmc);
mmc_spi_put_pdata(spi); mmc_spi_put_pdata(spi);
dev_set_drvdata(&spi->dev, NULL);
}
return 0; return 0;
} }
...@@ -1542,8 +1519,7 @@ static struct spi_driver mmc_spi_driver = { ...@@ -1542,8 +1519,7 @@ static struct spi_driver mmc_spi_driver = {
module_spi_driver(mmc_spi_driver); module_spi_driver(mmc_spi_driver);
MODULE_AUTHOR("Mike Lavender, David Brownell, " MODULE_AUTHOR("Mike Lavender, David Brownell, Hans-Peter Nilsson, Jan Nikitenko");
"Hans-Peter Nilsson, Jan Nikitenko");
MODULE_DESCRIPTION("SPI SD/MMC host driver"); MODULE_DESCRIPTION("SPI SD/MMC host driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_ALIAS("spi:mmc_spi"); MODULE_ALIAS("spi:mmc_spi");
...@@ -43,21 +43,11 @@ ...@@ -43,21 +43,11 @@
#include <asm/io.h> #include <asm/io.h>
#include "mmci.h" #include "mmci.h"
#include "mmci_qcom_dml.h"
#define DRIVER_NAME "mmci-pl18x" #define DRIVER_NAME "mmci-pl18x"
#ifdef CONFIG_DMA_ENGINE static void mmci_variant_init(struct mmci_host *host);
void mmci_variant_init(struct mmci_host *host); static void ux500v2_variant_init(struct mmci_host *host);
#else
static inline void mmci_variant_init(struct mmci_host *host) {}
#endif
#ifdef CONFIG_MMC_STM32_SDMMC
void sdmmc_variant_init(struct mmci_host *host);
#else
static inline void sdmmc_variant_init(struct mmci_host *host) {}
#endif
static unsigned int fmax = 515633; static unsigned int fmax = 515633;
...@@ -70,7 +60,6 @@ static struct variant_data variant_arm = { ...@@ -70,7 +60,6 @@ static struct variant_data variant_arm = {
.cmdreg_srsp = MCI_CPSM_RESPONSE, .cmdreg_srsp = MCI_CPSM_RESPONSE,
.datalength_bits = 16, .datalength_bits = 16,
.datactrl_blocksz = 11, .datactrl_blocksz = 11,
.datactrl_dpsm_enable = MCI_DPSM_ENABLE,
.pwrreg_powerup = MCI_PWR_UP, .pwrreg_powerup = MCI_PWR_UP,
.f_max = 100000000, .f_max = 100000000,
.reversed_irq_handling = true, .reversed_irq_handling = true,
...@@ -90,7 +79,6 @@ static struct variant_data variant_arm_extended_fifo = { ...@@ -90,7 +79,6 @@ static struct variant_data variant_arm_extended_fifo = {
.cmdreg_srsp = MCI_CPSM_RESPONSE, .cmdreg_srsp = MCI_CPSM_RESPONSE,
.datalength_bits = 16, .datalength_bits = 16,
.datactrl_blocksz = 11, .datactrl_blocksz = 11,
.datactrl_dpsm_enable = MCI_DPSM_ENABLE,
.pwrreg_powerup = MCI_PWR_UP, .pwrreg_powerup = MCI_PWR_UP,
.f_max = 100000000, .f_max = 100000000,
.mmcimask1 = true, .mmcimask1 = true,
...@@ -110,7 +98,6 @@ static struct variant_data variant_arm_extended_fifo_hwfc = { ...@@ -110,7 +98,6 @@ static struct variant_data variant_arm_extended_fifo_hwfc = {
.cmdreg_srsp = MCI_CPSM_RESPONSE, .cmdreg_srsp = MCI_CPSM_RESPONSE,
.datalength_bits = 16, .datalength_bits = 16,
.datactrl_blocksz = 11, .datactrl_blocksz = 11,
.datactrl_dpsm_enable = MCI_DPSM_ENABLE,
.pwrreg_powerup = MCI_PWR_UP, .pwrreg_powerup = MCI_PWR_UP,
.f_max = 100000000, .f_max = 100000000,
.mmcimask1 = true, .mmcimask1 = true,
...@@ -131,7 +118,6 @@ static struct variant_data variant_u300 = { ...@@ -131,7 +118,6 @@ static struct variant_data variant_u300 = {
.cmdreg_srsp = MCI_CPSM_RESPONSE, .cmdreg_srsp = MCI_CPSM_RESPONSE,
.datalength_bits = 16, .datalength_bits = 16,
.datactrl_blocksz = 11, .datactrl_blocksz = 11,
.datactrl_dpsm_enable = MCI_DPSM_ENABLE,
.datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN, .datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN,
.st_sdio = true, .st_sdio = true,
.pwrreg_powerup = MCI_PWR_ON, .pwrreg_powerup = MCI_PWR_ON,
...@@ -157,7 +143,6 @@ static struct variant_data variant_nomadik = { ...@@ -157,7 +143,6 @@ static struct variant_data variant_nomadik = {
.cmdreg_srsp = MCI_CPSM_RESPONSE, .cmdreg_srsp = MCI_CPSM_RESPONSE,
.datalength_bits = 24, .datalength_bits = 24,
.datactrl_blocksz = 11, .datactrl_blocksz = 11,
.datactrl_dpsm_enable = MCI_DPSM_ENABLE,
.datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN, .datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN,
.st_sdio = true, .st_sdio = true,
.st_clkdiv = true, .st_clkdiv = true,
...@@ -186,7 +171,6 @@ static struct variant_data variant_ux500 = { ...@@ -186,7 +171,6 @@ static struct variant_data variant_ux500 = {
.cmdreg_srsp = MCI_CPSM_RESPONSE, .cmdreg_srsp = MCI_CPSM_RESPONSE,
.datalength_bits = 24, .datalength_bits = 24,
.datactrl_blocksz = 11, .datactrl_blocksz = 11,
.datactrl_dpsm_enable = MCI_DPSM_ENABLE,
.datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN, .datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN,
.st_sdio = true, .st_sdio = true,
.st_clkdiv = true, .st_clkdiv = true,
...@@ -220,11 +204,9 @@ static struct variant_data variant_ux500v2 = { ...@@ -220,11 +204,9 @@ static struct variant_data variant_ux500v2 = {
.datactrl_mask_ddrmode = MCI_DPSM_ST_DDRMODE, .datactrl_mask_ddrmode = MCI_DPSM_ST_DDRMODE,
.datalength_bits = 24, .datalength_bits = 24,
.datactrl_blocksz = 11, .datactrl_blocksz = 11,
.datactrl_dpsm_enable = MCI_DPSM_ENABLE,
.datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN, .datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN,
.st_sdio = true, .st_sdio = true,
.st_clkdiv = true, .st_clkdiv = true,
.blksz_datactrl16 = true,
.pwrreg_powerup = MCI_PWR_ON, .pwrreg_powerup = MCI_PWR_ON,
.f_max = 100000000, .f_max = 100000000,
.signal_direction = true, .signal_direction = true,
...@@ -238,7 +220,7 @@ static struct variant_data variant_ux500v2 = { ...@@ -238,7 +220,7 @@ static struct variant_data variant_ux500v2 = {
.irq_pio_mask = MCI_IRQ_PIO_MASK, .irq_pio_mask = MCI_IRQ_PIO_MASK,
.start_err = MCI_STARTBITERR, .start_err = MCI_STARTBITERR,
.opendrain = MCI_OD, .opendrain = MCI_OD,
.init = mmci_variant_init, .init = ux500v2_variant_init,
}; };
static struct variant_data variant_stm32 = { static struct variant_data variant_stm32 = {
...@@ -255,7 +237,6 @@ static struct variant_data variant_stm32 = { ...@@ -255,7 +237,6 @@ static struct variant_data variant_stm32 = {
.irq_pio_mask = MCI_IRQ_PIO_MASK, .irq_pio_mask = MCI_IRQ_PIO_MASK,
.datalength_bits = 24, .datalength_bits = 24,
.datactrl_blocksz = 11, .datactrl_blocksz = 11,
.datactrl_dpsm_enable = MCI_DPSM_ENABLE,
.datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN, .datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN,
.st_sdio = true, .st_sdio = true,
.st_clkdiv = true, .st_clkdiv = true,
...@@ -299,10 +280,8 @@ static struct variant_data variant_qcom = { ...@@ -299,10 +280,8 @@ static struct variant_data variant_qcom = {
.cmdreg_srsp_crc = MCI_CPSM_RESPONSE, .cmdreg_srsp_crc = MCI_CPSM_RESPONSE,
.cmdreg_srsp = MCI_CPSM_RESPONSE, .cmdreg_srsp = MCI_CPSM_RESPONSE,
.data_cmd_enable = MCI_CPSM_QCOM_DATCMD, .data_cmd_enable = MCI_CPSM_QCOM_DATCMD,
.blksz_datactrl4 = true,
.datalength_bits = 24, .datalength_bits = 24,
.datactrl_blocksz = 11, .datactrl_blocksz = 11,
.datactrl_dpsm_enable = MCI_DPSM_ENABLE,
.pwrreg_powerup = MCI_PWR_UP, .pwrreg_powerup = MCI_PWR_UP,
.f_max = 208000000, .f_max = 208000000,
.explicit_mclk_control = true, .explicit_mclk_control = true,
...@@ -624,6 +603,16 @@ static void mmci_init_sg(struct mmci_host *host, struct mmc_data *data) ...@@ -624,6 +603,16 @@ static void mmci_init_sg(struct mmci_host *host, struct mmc_data *data)
sg_miter_start(&host->sg_miter, data->sg, data->sg_len, flags); sg_miter_start(&host->sg_miter, data->sg, data->sg_len, flags);
} }
static u32 mmci_get_dctrl_cfg(struct mmci_host *host)
{
return MCI_DPSM_ENABLE | mmci_dctrl_blksz(host);
}
static u32 ux500v2_get_dctrl_cfg(struct mmci_host *host)
{
return MCI_DPSM_ENABLE | (host->data->blksz << 16);
}
/* /*
* All the DMA operation mode stuff goes inside this ifdef. * All the DMA operation mode stuff goes inside this ifdef.
* This assumes that you have a generic DMA device interface, * This assumes that you have a generic DMA device interface,
...@@ -886,15 +875,11 @@ int mmci_dmae_prep_data(struct mmci_host *host, ...@@ -886,15 +875,11 @@ int mmci_dmae_prep_data(struct mmci_host *host,
int mmci_dmae_start(struct mmci_host *host, unsigned int *datactrl) int mmci_dmae_start(struct mmci_host *host, unsigned int *datactrl)
{ {
struct mmci_dmae_priv *dmae = host->dma_priv; struct mmci_dmae_priv *dmae = host->dma_priv;
struct mmc_data *data = host->data;
host->dma_in_progress = true; host->dma_in_progress = true;
dmaengine_submit(dmae->desc_current); dmaengine_submit(dmae->desc_current);
dma_async_issue_pending(dmae->cur); dma_async_issue_pending(dmae->cur);
if (host->variant->qcom_dml)
dml_start_xfer(host, data);
*datactrl |= MCI_DPSM_DMAENABLE; *datactrl |= MCI_DPSM_DMAENABLE;
return 0; return 0;
...@@ -952,6 +937,7 @@ void mmci_dmae_unprep_data(struct mmci_host *host, ...@@ -952,6 +937,7 @@ void mmci_dmae_unprep_data(struct mmci_host *host,
static struct mmci_host_ops mmci_variant_ops = { static struct mmci_host_ops mmci_variant_ops = {
.prep_data = mmci_dmae_prep_data, .prep_data = mmci_dmae_prep_data,
.unprep_data = mmci_dmae_unprep_data, .unprep_data = mmci_dmae_unprep_data,
.get_datactrl_cfg = mmci_get_dctrl_cfg,
.get_next_data = mmci_dmae_get_next_data, .get_next_data = mmci_dmae_get_next_data,
.dma_setup = mmci_dmae_setup, .dma_setup = mmci_dmae_setup,
.dma_release = mmci_dmae_release, .dma_release = mmci_dmae_release,
...@@ -959,12 +945,22 @@ static struct mmci_host_ops mmci_variant_ops = { ...@@ -959,12 +945,22 @@ static struct mmci_host_ops mmci_variant_ops = {
.dma_finalize = mmci_dmae_finalize, .dma_finalize = mmci_dmae_finalize,
.dma_error = mmci_dmae_error, .dma_error = mmci_dmae_error,
}; };
#else
static struct mmci_host_ops mmci_variant_ops = {
.get_datactrl_cfg = mmci_get_dctrl_cfg,
};
#endif
void mmci_variant_init(struct mmci_host *host) void mmci_variant_init(struct mmci_host *host)
{ {
host->ops = &mmci_variant_ops; host->ops = &mmci_variant_ops;
} }
#endif
void ux500v2_variant_init(struct mmci_host *host)
{
host->ops = &mmci_variant_ops;
host->ops->get_datactrl_cfg = ux500v2_get_dctrl_cfg;
}
static void mmci_pre_request(struct mmc_host *mmc, struct mmc_request *mrq) static void mmci_pre_request(struct mmc_host *mmc, struct mmc_request *mrq)
{ {
...@@ -1000,7 +996,6 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data) ...@@ -1000,7 +996,6 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
unsigned int datactrl, timeout, irqmask; unsigned int datactrl, timeout, irqmask;
unsigned long long clks; unsigned long long clks;
void __iomem *base; void __iomem *base;
int blksz_bits;
dev_dbg(mmc_dev(host->mmc), "blksz %04x blks %04x flags %08x\n", dev_dbg(mmc_dev(host->mmc), "blksz %04x blks %04x flags %08x\n",
data->blksz, data->blocks, data->flags); data->blksz, data->blocks, data->flags);
...@@ -1018,18 +1013,8 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data) ...@@ -1018,18 +1013,8 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
writel(timeout, base + MMCIDATATIMER); writel(timeout, base + MMCIDATATIMER);
writel(host->size, base + MMCIDATALENGTH); writel(host->size, base + MMCIDATALENGTH);
blksz_bits = ffs(data->blksz) - 1; datactrl = host->ops->get_datactrl_cfg(host);
BUG_ON(1 << blksz_bits != data->blksz); datactrl |= host->data->flags & MMC_DATA_READ ? MCI_DPSM_DIRECTION : 0;
if (variant->blksz_datactrl16)
datactrl = variant->datactrl_dpsm_enable | (data->blksz << 16);
else if (variant->blksz_datactrl4)
datactrl = variant->datactrl_dpsm_enable | (data->blksz << 4);
else
datactrl = variant->datactrl_dpsm_enable | blksz_bits << 4;
if (data->flags & MMC_DATA_READ)
datactrl |= MCI_DPSM_DIRECTION;
if (host->mmc->card && mmc_card_sdio(host->mmc->card)) { if (host->mmc->card && mmc_card_sdio(host->mmc->card)) {
u32 clk; u32 clk;
...@@ -1220,12 +1205,13 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd, ...@@ -1220,12 +1205,13 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd,
unsigned int status) unsigned int status)
{ {
void __iomem *base = host->base; void __iomem *base = host->base;
bool sbc; bool sbc, busy_resp;
if (!cmd) if (!cmd)
return; return;
sbc = (cmd == host->mrq->sbc); sbc = (cmd == host->mrq->sbc);
busy_resp = !!(cmd->flags & MMC_RSP_BUSY);
/* /*
* We need to be one of these interrupts to be considered worth * We need to be one of these interrupts to be considered worth
...@@ -1239,8 +1225,7 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd, ...@@ -1239,8 +1225,7 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd,
/* /*
* ST Micro variant: handle busy detection. * ST Micro variant: handle busy detection.
*/ */
if (host->variant->busy_detect) { if (busy_resp && host->variant->busy_detect) {
bool busy_resp = !!(cmd->flags & MMC_RSP_BUSY);
/* We are busy with a command, return */ /* We are busy with a command, return */
if (host->busy_status && if (host->busy_status &&
...@@ -1253,7 +1238,7 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd, ...@@ -1253,7 +1238,7 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd,
* that the special busy status bit is still set before * that the special busy status bit is still set before
* proceeding. * proceeding.
*/ */
if (!host->busy_status && busy_resp && if (!host->busy_status &&
!(status & (MCI_CMDCRCFAIL|MCI_CMDTIMEOUT)) && !(status & (MCI_CMDCRCFAIL|MCI_CMDTIMEOUT)) &&
(readl(base + MMCISTATUS) & host->variant->busy_detect_flag)) { (readl(base + MMCISTATUS) & host->variant->busy_detect_flag)) {
...@@ -1550,9 +1535,10 @@ static irqreturn_t mmci_irq(int irq, void *dev_id) ...@@ -1550,9 +1535,10 @@ static irqreturn_t mmci_irq(int irq, void *dev_id)
} }
/* /*
* Don't poll for busy completion in irq context. * Busy detection has been handled by mmci_cmd_irq() above.
* Clear the status bit to prevent polling in IRQ context.
*/ */
if (host->variant->busy_detect && host->busy_status) if (host->variant->busy_detect_flag)
status &= ~host->variant->busy_detect_flag; status &= ~host->variant->busy_detect_flag;
ret = 1; ret = 1;
......
...@@ -131,6 +131,11 @@ ...@@ -131,6 +131,11 @@
/* Control register extensions in the Qualcomm versions */ /* Control register extensions in the Qualcomm versions */
#define MCI_DPSM_QCOM_DATA_PEND BIT(17) #define MCI_DPSM_QCOM_DATA_PEND BIT(17)
#define MCI_DPSM_QCOM_RX_DATA_PEND BIT(20) #define MCI_DPSM_QCOM_RX_DATA_PEND BIT(20)
/* Control register extensions in STM32 versions */
#define MCI_DPSM_STM32_MODE_BLOCK (0 << 2)
#define MCI_DPSM_STM32_MODE_SDIO (1 << 2)
#define MCI_DPSM_STM32_MODE_STREAM (2 << 2)
#define MCI_DPSM_STM32_MODE_BLOCK_STOP (3 << 2)
#define MMCIDATACNT 0x030 #define MMCIDATACNT 0x030
#define MMCISTATUS 0x034 #define MMCISTATUS 0x034
...@@ -275,12 +280,8 @@ struct mmci_host; ...@@ -275,12 +280,8 @@ struct mmci_host;
* @st_clkdiv: true if using a ST-specific clock divider algorithm * @st_clkdiv: true if using a ST-specific clock divider algorithm
* @stm32_clkdiv: true if using a STM32-specific clock divider algorithm * @stm32_clkdiv: true if using a STM32-specific clock divider algorithm
* @datactrl_mask_ddrmode: ddr mode mask in datactrl register. * @datactrl_mask_ddrmode: ddr mode mask in datactrl register.
* @blksz_datactrl16: true if Block size is at b16..b30 position in datactrl register
* @blksz_datactrl4: true if Block size is at b4..b16 position in datactrl
* register
* @datactrl_mask_sdio: SDIO enable mask in datactrl register * @datactrl_mask_sdio: SDIO enable mask in datactrl register
* @datactrl_blksz: block size in power of two * @datactrl_blksz: block size in power of two
* @datactrl_dpsm_enable: enable value for DPSM
* @datactrl_first: true if data must be setup before send command * @datactrl_first: true if data must be setup before send command
* @datacnt_useless: true if you could not use datacnt register to read * @datacnt_useless: true if you could not use datacnt register to read
* remaining data * remaining data
...@@ -325,14 +326,11 @@ struct variant_data { ...@@ -325,14 +326,11 @@ struct variant_data {
unsigned int datactrl_mask_ddrmode; unsigned int datactrl_mask_ddrmode;
unsigned int datactrl_mask_sdio; unsigned int datactrl_mask_sdio;
unsigned int datactrl_blocksz; unsigned int datactrl_blocksz;
unsigned int datactrl_dpsm_enable;
u8 datactrl_first:1; u8 datactrl_first:1;
u8 datacnt_useless:1; u8 datacnt_useless:1;
u8 st_sdio:1; u8 st_sdio:1;
u8 st_clkdiv:1; u8 st_clkdiv:1;
u8 stm32_clkdiv:1; u8 stm32_clkdiv:1;
u8 blksz_datactrl16:1;
u8 blksz_datactrl4:1;
u32 pwrreg_powerup; u32 pwrreg_powerup;
u32 f_max; u32 f_max;
u8 signal_direction:1; u8 signal_direction:1;
...@@ -362,6 +360,7 @@ struct mmci_host_ops { ...@@ -362,6 +360,7 @@ struct mmci_host_ops {
bool next); bool next);
void (*unprep_data)(struct mmci_host *host, struct mmc_data *data, void (*unprep_data)(struct mmci_host *host, struct mmc_data *data,
int err); int err);
u32 (*get_datactrl_cfg)(struct mmci_host *host);
void (*get_next_data)(struct mmci_host *host, struct mmc_data *data); void (*get_next_data)(struct mmci_host *host, struct mmc_data *data);
int (*dma_setup)(struct mmci_host *host); int (*dma_setup)(struct mmci_host *host);
void (*dma_release)(struct mmci_host *host); void (*dma_release)(struct mmci_host *host);
...@@ -429,6 +428,12 @@ struct mmci_host { ...@@ -429,6 +428,12 @@ struct mmci_host {
void mmci_write_clkreg(struct mmci_host *host, u32 clk); void mmci_write_clkreg(struct mmci_host *host, u32 clk);
void mmci_write_pwrreg(struct mmci_host *host, u32 pwr); void mmci_write_pwrreg(struct mmci_host *host, u32 pwr);
static inline u32 mmci_dctrl_blksz(struct mmci_host *host)
{
return (ffs(host->data->blksz) - 1) << 4;
}
#ifdef CONFIG_DMA_ENGINE
int mmci_dmae_prep_data(struct mmci_host *host, struct mmc_data *data, int mmci_dmae_prep_data(struct mmci_host *host, struct mmc_data *data,
bool next); bool next);
void mmci_dmae_unprep_data(struct mmci_host *host, struct mmc_data *data, void mmci_dmae_unprep_data(struct mmci_host *host, struct mmc_data *data,
...@@ -439,3 +444,16 @@ void mmci_dmae_release(struct mmci_host *host); ...@@ -439,3 +444,16 @@ void mmci_dmae_release(struct mmci_host *host);
int mmci_dmae_start(struct mmci_host *host, unsigned int *datactrl); int mmci_dmae_start(struct mmci_host *host, unsigned int *datactrl);
void mmci_dmae_finalize(struct mmci_host *host, struct mmc_data *data); void mmci_dmae_finalize(struct mmci_host *host, struct mmc_data *data);
void mmci_dmae_error(struct mmci_host *host); void mmci_dmae_error(struct mmci_host *host);
#endif
#ifdef CONFIG_MMC_QCOM_DML
void qcom_variant_init(struct mmci_host *host);
#else
static inline void qcom_variant_init(struct mmci_host *host) {}
#endif
#ifdef CONFIG_MMC_STM32_SDMMC
void sdmmc_variant_init(struct mmci_host *host);
#else
static inline void sdmmc_variant_init(struct mmci_host *host) {}
#endif
...@@ -54,10 +54,15 @@ ...@@ -54,10 +54,15 @@
#define DML_OFFSET 0x800 #define DML_OFFSET 0x800
void dml_start_xfer(struct mmci_host *host, struct mmc_data *data) static int qcom_dma_start(struct mmci_host *host, unsigned int *datactrl)
{ {
u32 config; u32 config;
void __iomem *base = host->base + DML_OFFSET; void __iomem *base = host->base + DML_OFFSET;
struct mmc_data *data = host->data;
int ret = mmci_dmae_start(host, datactrl);
if (ret)
return ret;
if (data->flags & MMC_DATA_READ) { if (data->flags & MMC_DATA_READ) {
/* Read operation: configure DML for producer operation */ /* Read operation: configure DML for producer operation */
...@@ -96,6 +101,7 @@ void dml_start_xfer(struct mmci_host *host, struct mmc_data *data) ...@@ -96,6 +101,7 @@ void dml_start_xfer(struct mmci_host *host, struct mmc_data *data)
/* make sure the dml is configured before dma is triggered */ /* make sure the dml is configured before dma is triggered */
wmb(); wmb();
return 0;
} }
static int of_get_dml_pipe_index(struct device_node *np, const char *name) static int of_get_dml_pipe_index(struct device_node *np, const char *name)
...@@ -133,7 +139,6 @@ static int qcom_dma_setup(struct mmci_host *host) ...@@ -133,7 +139,6 @@ static int qcom_dma_setup(struct mmci_host *host)
producer_id = of_get_dml_pipe_index(np, "rx"); producer_id = of_get_dml_pipe_index(np, "rx");
if (producer_id < 0 || consumer_id < 0) { if (producer_id < 0 || consumer_id < 0) {
host->variant->qcom_dml = false;
mmci_dmae_release(host); mmci_dmae_release(host);
return -EINVAL; return -EINVAL;
} }
...@@ -183,13 +188,19 @@ static int qcom_dma_setup(struct mmci_host *host) ...@@ -183,13 +188,19 @@ static int qcom_dma_setup(struct mmci_host *host)
return 0; return 0;
} }
static u32 qcom_get_dctrl_cfg(struct mmci_host *host)
{
return MCI_DPSM_ENABLE | (host->data->blksz << 4);
}
static struct mmci_host_ops qcom_variant_ops = { static struct mmci_host_ops qcom_variant_ops = {
.prep_data = mmci_dmae_prep_data, .prep_data = mmci_dmae_prep_data,
.unprep_data = mmci_dmae_unprep_data, .unprep_data = mmci_dmae_unprep_data,
.get_datactrl_cfg = qcom_get_dctrl_cfg,
.get_next_data = mmci_dmae_get_next_data, .get_next_data = mmci_dmae_get_next_data,
.dma_setup = qcom_dma_setup, .dma_setup = qcom_dma_setup,
.dma_release = mmci_dmae_release, .dma_release = mmci_dmae_release,
.dma_start = mmci_dmae_start, .dma_start = qcom_dma_start,
.dma_finalize = mmci_dmae_finalize, .dma_finalize = mmci_dmae_finalize,
.dma_error = mmci_dmae_error, .dma_error = mmci_dmae_error,
}; };
......
/*
*
* Copyright (c) 2011, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#ifndef __MMC_QCOM_DML_H__
#define __MMC_QCOM_DML_H__
#ifdef CONFIG_MMC_QCOM_DML
void qcom_variant_init(struct mmci_host *host);
void dml_start_xfer(struct mmci_host *host, struct mmc_data *data);
#else
static inline void qcom_variant_init(struct mmci_host *host)
{
}
static inline void dml_start_xfer(struct mmci_host *host, struct mmc_data *data)
{
}
#endif /* CONFIG_MMC_QCOM_DML */
#endif /* __MMC_QCOM_DML_H__ */
...@@ -265,10 +265,28 @@ static void mmci_sdmmc_set_pwrreg(struct mmci_host *host, unsigned int pwr) ...@@ -265,10 +265,28 @@ static void mmci_sdmmc_set_pwrreg(struct mmci_host *host, unsigned int pwr)
} }
} }
static u32 sdmmc_get_dctrl_cfg(struct mmci_host *host)
{
u32 datactrl;
datactrl = mmci_dctrl_blksz(host);
if (host->mmc->card && mmc_card_sdio(host->mmc->card) &&
host->data->blocks == 1)
datactrl |= MCI_DPSM_STM32_MODE_SDIO;
else if (host->data->stop && !host->mrq->sbc)
datactrl |= MCI_DPSM_STM32_MODE_BLOCK_STOP;
else
datactrl |= MCI_DPSM_STM32_MODE_BLOCK;
return datactrl;
}
static struct mmci_host_ops sdmmc_variant_ops = { static struct mmci_host_ops sdmmc_variant_ops = {
.validate_data = sdmmc_idma_validate_data, .validate_data = sdmmc_idma_validate_data,
.prep_data = sdmmc_idma_prep_data, .prep_data = sdmmc_idma_prep_data,
.unprep_data = sdmmc_idma_unprep_data, .unprep_data = sdmmc_idma_unprep_data,
.get_datactrl_cfg = sdmmc_get_dctrl_cfg,
.dma_setup = sdmmc_idma_setup, .dma_setup = sdmmc_idma_setup,
.dma_start = sdmmc_idma_start, .dma_start = sdmmc_idma_start,
.dma_finalize = sdmmc_idma_finalize, .dma_finalize = sdmmc_idma_finalize,
......
...@@ -300,6 +300,8 @@ ...@@ -300,6 +300,8 @@
#define CMD_TIMEOUT (HZ/10 * 5) /* 100ms x5 */ #define CMD_TIMEOUT (HZ/10 * 5) /* 100ms x5 */
#define DAT_TIMEOUT (HZ * 5) /* 1000ms x5 */ #define DAT_TIMEOUT (HZ * 5) /* 1000ms x5 */
#define DEFAULT_DEBOUNCE (8) /* 8 cycles CD debounce */
#define PAD_DELAY_MAX 32 /* PAD delay cells */ #define PAD_DELAY_MAX 32 /* PAD delay cells */
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
/* Descriptor Structure */ /* Descriptor Structure */
...@@ -372,6 +374,7 @@ struct mtk_mmc_compatible { ...@@ -372,6 +374,7 @@ struct mtk_mmc_compatible {
bool stop_clk_fix; bool stop_clk_fix;
bool enhance_rx; bool enhance_rx;
bool support_64g; bool support_64g;
bool use_internal_cd;
}; };
struct msdc_tune_para { struct msdc_tune_para {
...@@ -430,6 +433,7 @@ struct msdc_host { ...@@ -430,6 +433,7 @@ struct msdc_host {
bool hs400_cmd_resp_sel_rising; bool hs400_cmd_resp_sel_rising;
/* cmd response sample selection for HS400 */ /* cmd response sample selection for HS400 */
bool hs400_mode; /* current eMMC will run at hs400 mode */ bool hs400_mode; /* current eMMC will run at hs400 mode */
bool internal_cd; /* Use internal card-detect logic */
struct msdc_save_para save_para; /* used when gate HCLK */ struct msdc_save_para save_para; /* used when gate HCLK */
struct msdc_tune_para def_tune_para; /* default tune setting */ struct msdc_tune_para def_tune_para; /* default tune setting */
struct msdc_tune_para saved_tune_para; /* tune result of CMD21/CMD19 */ struct msdc_tune_para saved_tune_para; /* tune result of CMD21/CMD19 */
...@@ -507,6 +511,28 @@ static const struct mtk_mmc_compatible mt7622_compat = { ...@@ -507,6 +511,28 @@ static const struct mtk_mmc_compatible mt7622_compat = {
.support_64g = false, .support_64g = false,
}; };
static const struct mtk_mmc_compatible mt8516_compat = {
.clk_div_bits = 12,
.hs400_tune = false,
.pad_tune_reg = MSDC_PAD_TUNE0,
.async_fifo = true,
.data_tune = true,
.busy_check = true,
.stop_clk_fix = true,
};
static const struct mtk_mmc_compatible mt7620_compat = {
.clk_div_bits = 8,
.hs400_tune = false,
.pad_tune_reg = MSDC_PAD_TUNE,
.async_fifo = false,
.data_tune = false,
.busy_check = false,
.stop_clk_fix = false,
.enhance_rx = false,
.use_internal_cd = true,
};
static const struct of_device_id msdc_of_ids[] = { static const struct of_device_id msdc_of_ids[] = {
{ .compatible = "mediatek,mt8135-mmc", .data = &mt8135_compat}, { .compatible = "mediatek,mt8135-mmc", .data = &mt8135_compat},
{ .compatible = "mediatek,mt8173-mmc", .data = &mt8173_compat}, { .compatible = "mediatek,mt8173-mmc", .data = &mt8173_compat},
...@@ -514,6 +540,8 @@ static const struct of_device_id msdc_of_ids[] = { ...@@ -514,6 +540,8 @@ static const struct of_device_id msdc_of_ids[] = {
{ .compatible = "mediatek,mt2701-mmc", .data = &mt2701_compat}, { .compatible = "mediatek,mt2701-mmc", .data = &mt2701_compat},
{ .compatible = "mediatek,mt2712-mmc", .data = &mt2712_compat}, { .compatible = "mediatek,mt2712-mmc", .data = &mt2712_compat},
{ .compatible = "mediatek,mt7622-mmc", .data = &mt7622_compat}, { .compatible = "mediatek,mt7622-mmc", .data = &mt7622_compat},
{ .compatible = "mediatek,mt8516-mmc", .data = &mt8516_compat},
{ .compatible = "mediatek,mt7620-mmc", .data = &mt7620_compat},
{} {}
}; };
MODULE_DEVICE_TABLE(of, msdc_of_ids); MODULE_DEVICE_TABLE(of, msdc_of_ids);
...@@ -1407,6 +1435,12 @@ static irqreturn_t msdc_irq(int irq, void *dev_id) ...@@ -1407,6 +1435,12 @@ static irqreturn_t msdc_irq(int irq, void *dev_id)
sdio_signal_irq(host->mmc); sdio_signal_irq(host->mmc);
} }
if ((events & event_mask) & MSDC_INT_CDSC) {
if (host->internal_cd)
mmc_detect_change(host->mmc, msecs_to_jiffies(20));
events &= ~MSDC_INT_CDSC;
}
if (!(events & (event_mask & ~MSDC_INT_SDIOIRQ))) if (!(events & (event_mask & ~MSDC_INT_SDIOIRQ)))
break; break;
...@@ -1440,14 +1474,24 @@ static void msdc_init_hw(struct msdc_host *host) ...@@ -1440,14 +1474,24 @@ static void msdc_init_hw(struct msdc_host *host)
/* Reset */ /* Reset */
msdc_reset_hw(host); msdc_reset_hw(host);
/* Disable card detection */
sdr_clr_bits(host->base + MSDC_PS, MSDC_PS_CDEN);
/* Disable and clear all interrupts */ /* Disable and clear all interrupts */
writel(0, host->base + MSDC_INTEN); writel(0, host->base + MSDC_INTEN);
val = readl(host->base + MSDC_INT); val = readl(host->base + MSDC_INT);
writel(val, host->base + MSDC_INT); writel(val, host->base + MSDC_INT);
/* Configure card detection */
if (host->internal_cd) {
sdr_set_field(host->base + MSDC_PS, MSDC_PS_CDDEBOUNCE,
DEFAULT_DEBOUNCE);
sdr_set_bits(host->base + MSDC_PS, MSDC_PS_CDEN);
sdr_set_bits(host->base + MSDC_INTEN, MSDC_INTEN_CDSC);
sdr_set_bits(host->base + SDC_CFG, SDC_CFG_INSWKUP);
} else {
sdr_clr_bits(host->base + SDC_CFG, SDC_CFG_INSWKUP);
sdr_clr_bits(host->base + MSDC_PS, MSDC_PS_CDEN);
sdr_clr_bits(host->base + MSDC_INTEN, MSDC_INTEN_CDSC);
}
if (host->top_base) { if (host->top_base) {
writel(0, host->top_base + EMMC_TOP_CONTROL); writel(0, host->top_base + EMMC_TOP_CONTROL);
writel(0, host->top_base + EMMC_TOP_CMD); writel(0, host->top_base + EMMC_TOP_CMD);
...@@ -1557,6 +1601,13 @@ static void msdc_init_hw(struct msdc_host *host) ...@@ -1557,6 +1601,13 @@ static void msdc_init_hw(struct msdc_host *host)
static void msdc_deinit_hw(struct msdc_host *host) static void msdc_deinit_hw(struct msdc_host *host)
{ {
u32 val; u32 val;
if (host->internal_cd) {
/* Disabled card-detect */
sdr_clr_bits(host->base + MSDC_PS, MSDC_PS_CDEN);
sdr_clr_bits(host->base + SDC_CFG, SDC_CFG_INSWKUP);
}
/* Disable and clear all interrupts */ /* Disable and clear all interrupts */
writel(0, host->base + MSDC_INTEN); writel(0, host->base + MSDC_INTEN);
...@@ -2055,13 +2106,31 @@ static void msdc_ack_sdio_irq(struct mmc_host *mmc) ...@@ -2055,13 +2106,31 @@ static void msdc_ack_sdio_irq(struct mmc_host *mmc)
__msdc_enable_sdio_irq(mmc, 1); __msdc_enable_sdio_irq(mmc, 1);
} }
static int msdc_get_cd(struct mmc_host *mmc)
{
struct msdc_host *host = mmc_priv(mmc);
int val;
if (mmc->caps & MMC_CAP_NONREMOVABLE)
return 1;
if (!host->internal_cd)
return mmc_gpio_get_cd(mmc);
val = readl(host->base + MSDC_PS) & MSDC_PS_CDSTS;
if (mmc->caps2 & MMC_CAP2_CD_ACTIVE_HIGH)
return !!val;
else
return !val;
}
static const struct mmc_host_ops mt_msdc_ops = { static const struct mmc_host_ops mt_msdc_ops = {
.post_req = msdc_post_req, .post_req = msdc_post_req,
.pre_req = msdc_pre_req, .pre_req = msdc_pre_req,
.request = msdc_ops_request, .request = msdc_ops_request,
.set_ios = msdc_ops_set_ios, .set_ios = msdc_ops_set_ios,
.get_ro = mmc_gpio_get_ro, .get_ro = mmc_gpio_get_ro,
.get_cd = mmc_gpio_get_cd, .get_cd = msdc_get_cd,
.enable_sdio_irq = msdc_enable_sdio_irq, .enable_sdio_irq = msdc_enable_sdio_irq,
.ack_sdio_irq = msdc_ack_sdio_irq, .ack_sdio_irq = msdc_ack_sdio_irq,
.start_signal_voltage_switch = msdc_ops_switch_volt, .start_signal_voltage_switch = msdc_ops_switch_volt,
...@@ -2123,9 +2192,11 @@ static int msdc_drv_probe(struct platform_device *pdev) ...@@ -2123,9 +2192,11 @@ static int msdc_drv_probe(struct platform_device *pdev)
} }
res = platform_get_resource(pdev, IORESOURCE_MEM, 1); res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
host->top_base = devm_ioremap_resource(&pdev->dev, res); if (res) {
if (IS_ERR(host->top_base)) host->top_base = devm_ioremap_resource(&pdev->dev, res);
host->top_base = NULL; if (IS_ERR(host->top_base))
host->top_base = NULL;
}
ret = mmc_regulator_get_supply(mmc); ret = mmc_regulator_get_supply(mmc);
if (ret) if (ret)
...@@ -2191,6 +2262,16 @@ static int msdc_drv_probe(struct platform_device *pdev) ...@@ -2191,6 +2262,16 @@ static int msdc_drv_probe(struct platform_device *pdev)
else else
mmc->f_min = DIV_ROUND_UP(host->src_clk_freq, 4 * 4095); mmc->f_min = DIV_ROUND_UP(host->src_clk_freq, 4 * 4095);
if (!(mmc->caps & MMC_CAP_NONREMOVABLE) &&
!mmc_can_gpio_cd(mmc) &&
host->dev_comp->use_internal_cd) {
/*
* Is removable but no GPIO declared, so
* use internal functionality.
*/
host->internal_cd = true;
}
if (mmc->caps & MMC_CAP_SDIO_IRQ) if (mmc->caps & MMC_CAP_SDIO_IRQ)
mmc->caps2 |= MMC_CAP2_SDIO_IRQ_NOTHREAD; mmc->caps2 |= MMC_CAP2_SDIO_IRQ_NOTHREAD;
...@@ -2227,7 +2308,7 @@ static int msdc_drv_probe(struct platform_device *pdev) ...@@ -2227,7 +2308,7 @@ static int msdc_drv_probe(struct platform_device *pdev)
msdc_init_hw(host); msdc_init_hw(host);
ret = devm_request_irq(&pdev->dev, host->irq, msdc_irq, ret = devm_request_irq(&pdev->dev, host->irq, msdc_irq,
IRQF_TRIGGER_LOW | IRQF_ONESHOT, pdev->name, host); IRQF_TRIGGER_NONE, pdev->name, host);
if (ret) if (ret)
goto release; goto release;
......
...@@ -648,7 +648,8 @@ static int mxs_mmc_probe(struct platform_device *pdev) ...@@ -648,7 +648,8 @@ static int mxs_mmc_probe(struct platform_device *pdev)
/* set mmc core parameters */ /* set mmc core parameters */
mmc->ops = &mxs_mmc_ops; mmc->ops = &mxs_mmc_ops;
mmc->caps = MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED | mmc->caps = MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED |
MMC_CAP_SDIO_IRQ | MMC_CAP_NEEDS_POLL | MMC_CAP_CMD23; MMC_CAP_SDIO_IRQ | MMC_CAP_NEEDS_POLL | MMC_CAP_CMD23 |
MMC_CAP_ERASE;
host->broken_cd = of_property_read_bool(np, "broken-cd"); host->broken_cd = of_property_read_bool(np, "broken-cd");
......
// SPDX-License-Identifier: GPL-2.0-or-later
/* /*
* OpenFirmware bindings for the MMC-over-SPI driver * OpenFirmware bindings for the MMC-over-SPI driver
* *
* Copyright (c) MontaVista Software, Inc. 2008. * Copyright (c) MontaVista Software, Inc. 2008.
* *
* Author: Anton Vorontsov <avorontsov@ru.mvista.com> * Author: Anton Vorontsov <avorontsov@ru.mvista.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/ */
#include <linux/kernel.h> #include <linux/kernel.h>
......
...@@ -2077,7 +2077,7 @@ static int omap_hsmmc_runtime_suspend(struct device *dev) ...@@ -2077,7 +2077,7 @@ static int omap_hsmmc_runtime_suspend(struct device *dev)
unsigned long flags; unsigned long flags;
int ret = 0; int ret = 0;
host = platform_get_drvdata(to_platform_device(dev)); host = dev_get_drvdata(dev);
omap_hsmmc_context_save(host); omap_hsmmc_context_save(host);
dev_dbg(dev, "disabled\n"); dev_dbg(dev, "disabled\n");
...@@ -2118,7 +2118,7 @@ static int omap_hsmmc_runtime_resume(struct device *dev) ...@@ -2118,7 +2118,7 @@ static int omap_hsmmc_runtime_resume(struct device *dev)
struct omap_hsmmc_host *host; struct omap_hsmmc_host *host;
unsigned long flags; unsigned long flags;
host = platform_get_drvdata(to_platform_device(dev)); host = dev_get_drvdata(dev);
omap_hsmmc_context_restore(host); omap_hsmmc_context_restore(host);
dev_dbg(dev, "enabled\n"); dev_dbg(dev, "enabled\n");
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* Renesas Mobile SDHI * Renesas Mobile SDHI
* *
* Copyright (C) 2017 Horms Solutions Ltd., Simon Horman * Copyright (C) 2017 Horms Solutions Ltd., Simon Horman
* Copyright (C) 2017 Renesas Electronics Corporation * Copyright (C) 2017-19 Renesas Electronics Corporation
*/ */
#ifndef RENESAS_SDHI_H #ifndef RENESAS_SDHI_H
......
...@@ -2,8 +2,8 @@ ...@@ -2,8 +2,8 @@
/* /*
* Renesas SDHI * Renesas SDHI
* *
* Copyright (C) 2015-17 Renesas Electronics Corporation * Copyright (C) 2015-19 Renesas Electronics Corporation
* Copyright (C) 2016-17 Sang Engineering, Wolfram Sang * Copyright (C) 2016-19 Sang Engineering, Wolfram Sang
* Copyright (C) 2016-17 Horms Solutions, Simon Horman * Copyright (C) 2016-17 Horms Solutions, Simon Horman
* Copyright (C) 2009 Magnus Damm * Copyright (C) 2009 Magnus Damm
* *
...@@ -779,14 +779,14 @@ int renesas_sdhi_probe(struct platform_device *pdev, ...@@ -779,14 +779,14 @@ int renesas_sdhi_probe(struct platform_device *pdev,
if (ver < SDHI_VER_GEN2_SDR104 && mmc_data->max_blk_count > U16_MAX) if (ver < SDHI_VER_GEN2_SDR104 && mmc_data->max_blk_count > U16_MAX)
mmc_data->max_blk_count = U16_MAX; mmc_data->max_blk_count = U16_MAX;
ret = tmio_mmc_host_probe(host);
if (ret < 0)
goto edisclk;
/* One Gen2 SDHI incarnation does NOT have a CBSY bit */ /* One Gen2 SDHI incarnation does NOT have a CBSY bit */
if (ver == SDHI_VER_GEN2_SDR50) if (ver == SDHI_VER_GEN2_SDR50)
mmc_data->flags &= ~TMIO_MMC_HAVE_CBSY; mmc_data->flags &= ~TMIO_MMC_HAVE_CBSY;
ret = tmio_mmc_host_probe(host);
if (ret < 0)
goto edisclk;
/* Enable tuning iff we have an SCC and a supported mode */ /* Enable tuning iff we have an SCC and a supported mode */
if (of_data && of_data->scc_offset && if (of_data && of_data->scc_offset &&
(host->mmc->caps & MMC_CAP_UHS_SDR104 || (host->mmc->caps & MMC_CAP_UHS_SDR104 ||
......
...@@ -2,8 +2,9 @@ ...@@ -2,8 +2,9 @@
/* /*
* DMA support for Internal DMAC with SDHI SD/SDIO controller * DMA support for Internal DMAC with SDHI SD/SDIO controller
* *
* Copyright (C) 2016-17 Renesas Electronics Corporation * Copyright (C) 2016-19 Renesas Electronics Corporation
* Copyright (C) 2016-17 Horms Solutions, Simon Horman * Copyright (C) 2016-17 Horms Solutions, Simon Horman
* Copyright (C) 2018-19 Sang Engineering, Wolfram Sang
*/ */
#include <linux/bitops.h> #include <linux/bitops.h>
...@@ -95,8 +96,8 @@ static const struct renesas_sdhi_of_data of_rza2_compatible = { ...@@ -95,8 +96,8 @@ static const struct renesas_sdhi_of_data of_rza2_compatible = {
.scc_offset = 0 - 0x1000, .scc_offset = 0 - 0x1000,
.taps = rcar_gen3_scc_taps, .taps = rcar_gen3_scc_taps,
.taps_num = ARRAY_SIZE(rcar_gen3_scc_taps), .taps_num = ARRAY_SIZE(rcar_gen3_scc_taps),
/* DMAC can handle 0xffffffff blk count but only 1 segment */ /* DMAC can handle 32bit blk count but only 1 segment */
.max_blk_count = 0xffffffff, .max_blk_count = UINT_MAX / TMIO_MAX_BLK_SIZE,
.max_segs = 1, .max_segs = 1,
}; };
...@@ -110,8 +111,8 @@ static const struct renesas_sdhi_of_data of_rcar_gen3_compatible = { ...@@ -110,8 +111,8 @@ static const struct renesas_sdhi_of_data of_rcar_gen3_compatible = {
.scc_offset = 0x1000, .scc_offset = 0x1000,
.taps = rcar_gen3_scc_taps, .taps = rcar_gen3_scc_taps,
.taps_num = ARRAY_SIZE(rcar_gen3_scc_taps), .taps_num = ARRAY_SIZE(rcar_gen3_scc_taps),
/* DMAC can handle 0xffffffff blk count but only 1 segment */ /* DMAC can handle 32bit blk count but only 1 segment */
.max_blk_count = 0xffffffff, .max_blk_count = UINT_MAX / TMIO_MAX_BLK_SIZE,
.max_segs = 1, .max_segs = 1,
}; };
......
...@@ -2,8 +2,8 @@ ...@@ -2,8 +2,8 @@
/* /*
* DMA support use of SYS DMAC with SDHI SD/SDIO controller * DMA support use of SYS DMAC with SDHI SD/SDIO controller
* *
* Copyright (C) 2016-17 Renesas Electronics Corporation * Copyright (C) 2016-19 Renesas Electronics Corporation
* Copyright (C) 2016-17 Sang Engineering, Wolfram Sang * Copyright (C) 2016-19 Sang Engineering, Wolfram Sang
* Copyright (C) 2017 Horms Solutions, Simon Horman * Copyright (C) 2017 Horms Solutions, Simon Horman
* Copyright (C) 2010-2011 Guennadi Liakhovetski * Copyright (C) 2010-2011 Guennadi Liakhovetski
*/ */
...@@ -65,7 +65,7 @@ static const struct renesas_sdhi_of_data of_rcar_gen2_compatible = { ...@@ -65,7 +65,7 @@ static const struct renesas_sdhi_of_data of_rcar_gen2_compatible = {
.scc_offset = 0x0300, .scc_offset = 0x0300,
.taps = rcar_gen2_scc_taps, .taps = rcar_gen2_scc_taps,
.taps_num = ARRAY_SIZE(rcar_gen2_scc_taps), .taps_num = ARRAY_SIZE(rcar_gen2_scc_taps),
.max_blk_count = 0xffffffff, .max_blk_count = UINT_MAX / TMIO_MAX_BLK_SIZE,
}; };
/* Definitions for sampling clocks */ /* Definitions for sampling clocks */
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/pm_qos.h>
#include <linux/mmc/host.h> #include <linux/mmc/host.h>
#include <linux/mmc/mmc.h> #include <linux/mmc/mmc.h>
#include <linux/mmc/sdio.h> #include <linux/mmc/sdio.h>
...@@ -73,6 +74,7 @@ ...@@ -73,6 +74,7 @@
#define ESDHC_STROBE_DLL_CTRL_ENABLE (1 << 0) #define ESDHC_STROBE_DLL_CTRL_ENABLE (1 << 0)
#define ESDHC_STROBE_DLL_CTRL_RESET (1 << 1) #define ESDHC_STROBE_DLL_CTRL_RESET (1 << 1)
#define ESDHC_STROBE_DLL_CTRL_SLV_DLY_TARGET_SHIFT 3 #define ESDHC_STROBE_DLL_CTRL_SLV_DLY_TARGET_SHIFT 3
#define ESDHC_STROBE_DLL_CTRL_SLV_UPDATE_INT_DEFAULT (4 << 20)
#define ESDHC_STROBE_DLL_STATUS 0x74 #define ESDHC_STROBE_DLL_STATUS 0x74
#define ESDHC_STROBE_DLL_STS_REF_LOCK (1 << 1) #define ESDHC_STROBE_DLL_STS_REF_LOCK (1 << 1)
...@@ -156,6 +158,8 @@ ...@@ -156,6 +158,8 @@
#define ESDHC_FLAG_HS400_ES BIT(11) #define ESDHC_FLAG_HS400_ES BIT(11)
/* The IP has Host Controller Interface for Command Queuing */ /* The IP has Host Controller Interface for Command Queuing */
#define ESDHC_FLAG_CQHCI BIT(12) #define ESDHC_FLAG_CQHCI BIT(12)
/* need request pmqos during low power */
#define ESDHC_FLAG_PMQOS BIT(13)
struct esdhc_soc_data { struct esdhc_soc_data {
u32 flags; u32 flags;
...@@ -204,6 +208,12 @@ static const struct esdhc_soc_data usdhc_imx7d_data = { ...@@ -204,6 +208,12 @@ static const struct esdhc_soc_data usdhc_imx7d_data = {
| ESDHC_FLAG_HS400, | ESDHC_FLAG_HS400,
}; };
static struct esdhc_soc_data usdhc_imx7ulp_data = {
.flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING
| ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200
| ESDHC_FLAG_PMQOS | ESDHC_FLAG_HS400,
};
static struct esdhc_soc_data usdhc_imx8qxp_data = { static struct esdhc_soc_data usdhc_imx8qxp_data = {
.flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING
| ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200 | ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200
...@@ -229,6 +239,7 @@ struct pltfm_imx_data { ...@@ -229,6 +239,7 @@ struct pltfm_imx_data {
WAIT_FOR_INT, /* sent CMD12, waiting for response INT */ WAIT_FOR_INT, /* sent CMD12, waiting for response INT */
} multiblock_status; } multiblock_status;
u32 is_ddr; u32 is_ddr;
struct pm_qos_request pm_qos_req;
}; };
static const struct platform_device_id imx_esdhc_devtype[] = { static const struct platform_device_id imx_esdhc_devtype[] = {
...@@ -257,6 +268,7 @@ static const struct of_device_id imx_esdhc_dt_ids[] = { ...@@ -257,6 +268,7 @@ static const struct of_device_id imx_esdhc_dt_ids[] = {
{ .compatible = "fsl,imx6q-usdhc", .data = &usdhc_imx6q_data, }, { .compatible = "fsl,imx6q-usdhc", .data = &usdhc_imx6q_data, },
{ .compatible = "fsl,imx6ull-usdhc", .data = &usdhc_imx6ull_data, }, { .compatible = "fsl,imx6ull-usdhc", .data = &usdhc_imx6ull_data, },
{ .compatible = "fsl,imx7d-usdhc", .data = &usdhc_imx7d_data, }, { .compatible = "fsl,imx7d-usdhc", .data = &usdhc_imx7d_data, },
{ .compatible = "fsl,imx7ulp-usdhc", .data = &usdhc_imx7ulp_data, },
{ .compatible = "fsl,imx8qxp-usdhc", .data = &usdhc_imx8qxp_data, }, { .compatible = "fsl,imx8qxp-usdhc", .data = &usdhc_imx8qxp_data, },
{ /* sentinel */ } { /* sentinel */ }
}; };
...@@ -983,15 +995,19 @@ static void esdhc_set_strobe_dll(struct sdhci_host *host) ...@@ -983,15 +995,19 @@ static void esdhc_set_strobe_dll(struct sdhci_host *host)
/* force a reset on strobe dll */ /* force a reset on strobe dll */
writel(ESDHC_STROBE_DLL_CTRL_RESET, writel(ESDHC_STROBE_DLL_CTRL_RESET,
host->ioaddr + ESDHC_STROBE_DLL_CTRL); host->ioaddr + ESDHC_STROBE_DLL_CTRL);
/* clear the reset bit on strobe dll before any setting */
writel(0, host->ioaddr + ESDHC_STROBE_DLL_CTRL);
/* /*
* enable strobe dll ctrl and adjust the delay target * enable strobe dll ctrl and adjust the delay target
* for the uSDHC loopback read clock * for the uSDHC loopback read clock
*/ */
v = ESDHC_STROBE_DLL_CTRL_ENABLE | v = ESDHC_STROBE_DLL_CTRL_ENABLE |
ESDHC_STROBE_DLL_CTRL_SLV_UPDATE_INT_DEFAULT |
(7 << ESDHC_STROBE_DLL_CTRL_SLV_DLY_TARGET_SHIFT); (7 << ESDHC_STROBE_DLL_CTRL_SLV_DLY_TARGET_SHIFT);
writel(v, host->ioaddr + ESDHC_STROBE_DLL_CTRL); writel(v, host->ioaddr + ESDHC_STROBE_DLL_CTRL);
/* wait 1us to make sure strobe dll status register stable */ /* wait 5us to make sure strobe dll status register stable */
udelay(1); udelay(5);
v = readl(host->ioaddr + ESDHC_STROBE_DLL_STATUS); v = readl(host->ioaddr + ESDHC_STROBE_DLL_STATUS);
if (!(v & ESDHC_STROBE_DLL_STS_REF_LOCK)) if (!(v & ESDHC_STROBE_DLL_STS_REF_LOCK))
dev_warn(mmc_dev(host->mmc), dev_warn(mmc_dev(host->mmc),
...@@ -1436,6 +1452,10 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev) ...@@ -1436,6 +1452,10 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
imx_data->socdata = of_id ? of_id->data : (struct esdhc_soc_data *) imx_data->socdata = of_id ? of_id->data : (struct esdhc_soc_data *)
pdev->id_entry->driver_data; pdev->id_entry->driver_data;
if (imx_data->socdata->flags & ESDHC_FLAG_PMQOS)
pm_qos_add_request(&imx_data->pm_qos_req,
PM_QOS_CPU_DMA_LATENCY, 0);
imx_data->clk_ipg = devm_clk_get(&pdev->dev, "ipg"); imx_data->clk_ipg = devm_clk_get(&pdev->dev, "ipg");
if (IS_ERR(imx_data->clk_ipg)) { if (IS_ERR(imx_data->clk_ipg)) {
err = PTR_ERR(imx_data->clk_ipg); err = PTR_ERR(imx_data->clk_ipg);
...@@ -1557,6 +1577,8 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev) ...@@ -1557,6 +1577,8 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
disable_per_clk: disable_per_clk:
clk_disable_unprepare(imx_data->clk_per); clk_disable_unprepare(imx_data->clk_per);
free_sdhci: free_sdhci:
if (imx_data->socdata->flags & ESDHC_FLAG_PMQOS)
pm_qos_remove_request(&imx_data->pm_qos_req);
sdhci_pltfm_free(pdev); sdhci_pltfm_free(pdev);
return err; return err;
} }
...@@ -1578,6 +1600,9 @@ static int sdhci_esdhc_imx_remove(struct platform_device *pdev) ...@@ -1578,6 +1600,9 @@ static int sdhci_esdhc_imx_remove(struct platform_device *pdev)
clk_disable_unprepare(imx_data->clk_ipg); clk_disable_unprepare(imx_data->clk_ipg);
clk_disable_unprepare(imx_data->clk_ahb); clk_disable_unprepare(imx_data->clk_ahb);
if (imx_data->socdata->flags & ESDHC_FLAG_PMQOS)
pm_qos_remove_request(&imx_data->pm_qos_req);
sdhci_pltfm_free(pdev); sdhci_pltfm_free(pdev);
return 0; return 0;
...@@ -1649,6 +1674,9 @@ static int sdhci_esdhc_runtime_suspend(struct device *dev) ...@@ -1649,6 +1674,9 @@ static int sdhci_esdhc_runtime_suspend(struct device *dev)
} }
clk_disable_unprepare(imx_data->clk_ahb); clk_disable_unprepare(imx_data->clk_ahb);
if (imx_data->socdata->flags & ESDHC_FLAG_PMQOS)
pm_qos_remove_request(&imx_data->pm_qos_req);
return ret; return ret;
} }
...@@ -1659,9 +1687,13 @@ static int sdhci_esdhc_runtime_resume(struct device *dev) ...@@ -1659,9 +1687,13 @@ static int sdhci_esdhc_runtime_resume(struct device *dev)
struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
int err; int err;
if (imx_data->socdata->flags & ESDHC_FLAG_PMQOS)
pm_qos_add_request(&imx_data->pm_qos_req,
PM_QOS_CPU_DMA_LATENCY, 0);
err = clk_prepare_enable(imx_data->clk_ahb); err = clk_prepare_enable(imx_data->clk_ahb);
if (err) if (err)
return err; goto remove_pm_qos_request;
if (!sdhci_sdio_irq_enabled(host)) { if (!sdhci_sdio_irq_enabled(host)) {
err = clk_prepare_enable(imx_data->clk_per); err = clk_prepare_enable(imx_data->clk_per);
...@@ -1690,6 +1722,9 @@ static int sdhci_esdhc_runtime_resume(struct device *dev) ...@@ -1690,6 +1722,9 @@ static int sdhci_esdhc_runtime_resume(struct device *dev)
clk_disable_unprepare(imx_data->clk_per); clk_disable_unprepare(imx_data->clk_per);
disable_ahb_clk: disable_ahb_clk:
clk_disable_unprepare(imx_data->clk_ahb); clk_disable_unprepare(imx_data->clk_ahb);
remove_pm_qos_request:
if (imx_data->socdata->flags & ESDHC_FLAG_PMQOS)
pm_qos_remove_request(&imx_data->pm_qos_req);
return err; return err;
} }
#endif #endif
......
...@@ -832,7 +832,10 @@ static int sdhci_arasan_probe(struct platform_device *pdev) ...@@ -832,7 +832,10 @@ static int sdhci_arasan_probe(struct platform_device *pdev)
host->mmc_host_ops.start_signal_voltage_switch = host->mmc_host_ops.start_signal_voltage_switch =
sdhci_arasan_voltage_switch; sdhci_arasan_voltage_switch;
sdhci_arasan->has_cqe = true; sdhci_arasan->has_cqe = true;
host->mmc->caps2 |= MMC_CAP2_CQE | MMC_CAP2_CQE_DCMD; host->mmc->caps2 |= MMC_CAP2_CQE;
if (!of_property_read_bool(np, "disable-cqe-dcmd"))
host->mmc->caps2 |= MMC_CAP2_CQE_DCMD;
} }
ret = sdhci_arasan_add_host(sdhci_arasan); ret = sdhci_arasan_add_host(sdhci_arasan);
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include <linux/ktime.h> #include <linux/ktime.h>
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <linux/mmc/host.h> #include <linux/mmc/host.h>
#include <linux/mmc/mmc.h>
#include "sdhci-pltfm.h" #include "sdhci-pltfm.h"
#include "sdhci-esdhc.h" #include "sdhci-esdhc.h"
...@@ -81,6 +82,7 @@ struct sdhci_esdhc { ...@@ -81,6 +82,7 @@ struct sdhci_esdhc {
bool quirk_limited_clk_division; bool quirk_limited_clk_division;
bool quirk_unreliable_pulse_detection; bool quirk_unreliable_pulse_detection;
bool quirk_fixup_tuning; bool quirk_fixup_tuning;
bool quirk_ignore_data_inhibit;
unsigned int peripheral_clock; unsigned int peripheral_clock;
const struct esdhc_clk_fixup *clk_fixup; const struct esdhc_clk_fixup *clk_fixup;
u32 div_ratio; u32 div_ratio;
...@@ -147,6 +149,19 @@ static u32 esdhc_readl_fixup(struct sdhci_host *host, ...@@ -147,6 +149,19 @@ static u32 esdhc_readl_fixup(struct sdhci_host *host,
return ret; return ret;
} }
/*
* Some controllers have unreliable Data Line Active
* bit for commands with busy signal. This affects
* Command Inhibit (data) bit. Just ignore it since
* MMC core driver has already polled card status
* with CMD13 after any command with busy siganl.
*/
if ((spec_reg == SDHCI_PRESENT_STATE) &&
(esdhc->quirk_ignore_data_inhibit == true)) {
ret = value & ~SDHCI_DATA_INHIBIT;
return ret;
}
ret = value; ret = value;
return ret; return ret;
} }
...@@ -694,6 +709,9 @@ static void esdhc_reset(struct sdhci_host *host, u8 mask) ...@@ -694,6 +709,9 @@ static void esdhc_reset(struct sdhci_host *host, u8 mask)
sdhci_writel(host, host->ier, SDHCI_INT_ENABLE); sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
if (of_find_compatible_node(NULL, NULL, "fsl,p2020-esdhc"))
mdelay(5);
if (mask & SDHCI_RESET_ALL) { if (mask & SDHCI_RESET_ALL) {
val = sdhci_readl(host, ESDHC_TBCTL); val = sdhci_readl(host, ESDHC_TBCTL);
val &= ~ESDHC_TB_EN; val &= ~ESDHC_TB_EN;
...@@ -864,6 +882,25 @@ static void esdhc_set_uhs_signaling(struct sdhci_host *host, ...@@ -864,6 +882,25 @@ static void esdhc_set_uhs_signaling(struct sdhci_host *host,
sdhci_set_uhs_signaling(host, timing); sdhci_set_uhs_signaling(host, timing);
} }
static u32 esdhc_irq(struct sdhci_host *host, u32 intmask)
{
u32 command;
if (of_find_compatible_node(NULL, NULL,
"fsl,p2020-esdhc")) {
command = SDHCI_GET_CMD(sdhci_readw(host,
SDHCI_COMMAND));
if (command == MMC_WRITE_MULTIPLE_BLOCK &&
sdhci_readw(host, SDHCI_BLOCK_COUNT) &&
intmask & SDHCI_INT_DATA_END) {
intmask &= ~SDHCI_INT_DATA_END;
sdhci_writel(host, SDHCI_INT_DATA_END,
SDHCI_INT_STATUS);
}
}
return intmask;
}
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_SLEEP
static u32 esdhc_proctl; static u32 esdhc_proctl;
static int esdhc_of_suspend(struct device *dev) static int esdhc_of_suspend(struct device *dev)
...@@ -911,6 +948,7 @@ static const struct sdhci_ops sdhci_esdhc_be_ops = { ...@@ -911,6 +948,7 @@ static const struct sdhci_ops sdhci_esdhc_be_ops = {
.set_bus_width = esdhc_pltfm_set_bus_width, .set_bus_width = esdhc_pltfm_set_bus_width,
.reset = esdhc_reset, .reset = esdhc_reset,
.set_uhs_signaling = esdhc_set_uhs_signaling, .set_uhs_signaling = esdhc_set_uhs_signaling,
.irq = esdhc_irq,
}; };
static const struct sdhci_ops sdhci_esdhc_le_ops = { static const struct sdhci_ops sdhci_esdhc_le_ops = {
...@@ -928,6 +966,7 @@ static const struct sdhci_ops sdhci_esdhc_le_ops = { ...@@ -928,6 +966,7 @@ static const struct sdhci_ops sdhci_esdhc_le_ops = {
.set_bus_width = esdhc_pltfm_set_bus_width, .set_bus_width = esdhc_pltfm_set_bus_width,
.reset = esdhc_reset, .reset = esdhc_reset,
.set_uhs_signaling = esdhc_set_uhs_signaling, .set_uhs_signaling = esdhc_set_uhs_signaling,
.irq = esdhc_irq,
}; };
static const struct sdhci_pltfm_data sdhci_esdhc_be_pdata = { static const struct sdhci_pltfm_data sdhci_esdhc_be_pdata = {
...@@ -955,6 +994,7 @@ static struct soc_device_attribute soc_incorrect_hostver[] = { ...@@ -955,6 +994,7 @@ static struct soc_device_attribute soc_incorrect_hostver[] = {
static struct soc_device_attribute soc_fixup_sdhc_clkdivs[] = { static struct soc_device_attribute soc_fixup_sdhc_clkdivs[] = {
{ .family = "QorIQ LX2160A", .revision = "1.0", }, { .family = "QorIQ LX2160A", .revision = "1.0", },
{ .family = "QorIQ LX2160A", .revision = "2.0", },
{ }, { },
}; };
...@@ -1074,6 +1114,11 @@ static int sdhci_esdhc_probe(struct platform_device *pdev) ...@@ -1074,6 +1114,11 @@ static int sdhci_esdhc_probe(struct platform_device *pdev)
if (esdhc->vendor_ver > VENDOR_V_22) if (esdhc->vendor_ver > VENDOR_V_22)
host->quirks &= ~SDHCI_QUIRK_NO_BUSY_IRQ; host->quirks &= ~SDHCI_QUIRK_NO_BUSY_IRQ;
if (of_find_compatible_node(NULL, NULL, "fsl,p2020-esdhc")) {
host->quirks2 |= SDHCI_QUIRK_RESET_AFTER_REQUEST;
host->quirks2 |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL;
}
if (of_device_is_compatible(np, "fsl,p5040-esdhc") || if (of_device_is_compatible(np, "fsl,p5040-esdhc") ||
of_device_is_compatible(np, "fsl,p5020-esdhc") || of_device_is_compatible(np, "fsl,p5020-esdhc") ||
of_device_is_compatible(np, "fsl,p4080-esdhc") || of_device_is_compatible(np, "fsl,p4080-esdhc") ||
...@@ -1084,12 +1129,14 @@ static int sdhci_esdhc_probe(struct platform_device *pdev) ...@@ -1084,12 +1129,14 @@ static int sdhci_esdhc_probe(struct platform_device *pdev)
if (of_device_is_compatible(np, "fsl,ls1021a-esdhc")) if (of_device_is_compatible(np, "fsl,ls1021a-esdhc"))
host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL; host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL;
esdhc->quirk_ignore_data_inhibit = false;
if (of_device_is_compatible(np, "fsl,p2020-esdhc")) { if (of_device_is_compatible(np, "fsl,p2020-esdhc")) {
/* /*
* Freescale messed up with P2020 as it has a non-standard * Freescale messed up with P2020 as it has a non-standard
* host control register * host control register
*/ */
host->quirks2 |= SDHCI_QUIRK2_BROKEN_HOST_CONTROL; host->quirks2 |= SDHCI_QUIRK2_BROKEN_HOST_CONTROL;
esdhc->quirk_ignore_data_inhibit = true;
} }
/* call to generic mmc_of_parse to support additional capabilities */ /* call to generic mmc_of_parse to support additional capabilities */
......
...@@ -785,7 +785,7 @@ static void sdhci_omap_set_uhs_signaling(struct sdhci_host *host, ...@@ -785,7 +785,7 @@ static void sdhci_omap_set_uhs_signaling(struct sdhci_host *host,
sdhci_omap_start_clock(omap_host); sdhci_omap_start_clock(omap_host);
} }
void sdhci_omap_reset(struct sdhci_host *host, u8 mask) static void sdhci_omap_reset(struct sdhci_host *host, u8 mask)
{ {
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_omap_host *omap_host = sdhci_pltfm_priv(pltfm_host); struct sdhci_omap_host *omap_host = sdhci_pltfm_priv(pltfm_host);
......
...@@ -31,6 +31,10 @@ ...@@ -31,6 +31,10 @@
#include <linux/mmc/sdhci-pci-data.h> #include <linux/mmc/sdhci-pci-data.h>
#include <linux/acpi.h> #include <linux/acpi.h>
#ifdef CONFIG_X86
#include <asm/iosf_mbi.h>
#endif
#include "cqhci.h" #include "cqhci.h"
#include "sdhci.h" #include "sdhci.h"
...@@ -451,6 +455,50 @@ static const struct sdhci_pci_fixes sdhci_intel_pch_sdio = { ...@@ -451,6 +455,50 @@ static const struct sdhci_pci_fixes sdhci_intel_pch_sdio = {
.probe_slot = pch_hc_probe_slot, .probe_slot = pch_hc_probe_slot,
}; };
#ifdef CONFIG_X86
#define BYT_IOSF_SCCEP 0x63
#define BYT_IOSF_OCP_NETCTRL0 0x1078
#define BYT_IOSF_OCP_TIMEOUT_BASE GENMASK(10, 8)
static void byt_ocp_setting(struct pci_dev *pdev)
{
u32 val = 0;
if (pdev->device != PCI_DEVICE_ID_INTEL_BYT_EMMC &&
pdev->device != PCI_DEVICE_ID_INTEL_BYT_SDIO &&
pdev->device != PCI_DEVICE_ID_INTEL_BYT_SD &&
pdev->device != PCI_DEVICE_ID_INTEL_BYT_EMMC2)
return;
if (iosf_mbi_read(BYT_IOSF_SCCEP, MBI_CR_READ, BYT_IOSF_OCP_NETCTRL0,
&val)) {
dev_err(&pdev->dev, "%s read error\n", __func__);
return;
}
if (!(val & BYT_IOSF_OCP_TIMEOUT_BASE))
return;
val &= ~BYT_IOSF_OCP_TIMEOUT_BASE;
if (iosf_mbi_write(BYT_IOSF_SCCEP, MBI_CR_WRITE, BYT_IOSF_OCP_NETCTRL0,
val)) {
dev_err(&pdev->dev, "%s write error\n", __func__);
return;
}
dev_dbg(&pdev->dev, "%s completed\n", __func__);
}
#else
static inline void byt_ocp_setting(struct pci_dev *pdev)
{
}
#endif
enum { enum {
INTEL_DSM_FNS = 0, INTEL_DSM_FNS = 0,
INTEL_DSM_V18_SWITCH = 3, INTEL_DSM_V18_SWITCH = 3,
...@@ -715,6 +763,8 @@ static void byt_probe_slot(struct sdhci_pci_slot *slot) ...@@ -715,6 +763,8 @@ static void byt_probe_slot(struct sdhci_pci_slot *slot)
byt_read_dsm(slot); byt_read_dsm(slot);
byt_ocp_setting(slot->chip->pdev);
ops->execute_tuning = intel_execute_tuning; ops->execute_tuning = intel_execute_tuning;
ops->start_signal_voltage_switch = intel_start_signal_voltage_switch; ops->start_signal_voltage_switch = intel_start_signal_voltage_switch;
...@@ -938,7 +988,35 @@ static int byt_sd_probe_slot(struct sdhci_pci_slot *slot) ...@@ -938,7 +988,35 @@ static int byt_sd_probe_slot(struct sdhci_pci_slot *slot)
return 0; return 0;
} }
#ifdef CONFIG_PM_SLEEP
static int byt_resume(struct sdhci_pci_chip *chip)
{
byt_ocp_setting(chip->pdev);
return sdhci_pci_resume_host(chip);
}
#endif
#ifdef CONFIG_PM
static int byt_runtime_resume(struct sdhci_pci_chip *chip)
{
byt_ocp_setting(chip->pdev);
return sdhci_pci_runtime_resume_host(chip);
}
#endif
static const struct sdhci_pci_fixes sdhci_intel_byt_emmc = { static const struct sdhci_pci_fixes sdhci_intel_byt_emmc = {
#ifdef CONFIG_PM_SLEEP
.resume = byt_resume,
#endif
#ifdef CONFIG_PM
.runtime_resume = byt_runtime_resume,
#endif
.allow_runtime_pm = true, .allow_runtime_pm = true,
.probe_slot = byt_emmc_probe_slot, .probe_slot = byt_emmc_probe_slot,
.quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC | .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC |
...@@ -972,6 +1050,12 @@ static const struct sdhci_pci_fixes sdhci_intel_glk_emmc = { ...@@ -972,6 +1050,12 @@ static const struct sdhci_pci_fixes sdhci_intel_glk_emmc = {
}; };
static const struct sdhci_pci_fixes sdhci_ni_byt_sdio = { static const struct sdhci_pci_fixes sdhci_ni_byt_sdio = {
#ifdef CONFIG_PM_SLEEP
.resume = byt_resume,
#endif
#ifdef CONFIG_PM
.runtime_resume = byt_runtime_resume,
#endif
.quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC | .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC |
SDHCI_QUIRK_NO_LED, SDHCI_QUIRK_NO_LED,
.quirks2 = SDHCI_QUIRK2_HOST_OFF_CARD_ON | .quirks2 = SDHCI_QUIRK2_HOST_OFF_CARD_ON |
...@@ -983,6 +1067,12 @@ static const struct sdhci_pci_fixes sdhci_ni_byt_sdio = { ...@@ -983,6 +1067,12 @@ static const struct sdhci_pci_fixes sdhci_ni_byt_sdio = {
}; };
static const struct sdhci_pci_fixes sdhci_intel_byt_sdio = { static const struct sdhci_pci_fixes sdhci_intel_byt_sdio = {
#ifdef CONFIG_PM_SLEEP
.resume = byt_resume,
#endif
#ifdef CONFIG_PM
.runtime_resume = byt_runtime_resume,
#endif
.quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC | .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC |
SDHCI_QUIRK_NO_LED, SDHCI_QUIRK_NO_LED,
.quirks2 = SDHCI_QUIRK2_HOST_OFF_CARD_ON | .quirks2 = SDHCI_QUIRK2_HOST_OFF_CARD_ON |
...@@ -994,6 +1084,12 @@ static const struct sdhci_pci_fixes sdhci_intel_byt_sdio = { ...@@ -994,6 +1084,12 @@ static const struct sdhci_pci_fixes sdhci_intel_byt_sdio = {
}; };
static const struct sdhci_pci_fixes sdhci_intel_byt_sd = { static const struct sdhci_pci_fixes sdhci_intel_byt_sd = {
#ifdef CONFIG_PM_SLEEP
.resume = byt_resume,
#endif
#ifdef CONFIG_PM
.runtime_resume = byt_runtime_resume,
#endif
.quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC | .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC |
SDHCI_QUIRK_NO_LED, SDHCI_QUIRK_NO_LED,
.quirks2 = SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON | .quirks2 = SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON |
...@@ -1576,6 +1672,8 @@ static const struct pci_device_id pci_ids[] = { ...@@ -1576,6 +1672,8 @@ static const struct pci_device_id pci_ids[] = {
SDHCI_PCI_DEVICE(INTEL, CNPH_SD, intel_byt_sd), SDHCI_PCI_DEVICE(INTEL, CNPH_SD, intel_byt_sd),
SDHCI_PCI_DEVICE(INTEL, ICP_EMMC, intel_glk_emmc), SDHCI_PCI_DEVICE(INTEL, ICP_EMMC, intel_glk_emmc),
SDHCI_PCI_DEVICE(INTEL, ICP_SD, intel_byt_sd), SDHCI_PCI_DEVICE(INTEL, ICP_SD, intel_byt_sd),
SDHCI_PCI_DEVICE(INTEL, CML_EMMC, intel_glk_emmc),
SDHCI_PCI_DEVICE(INTEL, CML_SD, intel_byt_sd),
SDHCI_PCI_DEVICE(O2, 8120, o2), SDHCI_PCI_DEVICE(O2, 8120, o2),
SDHCI_PCI_DEVICE(O2, 8220, o2), SDHCI_PCI_DEVICE(O2, 8220, o2),
SDHCI_PCI_DEVICE(O2, 8221, o2), SDHCI_PCI_DEVICE(O2, 8221, o2),
......
...@@ -50,6 +50,8 @@ ...@@ -50,6 +50,8 @@
#define PCI_DEVICE_ID_INTEL_CNPH_SD 0xa375 #define PCI_DEVICE_ID_INTEL_CNPH_SD 0xa375
#define PCI_DEVICE_ID_INTEL_ICP_EMMC 0x34c4 #define PCI_DEVICE_ID_INTEL_ICP_EMMC 0x34c4
#define PCI_DEVICE_ID_INTEL_ICP_SD 0x34f8 #define PCI_DEVICE_ID_INTEL_ICP_SD 0x34f8
#define PCI_DEVICE_ID_INTEL_CML_EMMC 0x02c4
#define PCI_DEVICE_ID_INTEL_CML_SD 0x02f5
#define PCI_DEVICE_ID_SYSKONNECT_8000 0x8000 #define PCI_DEVICE_ID_SYSKONNECT_8000 0x8000
#define PCI_DEVICE_ID_VIA_95D0 0x95d0 #define PCI_DEVICE_ID_VIA_95D0 0x95d0
......
This diff is collapsed.
This diff is collapsed.
...@@ -560,7 +560,8 @@ struct sdhci_host { ...@@ -560,7 +560,8 @@ struct sdhci_host {
unsigned int desc_sz; /* ADMA descriptor size */ unsigned int desc_sz; /* ADMA descriptor size */
struct tasklet_struct finish_tasklet; /* Tasklet structures */ struct workqueue_struct *complete_wq; /* Request completion wq */
struct work_struct complete_work; /* Request completion work */
struct timer_list timer; /* Timer for timeouts */ struct timer_list timer; /* Timer for timeouts */
struct timer_list data_timer; /* Timer for data timeouts */ struct timer_list data_timer; /* Timer for data timeouts */
...@@ -596,6 +597,7 @@ struct sdhci_host { ...@@ -596,6 +597,7 @@ struct sdhci_host {
#define SDHCI_TUNING_MODE_3 2 #define SDHCI_TUNING_MODE_3 2
/* Delay (ms) between tuning commands */ /* Delay (ms) between tuning commands */
int tuning_delay; int tuning_delay;
int tuning_loop_count;
/* Host SDMA buffer boundary. */ /* Host SDMA buffer boundary. */
u32 sdma_boundary; u32 sdma_boundary;
......
...@@ -158,6 +158,27 @@ static void sdhci_am654_set_power(struct sdhci_host *host, unsigned char mode, ...@@ -158,6 +158,27 @@ static void sdhci_am654_set_power(struct sdhci_host *host, unsigned char mode,
sdhci_set_power_noreg(host, mode, vdd); sdhci_set_power_noreg(host, mode, vdd);
} }
static void sdhci_am654_write_b(struct sdhci_host *host, u8 val, int reg)
{
unsigned char timing = host->mmc->ios.timing;
if (reg == SDHCI_HOST_CONTROL) {
switch (timing) {
/*
* According to the data manual, HISPD bit
* should not be set in these speed modes.
*/
case MMC_TIMING_SD_HS:
case MMC_TIMING_MMC_HS:
case MMC_TIMING_UHS_SDR12:
case MMC_TIMING_UHS_SDR25:
val &= ~SDHCI_CTRL_HISPD;
}
}
writeb(val, host->ioaddr + reg);
}
static struct sdhci_ops sdhci_am654_ops = { static struct sdhci_ops sdhci_am654_ops = {
.get_max_clock = sdhci_pltfm_clk_get_max_clock, .get_max_clock = sdhci_pltfm_clk_get_max_clock,
.get_timeout_clock = sdhci_pltfm_clk_get_max_clock, .get_timeout_clock = sdhci_pltfm_clk_get_max_clock,
...@@ -165,6 +186,7 @@ static struct sdhci_ops sdhci_am654_ops = { ...@@ -165,6 +186,7 @@ static struct sdhci_ops sdhci_am654_ops = {
.set_bus_width = sdhci_set_bus_width, .set_bus_width = sdhci_set_bus_width,
.set_power = sdhci_am654_set_power, .set_power = sdhci_am654_set_power,
.set_clock = sdhci_am654_set_clock, .set_clock = sdhci_am654_set_clock,
.write_b = sdhci_am654_write_b,
.reset = sdhci_reset, .reset = sdhci_reset,
}; };
......
...@@ -4,8 +4,8 @@ ...@@ -4,8 +4,8 @@
* *
* TC6393XB TC6391XB TC6387XB T7L66XB ASIC3 * TC6393XB TC6391XB TC6387XB T7L66XB ASIC3
* *
* Copyright (C) 2015-17 Renesas Electronics Corporation * Copyright (C) 2015-19 Renesas Electronics Corporation
* Copyright (C) 2016-17 Sang Engineering, Wolfram Sang * Copyright (C) 2016-19 Sang Engineering, Wolfram Sang
* Copyright (C) 2016-17 Horms Solutions, Simon Horman * Copyright (C) 2016-17 Horms Solutions, Simon Horman
* Copyright (C) 2007 Ian Molton * Copyright (C) 2007 Ian Molton
* Copyright (C) 2004 Ian Molton * Copyright (C) 2004 Ian Molton
...@@ -105,6 +105,8 @@ ...@@ -105,6 +105,8 @@
TMIO_STAT_CARD_REMOVE | TMIO_STAT_CARD_INSERT) TMIO_STAT_CARD_REMOVE | TMIO_STAT_CARD_INSERT)
#define TMIO_MASK_IRQ (TMIO_MASK_READOP | TMIO_MASK_WRITEOP | TMIO_MASK_CMD) #define TMIO_MASK_IRQ (TMIO_MASK_READOP | TMIO_MASK_WRITEOP | TMIO_MASK_CMD)
#define TMIO_MAX_BLK_SIZE 512
struct tmio_mmc_data; struct tmio_mmc_data;
struct tmio_mmc_host; struct tmio_mmc_host;
......
...@@ -4,8 +4,8 @@ ...@@ -4,8 +4,8 @@
* *
* TC6393XB, TC6391XB, TC6387XB, T7L66XB, ASIC3, SH-Mobile SoCs * TC6393XB, TC6391XB, TC6387XB, T7L66XB, ASIC3, SH-Mobile SoCs
* *
* Copyright (C) 2015-17 Renesas Electronics Corporation * Copyright (C) 2015-19 Renesas Electronics Corporation
* Copyright (C) 2016-17 Sang Engineering, Wolfram Sang * Copyright (C) 2016-19 Sang Engineering, Wolfram Sang
* Copyright (C) 2017 Horms Solutions, Simon Horman * Copyright (C) 2017 Horms Solutions, Simon Horman
* Copyright (C) 2011 Guennadi Liakhovetski * Copyright (C) 2011 Guennadi Liakhovetski
* Copyright (C) 2007 Ian Molton * Copyright (C) 2007 Ian Molton
...@@ -1186,7 +1186,7 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host) ...@@ -1186,7 +1186,7 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host)
mmc->caps |= MMC_CAP_4_BIT_DATA | pdata->capabilities; mmc->caps |= MMC_CAP_4_BIT_DATA | pdata->capabilities;
mmc->caps2 |= pdata->capabilities2; mmc->caps2 |= pdata->capabilities2;
mmc->max_segs = pdata->max_segs ? : 32; mmc->max_segs = pdata->max_segs ? : 32;
mmc->max_blk_size = 512; mmc->max_blk_size = TMIO_MAX_BLK_SIZE;
mmc->max_blk_count = pdata->max_blk_count ? : mmc->max_blk_count = pdata->max_blk_count ? :
(PAGE_SIZE / mmc->max_blk_size) * mmc->max_segs; (PAGE_SIZE / mmc->max_blk_size) * mmc->max_segs;
mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count; mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
......
...@@ -1339,7 +1339,7 @@ static int usdhi6_stop_cmd(struct usdhi6_host *host) ...@@ -1339,7 +1339,7 @@ static int usdhi6_stop_cmd(struct usdhi6_host *host)
host->wait = USDHI6_WAIT_FOR_STOP; host->wait = USDHI6_WAIT_FOR_STOP;
return 0; return 0;
} }
/* Unsupported STOP command */ /* fall through - Unsupported STOP command. */
default: default:
dev_err(mmc_dev(host->mmc), dev_err(mmc_dev(host->mmc),
"unsupported stop CMD%d for CMD%d\n", "unsupported stop CMD%d for CMD%d\n",
...@@ -1687,7 +1687,7 @@ static void usdhi6_timeout_work(struct work_struct *work) ...@@ -1687,7 +1687,7 @@ static void usdhi6_timeout_work(struct work_struct *work)
switch (host->wait) { switch (host->wait) {
default: default:
dev_err(mmc_dev(host->mmc), "Invalid state %u\n", host->wait); dev_err(mmc_dev(host->mmc), "Invalid state %u\n", host->wait);
/* mrq can be NULL in this actually impossible case */ /* fall through - mrq can be NULL, but is impossible. */
case USDHI6_WAIT_FOR_CMD: case USDHI6_WAIT_FOR_CMD:
usdhi6_error_code(host); usdhi6_error_code(host);
if (mrq) if (mrq)
...@@ -1709,10 +1709,7 @@ static void usdhi6_timeout_work(struct work_struct *work) ...@@ -1709,10 +1709,7 @@ static void usdhi6_timeout_work(struct work_struct *work)
host->offset, data->blocks, data->blksz, data->sg_len, host->offset, data->blocks, data->blksz, data->sg_len,
sg_dma_len(sg), sg->offset); sg_dma_len(sg), sg->offset);
usdhi6_sg_unmap(host, true); usdhi6_sg_unmap(host, true);
/* /* fall through - page unmapped in USDHI6_WAIT_FOR_DATA_END. */
* If USDHI6_WAIT_FOR_DATA_END times out, we have already unmapped
* the page
*/
case USDHI6_WAIT_FOR_DATA_END: case USDHI6_WAIT_FOR_DATA_END:
usdhi6_error_code(host); usdhi6_error_code(host);
data->error = -ETIMEDOUT; data->error = -ETIMEDOUT;
......
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
#define AU6601_BASE_CLOCK 31000000 #define AU6601_BASE_CLOCK 31000000
#define AU6601_MIN_CLOCK 150000 #define AU6601_MIN_CLOCK 150000
#define AU6601_MAX_CLOCK 208000000 #define AU6601_MAX_CLOCK 208000000
#define AU6601_MAX_DMA_SEGMENTS 1 #define AU6601_MAX_DMA_SEGMENTS 64
#define AU6601_MAX_PIO_SEGMENTS 1 #define AU6601_MAX_PIO_SEGMENTS 1
#define AU6601_MAX_DMA_BLOCK_SIZE 0x1000 #define AU6601_MAX_DMA_BLOCK_SIZE 0x1000
#define AU6601_MAX_PIO_BLOCK_SIZE 0x200 #define AU6601_MAX_PIO_BLOCK_SIZE 0x200
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment