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