diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-12-08 18:42:44 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-12-08 18:42:44 -0800 |
commit | f2fb38049c724558c590c31e57627f6ba8d48a5b (patch) | |
tree | 51ff06495a51de92c24d1b9ec7759d61e8560928 /drivers/mmc/host/dw_mmc-exynos.c | |
parent | b2776bf7149bddd1f4161f14f79520f17fc1d71d (diff) | |
parent | 33d73935e4abb2c75f263dd31a314db09ccf41be (diff) |
Merge tag 'mmc-v3.19-1' of git://git.linaro.org/people/ulf.hansson/mmc
Pull MMC updates from Ulf Hansson:
"MMC core:
- Consolidation and cleanups.
- Some improvements regarding error handling.
- Increase maximum amount of block devices.
- Use correct OCR mask for SDIO when restoring power.
- Fix prepared requests while doing BKOPS.
- Convert to modern PM ops.
- Add mmc_send_tuning() API and convert some hosts to use it.
MMC host:
- toshsd: New Toshiba PCI SD controller driver.
- sdhci: 64-bit ADMA support.
- sdhci: Some regulator fixes.
- sdhci: HS400 support.
- sdhci: Various fixes cleanups.
- atmel-mci: Modernization and cleanups.
- atmel-mci: Runtime PM support.
- omap_hsmmc: Modernization and cleanups.
- omap_hsmmc: Fix UHS card with DDR50 support.
- dw_mmc: Support for ARM64 and Exynos 7 variant.
- dw_mmc: Add support for IMG Pistachio variant.
- dw_mmc: Various fixes and cleanups.
- mvsdio: DMA fixes.
- mxs-mmc: Modernization and cleanups.
- mxcmmc: Various fixes"
* tag 'mmc-v3.19-1' of git://git.linaro.org/people/ulf.hansson/mmc: (126 commits)
mmc: sdhci-msm: Convert to mmc_send_tuning()
mmc: sdhci-esdhc-imx: Convert to mmc_send_tuning()
mmc: core: Let mmc_send_tuning() to take struct mmc_host* as parameter
mmc: queue: Improve error handling during allocation of bounce buffers
mmc: sdhci-acpi: Add two host capabilities for Intel
mmc: sdhci-pci: Add two host capabilities for BYT
mmc: sdhci-acpi: Add SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC
mmc: sdhci-pci: Add SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC to BYT
mmc: atmel-mci: use probe deferring if dma controller is not ready yet
mmc: atmel-mci: stop using specific initcall
mmc: atmel-mci: remove __init/__exit attributes
mmc: atmel-mci: remove useless DMA stuff for non-dt devices
mmc: omap_hsmmc: Fix UHS card with DDR50 support
mmc: core: add core-level function for sending tuning commands
mmc: core: hold SD Clock before CMD11 during Signal
mmc: mxs-mmc: Check for clk_prepare_enable() error
mmc: mxs-mmc: Propagate the real error
mmc: mxs-mmc: No need to do NULL check on 'iores'
mmc: dw_mmc: Add support for IMG Pistachio
mmc: mxs-mmc: Simplify PM hooks
...
Diffstat (limited to 'drivers/mmc/host/dw_mmc-exynos.c')
-rw-r--r-- | drivers/mmc/host/dw_mmc-exynos.c | 91 |
1 files changed, 78 insertions, 13 deletions
diff --git a/drivers/mmc/host/dw_mmc-exynos.c b/drivers/mmc/host/dw_mmc-exynos.c index 0fbc53ac7eae..509365cb22c6 100644 --- a/drivers/mmc/host/dw_mmc-exynos.c +++ b/drivers/mmc/host/dw_mmc-exynos.c @@ -25,6 +25,7 @@ #define NUM_PINS(x) (x + 2) #define SDMMC_CLKSEL 0x09C +#define SDMMC_CLKSEL64 0x0A8 #define SDMMC_CLKSEL_CCLK_SAMPLE(x) (((x) & 7) << 0) #define SDMMC_CLKSEL_CCLK_DRIVE(x) (((x) & 7) << 16) #define SDMMC_CLKSEL_CCLK_DIVIDER(x) (((x) & 7) << 24) @@ -65,6 +66,8 @@ enum dw_mci_exynos_type { DW_MCI_TYPE_EXYNOS5250, DW_MCI_TYPE_EXYNOS5420, DW_MCI_TYPE_EXYNOS5420_SMU, + DW_MCI_TYPE_EXYNOS7, + DW_MCI_TYPE_EXYNOS7_SMU, }; /* Exynos implementation specific driver private data */ @@ -95,6 +98,12 @@ static struct dw_mci_exynos_compatible { }, { .compatible = "samsung,exynos5420-dw-mshc-smu", .ctrl_type = DW_MCI_TYPE_EXYNOS5420_SMU, + }, { + .compatible = "samsung,exynos7-dw-mshc", + .ctrl_type = DW_MCI_TYPE_EXYNOS7, + }, { + .compatible = "samsung,exynos7-dw-mshc-smu", + .ctrl_type = DW_MCI_TYPE_EXYNOS7_SMU, }, }; @@ -102,7 +111,8 @@ static int dw_mci_exynos_priv_init(struct dw_mci *host) { struct dw_mci_exynos_priv_data *priv = host->priv; - if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS5420_SMU) { + if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS5420_SMU || + priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU) { mci_writel(host, MPSBEGIN0, 0); mci_writel(host, MPSEND0, DWMCI_BLOCK_NUM); mci_writel(host, MPSCTRL0, DWMCI_MPSCTRL_SECURE_WRITE_BIT | @@ -153,11 +163,22 @@ static int dw_mci_exynos_resume(struct device *dev) static int dw_mci_exynos_resume_noirq(struct device *dev) { struct dw_mci *host = dev_get_drvdata(dev); + struct dw_mci_exynos_priv_data *priv = host->priv; u32 clksel; - clksel = mci_readl(host, CLKSEL); - if (clksel & SDMMC_CLKSEL_WAKEUP_INT) - mci_writel(host, CLKSEL, clksel); + if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || + priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU) + clksel = mci_readl(host, CLKSEL64); + else + clksel = mci_readl(host, CLKSEL); + + if (clksel & SDMMC_CLKSEL_WAKEUP_INT) { + if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || + priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU) + mci_writel(host, CLKSEL64, clksel); + else + mci_writel(host, CLKSEL, clksel); + } return 0; } @@ -169,6 +190,7 @@ static int dw_mci_exynos_resume_noirq(struct device *dev) static void dw_mci_exynos_prepare_command(struct dw_mci *host, u32 *cmdr) { + struct dw_mci_exynos_priv_data *priv = host->priv; /* * Exynos4412 and Exynos5250 extends the use of CMD register with the * use of bit 29 (which is reserved on standard MSHC controllers) for @@ -176,8 +198,14 @@ static void dw_mci_exynos_prepare_command(struct dw_mci *host, u32 *cmdr) * HOLD register should be bypassed in case there is no phase shift * applied on CMD/DATA that is sent to the card. */ - if (SDMMC_CLKSEL_GET_DRV_WD3(mci_readl(host, CLKSEL))) - *cmdr |= SDMMC_CMD_USE_HOLD_REG; + if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || + priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU) { + if (SDMMC_CLKSEL_GET_DRV_WD3(mci_readl(host, CLKSEL64))) + *cmdr |= SDMMC_CMD_USE_HOLD_REG; + } else { + if (SDMMC_CLKSEL_GET_DRV_WD3(mci_readl(host, CLKSEL))) + *cmdr |= SDMMC_CMD_USE_HOLD_REG; + } } static void dw_mci_exynos_set_ios(struct dw_mci *host, struct mmc_ios *ios) @@ -188,12 +216,20 @@ static void dw_mci_exynos_set_ios(struct dw_mci *host, struct mmc_ios *ios) u8 div = priv->ciu_div + 1; if (ios->timing == MMC_TIMING_MMC_DDR52) { - mci_writel(host, CLKSEL, priv->ddr_timing); + if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || + priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU) + mci_writel(host, CLKSEL64, priv->ddr_timing); + else + mci_writel(host, CLKSEL, priv->ddr_timing); /* Should be double rate for DDR mode */ if (ios->bus_width == MMC_BUS_WIDTH_8) wanted <<= 1; } else { - mci_writel(host, CLKSEL, priv->sdr_timing); + if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || + priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU) + mci_writel(host, CLKSEL64, priv->sdr_timing); + else + mci_writel(host, CLKSEL, priv->sdr_timing); } /* Don't care if wanted clock is zero */ @@ -265,26 +301,51 @@ static int dw_mci_exynos_parse_dt(struct dw_mci *host) static inline u8 dw_mci_exynos_get_clksmpl(struct dw_mci *host) { - return SDMMC_CLKSEL_CCLK_SAMPLE(mci_readl(host, CLKSEL)); + struct dw_mci_exynos_priv_data *priv = host->priv; + + if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || + priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU) + return SDMMC_CLKSEL_CCLK_SAMPLE(mci_readl(host, CLKSEL64)); + else + return SDMMC_CLKSEL_CCLK_SAMPLE(mci_readl(host, CLKSEL)); } static inline void dw_mci_exynos_set_clksmpl(struct dw_mci *host, u8 sample) { u32 clksel; - clksel = mci_readl(host, CLKSEL); + struct dw_mci_exynos_priv_data *priv = host->priv; + + if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || + priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU) + clksel = mci_readl(host, CLKSEL64); + else + clksel = mci_readl(host, CLKSEL); clksel = (clksel & ~0x7) | SDMMC_CLKSEL_CCLK_SAMPLE(sample); - mci_writel(host, CLKSEL, clksel); + if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || + priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU) + mci_writel(host, CLKSEL64, clksel); + else + mci_writel(host, CLKSEL, clksel); } static inline u8 dw_mci_exynos_move_next_clksmpl(struct dw_mci *host) { + struct dw_mci_exynos_priv_data *priv = host->priv; u32 clksel; u8 sample; - clksel = mci_readl(host, CLKSEL); + if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || + priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU) + clksel = mci_readl(host, CLKSEL64); + else + clksel = mci_readl(host, CLKSEL); sample = (clksel + 1) & 0x7; clksel = (clksel & ~0x7) | sample; - mci_writel(host, CLKSEL, clksel); + if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || + priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU) + mci_writel(host, CLKSEL64, clksel); + else + mci_writel(host, CLKSEL, clksel); return sample; } @@ -411,6 +472,10 @@ static const struct of_device_id dw_mci_exynos_match[] = { .data = &exynos_drv_data, }, { .compatible = "samsung,exynos5420-dw-mshc-smu", .data = &exynos_drv_data, }, + { .compatible = "samsung,exynos7-dw-mshc", + .data = &exynos_drv_data, }, + { .compatible = "samsung,exynos7-dw-mshc-smu", + .data = &exynos_drv_data, }, {}, }; MODULE_DEVICE_TABLE(of, dw_mci_exynos_match); |