1c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 2ff6af28fSMasahiro Yamada /* 3ff6af28fSMasahiro Yamada * Copyright (C) 2016 Socionext Inc. 4ff6af28fSMasahiro Yamada * Author: Masahiro Yamada <yamada.masahiro@socionext.com> 5ff6af28fSMasahiro Yamada */ 6ff6af28fSMasahiro Yamada 7f02cebdfSMasahiro Yamada #include <linux/bitfield.h> 8cd7a0d21SMasahiro Yamada #include <linux/bits.h> 9ff6af28fSMasahiro Yamada #include <linux/iopoll.h> 10ff6af28fSMasahiro Yamada #include <linux/module.h> 11ff6af28fSMasahiro Yamada #include <linux/mmc/host.h> 12963836adSUlf Hansson #include <linux/mmc/mmc.h> 13a89c472dSPiotr Sroka #include <linux/of.h> 1418b587b4SMasahiro Yamada #include <linux/of_device.h> 15ff6af28fSMasahiro Yamada 16ff6af28fSMasahiro Yamada #include "sdhci-pltfm.h" 17ff6af28fSMasahiro Yamada 18ff6af28fSMasahiro Yamada /* HRS - Host Register Set (specific to Cadence) */ 19ff6af28fSMasahiro Yamada #define SDHCI_CDNS_HRS04 0x10 /* PHY access port */ 20ff6af28fSMasahiro Yamada #define SDHCI_CDNS_HRS04_ACK BIT(26) 21ff6af28fSMasahiro Yamada #define SDHCI_CDNS_HRS04_RD BIT(25) 22ff6af28fSMasahiro Yamada #define SDHCI_CDNS_HRS04_WR BIT(24) 23f02cebdfSMasahiro Yamada #define SDHCI_CDNS_HRS04_RDATA GENMASK(23, 16) 24f02cebdfSMasahiro Yamada #define SDHCI_CDNS_HRS04_WDATA GENMASK(15, 8) 25f02cebdfSMasahiro Yamada #define SDHCI_CDNS_HRS04_ADDR GENMASK(5, 0) 26ff6af28fSMasahiro Yamada 27ff6af28fSMasahiro Yamada #define SDHCI_CDNS_HRS06 0x18 /* eMMC control */ 28ff6af28fSMasahiro Yamada #define SDHCI_CDNS_HRS06_TUNE_UP BIT(15) 29f02cebdfSMasahiro Yamada #define SDHCI_CDNS_HRS06_TUNE GENMASK(13, 8) 30f02cebdfSMasahiro Yamada #define SDHCI_CDNS_HRS06_MODE GENMASK(2, 0) 31ff6af28fSMasahiro Yamada #define SDHCI_CDNS_HRS06_MODE_SD 0x0 32ff6af28fSMasahiro Yamada #define SDHCI_CDNS_HRS06_MODE_MMC_SDR 0x2 33ff6af28fSMasahiro Yamada #define SDHCI_CDNS_HRS06_MODE_MMC_DDR 0x3 34ff6af28fSMasahiro Yamada #define SDHCI_CDNS_HRS06_MODE_MMC_HS200 0x4 35ff6af28fSMasahiro Yamada #define SDHCI_CDNS_HRS06_MODE_MMC_HS400 0x5 36d12990f9SPiotr Sroka #define SDHCI_CDNS_HRS06_MODE_MMC_HS400ES 0x6 37ff6af28fSMasahiro Yamada 38ff6af28fSMasahiro Yamada /* SRS - Slot Register Set (SDHCI-compatible) */ 39ff6af28fSMasahiro Yamada #define SDHCI_CDNS_SRS_BASE 0x200 40ff6af28fSMasahiro Yamada 41ff6af28fSMasahiro Yamada /* PHY */ 42ff6af28fSMasahiro Yamada #define SDHCI_CDNS_PHY_DLY_SD_HS 0x00 43ff6af28fSMasahiro Yamada #define SDHCI_CDNS_PHY_DLY_SD_DEFAULT 0x01 44ff6af28fSMasahiro Yamada #define SDHCI_CDNS_PHY_DLY_UHS_SDR12 0x02 45ff6af28fSMasahiro Yamada #define SDHCI_CDNS_PHY_DLY_UHS_SDR25 0x03 46ff6af28fSMasahiro Yamada #define SDHCI_CDNS_PHY_DLY_UHS_SDR50 0x04 47ff6af28fSMasahiro Yamada #define SDHCI_CDNS_PHY_DLY_UHS_DDR50 0x05 48ff6af28fSMasahiro Yamada #define SDHCI_CDNS_PHY_DLY_EMMC_LEGACY 0x06 49ff6af28fSMasahiro Yamada #define SDHCI_CDNS_PHY_DLY_EMMC_SDR 0x07 50ff6af28fSMasahiro Yamada #define SDHCI_CDNS_PHY_DLY_EMMC_DDR 0x08 51a89c472dSPiotr Sroka #define SDHCI_CDNS_PHY_DLY_SDCLK 0x0b 52a89c472dSPiotr Sroka #define SDHCI_CDNS_PHY_DLY_HSMMC 0x0c 53a89c472dSPiotr Sroka #define SDHCI_CDNS_PHY_DLY_STROBE 0x0d 54ff6af28fSMasahiro Yamada 55ff6af28fSMasahiro Yamada /* 56ff6af28fSMasahiro Yamada * The tuned val register is 6 bit-wide, but not the whole of the range is 57ff6af28fSMasahiro Yamada * available. The range 0-42 seems to be available (then 43 wraps around to 0) 58ff6af28fSMasahiro Yamada * but I am not quite sure if it is official. Use only 0 to 39 for safety. 59ff6af28fSMasahiro Yamada */ 60ff6af28fSMasahiro Yamada #define SDHCI_CDNS_MAX_TUNING_LOOP 40 61ff6af28fSMasahiro Yamada 62a232a8f2SMasahiro Yamada struct sdhci_cdns_phy_param { 63a232a8f2SMasahiro Yamada u8 addr; 64a232a8f2SMasahiro Yamada u8 data; 65a232a8f2SMasahiro Yamada }; 66a232a8f2SMasahiro Yamada 67ff6af28fSMasahiro Yamada struct sdhci_cdns_priv { 68ff6af28fSMasahiro Yamada void __iomem *hrs_addr; 69d12990f9SPiotr Sroka bool enhanced_strobe; 70a232a8f2SMasahiro Yamada unsigned int nr_phy_params; 711a91a36aSGustavo A. R. Silva struct sdhci_cdns_phy_param phy_params[]; 72ff6af28fSMasahiro Yamada }; 73ff6af28fSMasahiro Yamada 74a89c472dSPiotr Sroka struct sdhci_cdns_phy_cfg { 75a89c472dSPiotr Sroka const char *property; 76a89c472dSPiotr Sroka u8 addr; 77a89c472dSPiotr Sroka }; 78a89c472dSPiotr Sroka 79a89c472dSPiotr Sroka static const struct sdhci_cdns_phy_cfg sdhci_cdns_phy_cfgs[] = { 80a89c472dSPiotr Sroka { "cdns,phy-input-delay-sd-highspeed", SDHCI_CDNS_PHY_DLY_SD_HS, }, 81a89c472dSPiotr Sroka { "cdns,phy-input-delay-legacy", SDHCI_CDNS_PHY_DLY_SD_DEFAULT, }, 82a89c472dSPiotr Sroka { "cdns,phy-input-delay-sd-uhs-sdr12", SDHCI_CDNS_PHY_DLY_UHS_SDR12, }, 83a89c472dSPiotr Sroka { "cdns,phy-input-delay-sd-uhs-sdr25", SDHCI_CDNS_PHY_DLY_UHS_SDR25, }, 84a89c472dSPiotr Sroka { "cdns,phy-input-delay-sd-uhs-sdr50", SDHCI_CDNS_PHY_DLY_UHS_SDR50, }, 85a89c472dSPiotr Sroka { "cdns,phy-input-delay-sd-uhs-ddr50", SDHCI_CDNS_PHY_DLY_UHS_DDR50, }, 86a89c472dSPiotr Sroka { "cdns,phy-input-delay-mmc-highspeed", SDHCI_CDNS_PHY_DLY_EMMC_SDR, }, 87a89c472dSPiotr Sroka { "cdns,phy-input-delay-mmc-ddr", SDHCI_CDNS_PHY_DLY_EMMC_DDR, }, 88a89c472dSPiotr Sroka { "cdns,phy-dll-delay-sdclk", SDHCI_CDNS_PHY_DLY_SDCLK, }, 89a89c472dSPiotr Sroka { "cdns,phy-dll-delay-sdclk-hsmmc", SDHCI_CDNS_PHY_DLY_HSMMC, }, 90a89c472dSPiotr Sroka { "cdns,phy-dll-delay-strobe", SDHCI_CDNS_PHY_DLY_STROBE, }, 91a89c472dSPiotr Sroka }; 92a89c472dSPiotr Sroka 93a0f82432SPiotr Sroka static int sdhci_cdns_write_phy_reg(struct sdhci_cdns_priv *priv, 94ff6af28fSMasahiro Yamada u8 addr, u8 data) 95ff6af28fSMasahiro Yamada { 96ff6af28fSMasahiro Yamada void __iomem *reg = priv->hrs_addr + SDHCI_CDNS_HRS04; 97ff6af28fSMasahiro Yamada u32 tmp; 98a0f82432SPiotr Sroka int ret; 99ff6af28fSMasahiro Yamada 100f02cebdfSMasahiro Yamada tmp = FIELD_PREP(SDHCI_CDNS_HRS04_WDATA, data) | 101f02cebdfSMasahiro Yamada FIELD_PREP(SDHCI_CDNS_HRS04_ADDR, addr); 102ff6af28fSMasahiro Yamada writel(tmp, reg); 103ff6af28fSMasahiro Yamada 104ff6af28fSMasahiro Yamada tmp |= SDHCI_CDNS_HRS04_WR; 105ff6af28fSMasahiro Yamada writel(tmp, reg); 106ff6af28fSMasahiro Yamada 107a0f82432SPiotr Sroka ret = readl_poll_timeout(reg, tmp, tmp & SDHCI_CDNS_HRS04_ACK, 0, 10); 108a0f82432SPiotr Sroka if (ret) 109a0f82432SPiotr Sroka return ret; 110a0f82432SPiotr Sroka 111ff6af28fSMasahiro Yamada tmp &= ~SDHCI_CDNS_HRS04_WR; 112ff6af28fSMasahiro Yamada writel(tmp, reg); 113a0f82432SPiotr Sroka 114a0f82432SPiotr Sroka return 0; 115ff6af28fSMasahiro Yamada } 116ff6af28fSMasahiro Yamada 117a232a8f2SMasahiro Yamada static unsigned int sdhci_cdns_phy_param_count(struct device_node *np) 118a232a8f2SMasahiro Yamada { 119a232a8f2SMasahiro Yamada unsigned int count = 0; 120a232a8f2SMasahiro Yamada int i; 121a232a8f2SMasahiro Yamada 122a232a8f2SMasahiro Yamada for (i = 0; i < ARRAY_SIZE(sdhci_cdns_phy_cfgs); i++) 123a232a8f2SMasahiro Yamada if (of_property_read_bool(np, sdhci_cdns_phy_cfgs[i].property)) 124a232a8f2SMasahiro Yamada count++; 125a232a8f2SMasahiro Yamada 126a232a8f2SMasahiro Yamada return count; 127a232a8f2SMasahiro Yamada } 128a232a8f2SMasahiro Yamada 129a232a8f2SMasahiro Yamada static void sdhci_cdns_phy_param_parse(struct device_node *np, 130a89c472dSPiotr Sroka struct sdhci_cdns_priv *priv) 131ff6af28fSMasahiro Yamada { 132a232a8f2SMasahiro Yamada struct sdhci_cdns_phy_param *p = priv->phy_params; 133a89c472dSPiotr Sroka u32 val; 134a89c472dSPiotr Sroka int ret, i; 135a89c472dSPiotr Sroka 136a89c472dSPiotr Sroka for (i = 0; i < ARRAY_SIZE(sdhci_cdns_phy_cfgs); i++) { 137a89c472dSPiotr Sroka ret = of_property_read_u32(np, sdhci_cdns_phy_cfgs[i].property, 138a89c472dSPiotr Sroka &val); 139a89c472dSPiotr Sroka if (ret) 140a89c472dSPiotr Sroka continue; 141a89c472dSPiotr Sroka 142a232a8f2SMasahiro Yamada p->addr = sdhci_cdns_phy_cfgs[i].addr; 143a232a8f2SMasahiro Yamada p->data = val; 144a232a8f2SMasahiro Yamada p++; 145a232a8f2SMasahiro Yamada } 146a232a8f2SMasahiro Yamada } 147a232a8f2SMasahiro Yamada 148a232a8f2SMasahiro Yamada static int sdhci_cdns_phy_init(struct sdhci_cdns_priv *priv) 149a232a8f2SMasahiro Yamada { 150a232a8f2SMasahiro Yamada int ret, i; 151a232a8f2SMasahiro Yamada 152a232a8f2SMasahiro Yamada for (i = 0; i < priv->nr_phy_params; i++) { 153a232a8f2SMasahiro Yamada ret = sdhci_cdns_write_phy_reg(priv, priv->phy_params[i].addr, 154a232a8f2SMasahiro Yamada priv->phy_params[i].data); 155a89c472dSPiotr Sroka if (ret) 156a89c472dSPiotr Sroka return ret; 157a89c472dSPiotr Sroka } 158a89c472dSPiotr Sroka 159a89c472dSPiotr Sroka return 0; 160ff6af28fSMasahiro Yamada } 161ff6af28fSMasahiro Yamada 1621d45a3f4SMasahiro Yamada static void *sdhci_cdns_priv(struct sdhci_host *host) 163ff6af28fSMasahiro Yamada { 164ff6af28fSMasahiro Yamada struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 165ff6af28fSMasahiro Yamada 166ff6af28fSMasahiro Yamada return sdhci_pltfm_priv(pltfm_host); 167ff6af28fSMasahiro Yamada } 168ff6af28fSMasahiro Yamada 169ff6af28fSMasahiro Yamada static unsigned int sdhci_cdns_get_timeout_clock(struct sdhci_host *host) 170ff6af28fSMasahiro Yamada { 171ff6af28fSMasahiro Yamada /* 172ff6af28fSMasahiro Yamada * Cadence's spec says the Timeout Clock Frequency is the same as the 1738cc35289SShawn Lin * Base Clock Frequency. 174ff6af28fSMasahiro Yamada */ 1758cc35289SShawn Lin return host->max_clk; 176ff6af28fSMasahiro Yamada } 177ff6af28fSMasahiro Yamada 178d12990f9SPiotr Sroka static void sdhci_cdns_set_emmc_mode(struct sdhci_cdns_priv *priv, u32 mode) 179d12990f9SPiotr Sroka { 180d12990f9SPiotr Sroka u32 tmp; 181d12990f9SPiotr Sroka 182d12990f9SPiotr Sroka /* The speed mode for eMMC is selected by HRS06 register */ 183d12990f9SPiotr Sroka tmp = readl(priv->hrs_addr + SDHCI_CDNS_HRS06); 184f02cebdfSMasahiro Yamada tmp &= ~SDHCI_CDNS_HRS06_MODE; 185f02cebdfSMasahiro Yamada tmp |= FIELD_PREP(SDHCI_CDNS_HRS06_MODE, mode); 186d12990f9SPiotr Sroka writel(tmp, priv->hrs_addr + SDHCI_CDNS_HRS06); 187d12990f9SPiotr Sroka } 188d12990f9SPiotr Sroka 189d12990f9SPiotr Sroka static u32 sdhci_cdns_get_emmc_mode(struct sdhci_cdns_priv *priv) 190d12990f9SPiotr Sroka { 191d12990f9SPiotr Sroka u32 tmp; 192d12990f9SPiotr Sroka 193d12990f9SPiotr Sroka tmp = readl(priv->hrs_addr + SDHCI_CDNS_HRS06); 194f02cebdfSMasahiro Yamada return FIELD_GET(SDHCI_CDNS_HRS06_MODE, tmp); 195d12990f9SPiotr Sroka } 196d12990f9SPiotr Sroka 197ff6af28fSMasahiro Yamada static void sdhci_cdns_set_uhs_signaling(struct sdhci_host *host, 198ff6af28fSMasahiro Yamada unsigned int timing) 199ff6af28fSMasahiro Yamada { 200ff6af28fSMasahiro Yamada struct sdhci_cdns_priv *priv = sdhci_cdns_priv(host); 201d12990f9SPiotr Sroka u32 mode; 202ff6af28fSMasahiro Yamada 203ff6af28fSMasahiro Yamada switch (timing) { 204ff6af28fSMasahiro Yamada case MMC_TIMING_MMC_HS: 205ff6af28fSMasahiro Yamada mode = SDHCI_CDNS_HRS06_MODE_MMC_SDR; 206ff6af28fSMasahiro Yamada break; 207ff6af28fSMasahiro Yamada case MMC_TIMING_MMC_DDR52: 208ff6af28fSMasahiro Yamada mode = SDHCI_CDNS_HRS06_MODE_MMC_DDR; 209ff6af28fSMasahiro Yamada break; 210ff6af28fSMasahiro Yamada case MMC_TIMING_MMC_HS200: 211ff6af28fSMasahiro Yamada mode = SDHCI_CDNS_HRS06_MODE_MMC_HS200; 212ff6af28fSMasahiro Yamada break; 213ff6af28fSMasahiro Yamada case MMC_TIMING_MMC_HS400: 214d12990f9SPiotr Sroka if (priv->enhanced_strobe) 215d12990f9SPiotr Sroka mode = SDHCI_CDNS_HRS06_MODE_MMC_HS400ES; 216d12990f9SPiotr Sroka else 217ff6af28fSMasahiro Yamada mode = SDHCI_CDNS_HRS06_MODE_MMC_HS400; 218ff6af28fSMasahiro Yamada break; 219ff6af28fSMasahiro Yamada default: 220ff6af28fSMasahiro Yamada mode = SDHCI_CDNS_HRS06_MODE_SD; 221ff6af28fSMasahiro Yamada break; 222ff6af28fSMasahiro Yamada } 223ff6af28fSMasahiro Yamada 224d12990f9SPiotr Sroka sdhci_cdns_set_emmc_mode(priv, mode); 225ff6af28fSMasahiro Yamada 226ff6af28fSMasahiro Yamada /* For SD, fall back to the default handler */ 227ff6af28fSMasahiro Yamada if (mode == SDHCI_CDNS_HRS06_MODE_SD) 228ff6af28fSMasahiro Yamada sdhci_set_uhs_signaling(host, timing); 229ff6af28fSMasahiro Yamada } 230ff6af28fSMasahiro Yamada 231ff6af28fSMasahiro Yamada static const struct sdhci_ops sdhci_cdns_ops = { 232ff6af28fSMasahiro Yamada .set_clock = sdhci_set_clock, 233ff6af28fSMasahiro Yamada .get_timeout_clock = sdhci_cdns_get_timeout_clock, 234ff6af28fSMasahiro Yamada .set_bus_width = sdhci_set_bus_width, 235ff6af28fSMasahiro Yamada .reset = sdhci_reset, 236ff6af28fSMasahiro Yamada .set_uhs_signaling = sdhci_cdns_set_uhs_signaling, 237ff6af28fSMasahiro Yamada }; 238ff6af28fSMasahiro Yamada 23918b587b4SMasahiro Yamada static const struct sdhci_pltfm_data sdhci_cdns_uniphier_pltfm_data = { 24018b587b4SMasahiro Yamada .ops = &sdhci_cdns_ops, 24118b587b4SMasahiro Yamada .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN, 24218b587b4SMasahiro Yamada }; 24318b587b4SMasahiro Yamada 244ff6af28fSMasahiro Yamada static const struct sdhci_pltfm_data sdhci_cdns_pltfm_data = { 245ff6af28fSMasahiro Yamada .ops = &sdhci_cdns_ops, 246ff6af28fSMasahiro Yamada }; 247ff6af28fSMasahiro Yamada 248ff6af28fSMasahiro Yamada static int sdhci_cdns_set_tune_val(struct sdhci_host *host, unsigned int val) 249ff6af28fSMasahiro Yamada { 250ff6af28fSMasahiro Yamada struct sdhci_cdns_priv *priv = sdhci_cdns_priv(host); 251ff6af28fSMasahiro Yamada void __iomem *reg = priv->hrs_addr + SDHCI_CDNS_HRS06; 252ff6af28fSMasahiro Yamada u32 tmp; 253ef6b7567SMasahiro Yamada int i, ret; 254ff6af28fSMasahiro Yamada 255f02cebdfSMasahiro Yamada if (WARN_ON(!FIELD_FIT(SDHCI_CDNS_HRS06_TUNE, val))) 256ff6af28fSMasahiro Yamada return -EINVAL; 257ff6af28fSMasahiro Yamada 258ff6af28fSMasahiro Yamada tmp = readl(reg); 259f02cebdfSMasahiro Yamada tmp &= ~SDHCI_CDNS_HRS06_TUNE; 260f02cebdfSMasahiro Yamada tmp |= FIELD_PREP(SDHCI_CDNS_HRS06_TUNE, val); 261ef6b7567SMasahiro Yamada 262ef6b7567SMasahiro Yamada /* 263ef6b7567SMasahiro Yamada * Workaround for IP errata: 264ef6b7567SMasahiro Yamada * The IP6116 SD/eMMC PHY design has a timing issue on receive data 265ef6b7567SMasahiro Yamada * path. Send tune request twice. 266ef6b7567SMasahiro Yamada */ 267ef6b7567SMasahiro Yamada for (i = 0; i < 2; i++) { 268ff6af28fSMasahiro Yamada tmp |= SDHCI_CDNS_HRS06_TUNE_UP; 269ff6af28fSMasahiro Yamada writel(tmp, reg); 270ff6af28fSMasahiro Yamada 271ef6b7567SMasahiro Yamada ret = readl_poll_timeout(reg, tmp, 272ef6b7567SMasahiro Yamada !(tmp & SDHCI_CDNS_HRS06_TUNE_UP), 273ff6af28fSMasahiro Yamada 0, 1); 2743f1109d1SGustavo A. R. Silva if (ret) 275ef6b7567SMasahiro Yamada return ret; 276ef6b7567SMasahiro Yamada } 277ef6b7567SMasahiro Yamada 278ef6b7567SMasahiro Yamada return 0; 279ff6af28fSMasahiro Yamada } 280ff6af28fSMasahiro Yamada 281ff6af28fSMasahiro Yamada static int sdhci_cdns_execute_tuning(struct mmc_host *mmc, u32 opcode) 282ff6af28fSMasahiro Yamada { 283ff6af28fSMasahiro Yamada struct sdhci_host *host = mmc_priv(mmc); 284ff6af28fSMasahiro Yamada int cur_streak = 0; 285ff6af28fSMasahiro Yamada int max_streak = 0; 286ff6af28fSMasahiro Yamada int end_of_streak = 0; 287ff6af28fSMasahiro Yamada int i; 288ff6af28fSMasahiro Yamada 289ff6af28fSMasahiro Yamada /* 290ff6af28fSMasahiro Yamada * This handler only implements the eMMC tuning that is specific to 291ff6af28fSMasahiro Yamada * this controller. Fall back to the standard method for SD timing. 292ff6af28fSMasahiro Yamada */ 293ff6af28fSMasahiro Yamada if (host->timing != MMC_TIMING_MMC_HS200) 294ff6af28fSMasahiro Yamada return sdhci_execute_tuning(mmc, opcode); 295ff6af28fSMasahiro Yamada 296ff6af28fSMasahiro Yamada if (WARN_ON(opcode != MMC_SEND_TUNING_BLOCK_HS200)) 297ff6af28fSMasahiro Yamada return -EINVAL; 298ff6af28fSMasahiro Yamada 299ff6af28fSMasahiro Yamada for (i = 0; i < SDHCI_CDNS_MAX_TUNING_LOOP; i++) { 300ff6af28fSMasahiro Yamada if (sdhci_cdns_set_tune_val(host, i) || 301ff6af28fSMasahiro Yamada mmc_send_tuning(host->mmc, opcode, NULL)) { /* bad */ 302ff6af28fSMasahiro Yamada cur_streak = 0; 303ff6af28fSMasahiro Yamada } else { /* good */ 304ff6af28fSMasahiro Yamada cur_streak++; 305ff6af28fSMasahiro Yamada if (cur_streak > max_streak) { 306ff6af28fSMasahiro Yamada max_streak = cur_streak; 307ff6af28fSMasahiro Yamada end_of_streak = i; 308ff6af28fSMasahiro Yamada } 309ff6af28fSMasahiro Yamada } 310ff6af28fSMasahiro Yamada } 311ff6af28fSMasahiro Yamada 312ff6af28fSMasahiro Yamada if (!max_streak) { 313ff6af28fSMasahiro Yamada dev_err(mmc_dev(host->mmc), "no tuning point found\n"); 314ff6af28fSMasahiro Yamada return -EIO; 315ff6af28fSMasahiro Yamada } 316ff6af28fSMasahiro Yamada 317ff6af28fSMasahiro Yamada return sdhci_cdns_set_tune_val(host, end_of_streak - max_streak / 2); 318ff6af28fSMasahiro Yamada } 319ff6af28fSMasahiro Yamada 320d12990f9SPiotr Sroka static void sdhci_cdns_hs400_enhanced_strobe(struct mmc_host *mmc, 321d12990f9SPiotr Sroka struct mmc_ios *ios) 322d12990f9SPiotr Sroka { 323d12990f9SPiotr Sroka struct sdhci_host *host = mmc_priv(mmc); 324d12990f9SPiotr Sroka struct sdhci_cdns_priv *priv = sdhci_cdns_priv(host); 325d12990f9SPiotr Sroka u32 mode; 326d12990f9SPiotr Sroka 327d12990f9SPiotr Sroka priv->enhanced_strobe = ios->enhanced_strobe; 328d12990f9SPiotr Sroka 329d12990f9SPiotr Sroka mode = sdhci_cdns_get_emmc_mode(priv); 330d12990f9SPiotr Sroka 331d12990f9SPiotr Sroka if (mode == SDHCI_CDNS_HRS06_MODE_MMC_HS400 && ios->enhanced_strobe) 332d12990f9SPiotr Sroka sdhci_cdns_set_emmc_mode(priv, 333d12990f9SPiotr Sroka SDHCI_CDNS_HRS06_MODE_MMC_HS400ES); 334d12990f9SPiotr Sroka 335d12990f9SPiotr Sroka if (mode == SDHCI_CDNS_HRS06_MODE_MMC_HS400ES && !ios->enhanced_strobe) 336d12990f9SPiotr Sroka sdhci_cdns_set_emmc_mode(priv, 337d12990f9SPiotr Sroka SDHCI_CDNS_HRS06_MODE_MMC_HS400); 338d12990f9SPiotr Sroka } 339d12990f9SPiotr Sroka 340ff6af28fSMasahiro Yamada static int sdhci_cdns_probe(struct platform_device *pdev) 341ff6af28fSMasahiro Yamada { 342ff6af28fSMasahiro Yamada struct sdhci_host *host; 34318b587b4SMasahiro Yamada const struct sdhci_pltfm_data *data; 344ff6af28fSMasahiro Yamada struct sdhci_pltfm_host *pltfm_host; 345ff6af28fSMasahiro Yamada struct sdhci_cdns_priv *priv; 346ff6af28fSMasahiro Yamada struct clk *clk; 347a232a8f2SMasahiro Yamada unsigned int nr_phy_params; 348ff6af28fSMasahiro Yamada int ret; 349a89c472dSPiotr Sroka struct device *dev = &pdev->dev; 35012a632e6SMasahiro Yamada static const u16 version = SDHCI_SPEC_400 << SDHCI_SPEC_VER_SHIFT; 351ff6af28fSMasahiro Yamada 352edf98579SPiotr Sroka clk = devm_clk_get(dev, NULL); 353ff6af28fSMasahiro Yamada if (IS_ERR(clk)) 354ff6af28fSMasahiro Yamada return PTR_ERR(clk); 355ff6af28fSMasahiro Yamada 356ff6af28fSMasahiro Yamada ret = clk_prepare_enable(clk); 357ff6af28fSMasahiro Yamada if (ret) 358ff6af28fSMasahiro Yamada return ret; 359ff6af28fSMasahiro Yamada 36018b587b4SMasahiro Yamada data = of_device_get_match_data(dev); 36118b587b4SMasahiro Yamada if (!data) 36218b587b4SMasahiro Yamada data = &sdhci_cdns_pltfm_data; 36318b587b4SMasahiro Yamada 364a232a8f2SMasahiro Yamada nr_phy_params = sdhci_cdns_phy_param_count(dev->of_node); 36518b587b4SMasahiro Yamada host = sdhci_pltfm_init(pdev, data, 366159a8b46SGustavo A. R. Silva struct_size(priv, phy_params, nr_phy_params)); 367ff6af28fSMasahiro Yamada if (IS_ERR(host)) { 368ff6af28fSMasahiro Yamada ret = PTR_ERR(host); 369ff6af28fSMasahiro Yamada goto disable_clk; 370ff6af28fSMasahiro Yamada } 371ff6af28fSMasahiro Yamada 372ff6af28fSMasahiro Yamada pltfm_host = sdhci_priv(host); 373ff6af28fSMasahiro Yamada pltfm_host->clk = clk; 374ff6af28fSMasahiro Yamada 375a232a8f2SMasahiro Yamada priv = sdhci_pltfm_priv(pltfm_host); 376a232a8f2SMasahiro Yamada priv->nr_phy_params = nr_phy_params; 377ff6af28fSMasahiro Yamada priv->hrs_addr = host->ioaddr; 378d12990f9SPiotr Sroka priv->enhanced_strobe = false; 379ff6af28fSMasahiro Yamada host->ioaddr += SDHCI_CDNS_SRS_BASE; 380ff6af28fSMasahiro Yamada host->mmc_host_ops.execute_tuning = sdhci_cdns_execute_tuning; 381d12990f9SPiotr Sroka host->mmc_host_ops.hs400_enhanced_strobe = 382d12990f9SPiotr Sroka sdhci_cdns_hs400_enhanced_strobe; 383e73a3896SMasahiro Yamada sdhci_enable_v4_mode(host); 38412a632e6SMasahiro Yamada __sdhci_read_caps(host, &version, NULL, NULL); 385ff6af28fSMasahiro Yamada 386861183f1SPiotr Sroka sdhci_get_of_property(pdev); 387861183f1SPiotr Sroka 388ff6af28fSMasahiro Yamada ret = mmc_of_parse(host->mmc); 389ff6af28fSMasahiro Yamada if (ret) 390ff6af28fSMasahiro Yamada goto free; 391ff6af28fSMasahiro Yamada 392a232a8f2SMasahiro Yamada sdhci_cdns_phy_param_parse(dev->of_node, priv); 393a232a8f2SMasahiro Yamada 394a232a8f2SMasahiro Yamada ret = sdhci_cdns_phy_init(priv); 395a89c472dSPiotr Sroka if (ret) 396a89c472dSPiotr Sroka goto free; 397ff6af28fSMasahiro Yamada 398ff6af28fSMasahiro Yamada ret = sdhci_add_host(host); 399ff6af28fSMasahiro Yamada if (ret) 400ff6af28fSMasahiro Yamada goto free; 401ff6af28fSMasahiro Yamada 402ff6af28fSMasahiro Yamada return 0; 403ff6af28fSMasahiro Yamada free: 404ff6af28fSMasahiro Yamada sdhci_pltfm_free(pdev); 405ff6af28fSMasahiro Yamada disable_clk: 406ff6af28fSMasahiro Yamada clk_disable_unprepare(clk); 407ff6af28fSMasahiro Yamada 408ff6af28fSMasahiro Yamada return ret; 409ff6af28fSMasahiro Yamada } 410ff6af28fSMasahiro Yamada 411a232a8f2SMasahiro Yamada #ifdef CONFIG_PM_SLEEP 412a232a8f2SMasahiro Yamada static int sdhci_cdns_resume(struct device *dev) 413a232a8f2SMasahiro Yamada { 414a232a8f2SMasahiro Yamada struct sdhci_host *host = dev_get_drvdata(dev); 415a232a8f2SMasahiro Yamada struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 416a232a8f2SMasahiro Yamada struct sdhci_cdns_priv *priv = sdhci_pltfm_priv(pltfm_host); 417a232a8f2SMasahiro Yamada int ret; 418a232a8f2SMasahiro Yamada 419a232a8f2SMasahiro Yamada ret = clk_prepare_enable(pltfm_host->clk); 420a232a8f2SMasahiro Yamada if (ret) 421a232a8f2SMasahiro Yamada return ret; 422a232a8f2SMasahiro Yamada 423a232a8f2SMasahiro Yamada ret = sdhci_cdns_phy_init(priv); 424a232a8f2SMasahiro Yamada if (ret) 425a232a8f2SMasahiro Yamada goto disable_clk; 426a232a8f2SMasahiro Yamada 427a232a8f2SMasahiro Yamada ret = sdhci_resume_host(host); 428a232a8f2SMasahiro Yamada if (ret) 429a232a8f2SMasahiro Yamada goto disable_clk; 430a232a8f2SMasahiro Yamada 431a232a8f2SMasahiro Yamada return 0; 432a232a8f2SMasahiro Yamada 433a232a8f2SMasahiro Yamada disable_clk: 434a232a8f2SMasahiro Yamada clk_disable_unprepare(pltfm_host->clk); 435a232a8f2SMasahiro Yamada 436a232a8f2SMasahiro Yamada return ret; 437a232a8f2SMasahiro Yamada } 438a232a8f2SMasahiro Yamada #endif 439a232a8f2SMasahiro Yamada 440a232a8f2SMasahiro Yamada static const struct dev_pm_ops sdhci_cdns_pm_ops = { 44183a7b32aSMasahiro Yamada SET_SYSTEM_SLEEP_PM_OPS(sdhci_pltfm_suspend, sdhci_cdns_resume) 442a232a8f2SMasahiro Yamada }; 443a232a8f2SMasahiro Yamada 444ff6af28fSMasahiro Yamada static const struct of_device_id sdhci_cdns_match[] = { 44518b587b4SMasahiro Yamada { 44618b587b4SMasahiro Yamada .compatible = "socionext,uniphier-sd4hc", 44718b587b4SMasahiro Yamada .data = &sdhci_cdns_uniphier_pltfm_data, 44818b587b4SMasahiro Yamada }, 449ff6af28fSMasahiro Yamada { .compatible = "cdns,sd4hc" }, 450ff6af28fSMasahiro Yamada { /* sentinel */ } 451ff6af28fSMasahiro Yamada }; 452ff6af28fSMasahiro Yamada MODULE_DEVICE_TABLE(of, sdhci_cdns_match); 453ff6af28fSMasahiro Yamada 454ff6af28fSMasahiro Yamada static struct platform_driver sdhci_cdns_driver = { 455ff6af28fSMasahiro Yamada .driver = { 456ff6af28fSMasahiro Yamada .name = "sdhci-cdns", 457a232a8f2SMasahiro Yamada .pm = &sdhci_cdns_pm_ops, 458ff6af28fSMasahiro Yamada .of_match_table = sdhci_cdns_match, 459ff6af28fSMasahiro Yamada }, 460ff6af28fSMasahiro Yamada .probe = sdhci_cdns_probe, 461ff6af28fSMasahiro Yamada .remove = sdhci_pltfm_unregister, 462ff6af28fSMasahiro Yamada }; 463ff6af28fSMasahiro Yamada module_platform_driver(sdhci_cdns_driver); 464ff6af28fSMasahiro Yamada 465ff6af28fSMasahiro Yamada MODULE_AUTHOR("Masahiro Yamada <yamada.masahiro@socionext.com>"); 466ff6af28fSMasahiro Yamada MODULE_DESCRIPTION("Cadence SD/SDIO/eMMC Host Controller Driver"); 467ff6af28fSMasahiro Yamada MODULE_LICENSE("GPL"); 468