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