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