1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Exynos Specific Extensions for Synopsys DW Multimedia Card Interface driver 4 * 5 * Copyright (C) 2012, Samsung Electronics Co., Ltd. 6 */ 7 8 #include <linux/module.h> 9 #include <linux/platform_device.h> 10 #include <linux/clk.h> 11 #include <linux/mmc/host.h> 12 #include <linux/mmc/mmc.h> 13 #include <linux/of.h> 14 #include <linux/pm_runtime.h> 15 #include <linux/slab.h> 16 17 #include "dw_mmc.h" 18 #include "dw_mmc-pltfm.h" 19 #include "dw_mmc-exynos.h" 20 21 /* Variations in Exynos specific dw-mshc controller */ 22 enum dw_mci_exynos_type { 23 DW_MCI_TYPE_EXYNOS4210, 24 DW_MCI_TYPE_EXYNOS4412, 25 DW_MCI_TYPE_EXYNOS5250, 26 DW_MCI_TYPE_EXYNOS5420, 27 DW_MCI_TYPE_EXYNOS5420_SMU, 28 DW_MCI_TYPE_EXYNOS7, 29 DW_MCI_TYPE_EXYNOS7_SMU, 30 DW_MCI_TYPE_EXYNOS7870, 31 DW_MCI_TYPE_EXYNOS7870_SMU, 32 DW_MCI_TYPE_ARTPEC8, 33 }; 34 35 /* Exynos implementation specific driver private data */ 36 struct dw_mci_exynos_priv_data { 37 enum dw_mci_exynos_type ctrl_type; 38 u8 ciu_div; 39 u32 sdr_timing; 40 u32 ddr_timing; 41 u32 hs400_timing; 42 u32 tuned_sample; 43 u32 cur_speed; 44 u32 dqs_delay; 45 u32 saved_dqs_en; 46 u32 saved_strobe_ctrl; 47 }; 48 49 static struct dw_mci_exynos_compatible { 50 char *compatible; 51 enum dw_mci_exynos_type ctrl_type; 52 } exynos_compat[] = { 53 { 54 .compatible = "samsung,exynos4210-dw-mshc", 55 .ctrl_type = DW_MCI_TYPE_EXYNOS4210, 56 }, { 57 .compatible = "samsung,exynos4412-dw-mshc", 58 .ctrl_type = DW_MCI_TYPE_EXYNOS4412, 59 }, { 60 .compatible = "samsung,exynos5250-dw-mshc", 61 .ctrl_type = DW_MCI_TYPE_EXYNOS5250, 62 }, { 63 .compatible = "samsung,exynos5420-dw-mshc", 64 .ctrl_type = DW_MCI_TYPE_EXYNOS5420, 65 }, { 66 .compatible = "samsung,exynos5420-dw-mshc-smu", 67 .ctrl_type = DW_MCI_TYPE_EXYNOS5420_SMU, 68 }, { 69 .compatible = "samsung,exynos7-dw-mshc", 70 .ctrl_type = DW_MCI_TYPE_EXYNOS7, 71 }, { 72 .compatible = "samsung,exynos7-dw-mshc-smu", 73 .ctrl_type = DW_MCI_TYPE_EXYNOS7_SMU, 74 }, { 75 .compatible = "samsung,exynos7870-dw-mshc", 76 .ctrl_type = DW_MCI_TYPE_EXYNOS7870, 77 }, { 78 .compatible = "samsung,exynos7870-dw-mshc-smu", 79 .ctrl_type = DW_MCI_TYPE_EXYNOS7870_SMU, 80 }, { 81 .compatible = "axis,artpec8-dw-mshc", 82 .ctrl_type = DW_MCI_TYPE_ARTPEC8, 83 }, 84 }; 85 86 static inline u8 dw_mci_exynos_get_ciu_div(struct dw_mci *host) 87 { 88 struct dw_mci_exynos_priv_data *priv = host->priv; 89 90 if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS4412) 91 return EXYNOS4412_FIXED_CIU_CLK_DIV; 92 else if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS4210) 93 return EXYNOS4210_FIXED_CIU_CLK_DIV; 94 else if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || 95 priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU || 96 priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870 || 97 priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870_SMU || 98 priv->ctrl_type == DW_MCI_TYPE_ARTPEC8) 99 return SDMMC_CLKSEL_GET_DIV(mci_readl(host, CLKSEL64)) + 1; 100 else 101 return SDMMC_CLKSEL_GET_DIV(mci_readl(host, CLKSEL)) + 1; 102 } 103 104 static void dw_mci_exynos_config_smu(struct dw_mci *host) 105 { 106 struct dw_mci_exynos_priv_data *priv = host->priv; 107 108 /* 109 * If Exynos is provided the Security management, 110 * set for non-ecryption mode at this time. 111 */ 112 if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS5420_SMU || 113 priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU || 114 priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870_SMU) { 115 mci_writel(host, MPSBEGIN0, 0); 116 mci_writel(host, MPSEND0, SDMMC_ENDING_SEC_NR_MAX); 117 mci_writel(host, MPSCTRL0, SDMMC_MPSCTRL_SECURE_WRITE_BIT | 118 SDMMC_MPSCTRL_NON_SECURE_READ_BIT | 119 SDMMC_MPSCTRL_VALID | 120 SDMMC_MPSCTRL_NON_SECURE_WRITE_BIT); 121 } 122 } 123 124 static int dw_mci_exynos_priv_init(struct dw_mci *host) 125 { 126 struct dw_mci_exynos_priv_data *priv = host->priv; 127 128 dw_mci_exynos_config_smu(host); 129 130 if (priv->ctrl_type >= DW_MCI_TYPE_EXYNOS5420) { 131 priv->saved_strobe_ctrl = mci_readl(host, HS400_DLINE_CTRL); 132 priv->saved_dqs_en = mci_readl(host, HS400_DQS_EN); 133 priv->saved_dqs_en |= AXI_NON_BLOCKING_WR; 134 mci_writel(host, HS400_DQS_EN, priv->saved_dqs_en); 135 if (!priv->dqs_delay) 136 priv->dqs_delay = 137 DQS_CTRL_GET_RD_DELAY(priv->saved_strobe_ctrl); 138 } 139 140 if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870 || 141 priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870_SMU) { 142 /* Quirk needed for certain Exynos SoCs */ 143 host->quirks |= DW_MMC_QUIRK_FIFO64_32; 144 } 145 146 if (priv->ctrl_type == DW_MCI_TYPE_ARTPEC8) { 147 /* Quirk needed for the ARTPEC-8 SoC */ 148 host->quirks |= DW_MMC_QUIRK_EXTENDED_TMOUT; 149 } 150 151 host->bus_hz /= (priv->ciu_div + 1); 152 153 return 0; 154 } 155 156 static void dw_mci_exynos_set_clksel_timing(struct dw_mci *host, u32 timing) 157 { 158 struct dw_mci_exynos_priv_data *priv = host->priv; 159 u32 clksel; 160 161 if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || 162 priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU || 163 priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870 || 164 priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870_SMU || 165 priv->ctrl_type == DW_MCI_TYPE_ARTPEC8) 166 clksel = mci_readl(host, CLKSEL64); 167 else 168 clksel = mci_readl(host, CLKSEL); 169 170 clksel = (clksel & ~SDMMC_CLKSEL_TIMING_MASK) | timing; 171 172 if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || 173 priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU || 174 priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870 || 175 priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870_SMU || 176 priv->ctrl_type == DW_MCI_TYPE_ARTPEC8) 177 mci_writel(host, CLKSEL64, clksel); 178 else 179 mci_writel(host, CLKSEL, clksel); 180 181 /* 182 * Exynos4412 and Exynos5250 extends the use of CMD register with the 183 * use of bit 29 (which is reserved on standard MSHC controllers) for 184 * optionally bypassing the HOLD register for command and data. The 185 * HOLD register should be bypassed in case there is no phase shift 186 * applied on CMD/DATA that is sent to the card. 187 */ 188 if (!SDMMC_CLKSEL_GET_DRV_WD3(clksel) && host->slot) 189 set_bit(DW_MMC_CARD_NO_USE_HOLD, &host->slot->flags); 190 } 191 192 #ifdef CONFIG_PM 193 static int dw_mci_exynos_runtime_resume(struct device *dev) 194 { 195 struct dw_mci *host = dev_get_drvdata(dev); 196 int ret; 197 198 ret = dw_mci_runtime_resume(dev); 199 if (ret) 200 return ret; 201 202 dw_mci_exynos_config_smu(host); 203 204 return ret; 205 } 206 #endif /* CONFIG_PM */ 207 208 #ifdef CONFIG_PM_SLEEP 209 /** 210 * dw_mci_exynos_suspend_noirq - Exynos-specific suspend code 211 * @dev: Device to suspend (this device) 212 * 213 * This ensures that device will be in runtime active state in 214 * dw_mci_exynos_resume_noirq after calling pm_runtime_force_resume() 215 */ 216 static int dw_mci_exynos_suspend_noirq(struct device *dev) 217 { 218 pm_runtime_get_noresume(dev); 219 return pm_runtime_force_suspend(dev); 220 } 221 222 /** 223 * dw_mci_exynos_resume_noirq - Exynos-specific resume code 224 * @dev: Device to resume (this device) 225 * 226 * On exynos5420 there is a silicon errata that will sometimes leave the 227 * WAKEUP_INT bit in the CLKSEL register asserted. This bit is 1 to indicate 228 * that it fired and we can clear it by writing a 1 back. Clear it to prevent 229 * interrupts from going off constantly. 230 * 231 * We run this code on all exynos variants because it doesn't hurt. 232 */ 233 static int dw_mci_exynos_resume_noirq(struct device *dev) 234 { 235 struct dw_mci *host = dev_get_drvdata(dev); 236 struct dw_mci_exynos_priv_data *priv = host->priv; 237 u32 clksel; 238 int ret; 239 240 ret = pm_runtime_force_resume(dev); 241 if (ret) 242 return ret; 243 244 if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || 245 priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU || 246 priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870 || 247 priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870_SMU || 248 priv->ctrl_type == DW_MCI_TYPE_ARTPEC8) 249 clksel = mci_readl(host, CLKSEL64); 250 else 251 clksel = mci_readl(host, CLKSEL); 252 253 if (clksel & SDMMC_CLKSEL_WAKEUP_INT) { 254 if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || 255 priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU || 256 priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870 || 257 priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870_SMU || 258 priv->ctrl_type == DW_MCI_TYPE_ARTPEC8) 259 mci_writel(host, CLKSEL64, clksel); 260 else 261 mci_writel(host, CLKSEL, clksel); 262 } 263 264 pm_runtime_put(dev); 265 266 return 0; 267 } 268 #endif /* CONFIG_PM_SLEEP */ 269 270 static void dw_mci_exynos_config_hs400(struct dw_mci *host, u32 timing) 271 { 272 struct dw_mci_exynos_priv_data *priv = host->priv; 273 u32 dqs, strobe; 274 275 /* 276 * Not supported to configure register 277 * related to HS400 278 */ 279 if ((priv->ctrl_type < DW_MCI_TYPE_EXYNOS5420) || 280 (priv->ctrl_type == DW_MCI_TYPE_ARTPEC8)) { 281 if (timing == MMC_TIMING_MMC_HS400) 282 dev_warn(host->dev, 283 "cannot configure HS400, unsupported chipset\n"); 284 return; 285 } 286 287 dqs = priv->saved_dqs_en; 288 strobe = priv->saved_strobe_ctrl; 289 290 if (timing == MMC_TIMING_MMC_HS400) { 291 dqs |= DATA_STROBE_EN; 292 strobe = DQS_CTRL_RD_DELAY(strobe, priv->dqs_delay); 293 } else if (timing == MMC_TIMING_UHS_SDR104) { 294 dqs &= 0xffffff00; 295 } else { 296 dqs &= ~DATA_STROBE_EN; 297 } 298 299 mci_writel(host, HS400_DQS_EN, dqs); 300 mci_writel(host, HS400_DLINE_CTRL, strobe); 301 } 302 303 static void dw_mci_exynos_adjust_clock(struct dw_mci *host, unsigned int wanted) 304 { 305 struct dw_mci_exynos_priv_data *priv = host->priv; 306 unsigned long actual; 307 u8 div; 308 int ret; 309 /* 310 * Don't care if wanted clock is zero or 311 * ciu clock is unavailable 312 */ 313 if (!wanted || IS_ERR(host->ciu_clk)) 314 return; 315 316 /* Guaranteed minimum frequency for cclkin */ 317 if (wanted < EXYNOS_CCLKIN_MIN) 318 wanted = EXYNOS_CCLKIN_MIN; 319 320 if (wanted == priv->cur_speed) 321 return; 322 323 div = dw_mci_exynos_get_ciu_div(host); 324 ret = clk_set_rate(host->ciu_clk, wanted * div); 325 if (ret) 326 dev_warn(host->dev, 327 "failed to set clk-rate %u error: %d\n", 328 wanted * div, ret); 329 actual = clk_get_rate(host->ciu_clk); 330 host->bus_hz = actual / div; 331 priv->cur_speed = wanted; 332 host->current_speed = 0; 333 } 334 335 static void dw_mci_exynos_set_ios(struct dw_mci *host, struct mmc_ios *ios) 336 { 337 struct dw_mci_exynos_priv_data *priv = host->priv; 338 unsigned int wanted = ios->clock; 339 u32 timing = ios->timing, clksel; 340 341 switch (timing) { 342 case MMC_TIMING_MMC_HS400: 343 /* Update tuned sample timing */ 344 clksel = SDMMC_CLKSEL_UP_SAMPLE( 345 priv->hs400_timing, priv->tuned_sample); 346 wanted <<= 1; 347 break; 348 case MMC_TIMING_MMC_DDR52: 349 clksel = priv->ddr_timing; 350 /* Should be double rate for DDR mode */ 351 if (ios->bus_width == MMC_BUS_WIDTH_8) 352 wanted <<= 1; 353 break; 354 case MMC_TIMING_UHS_SDR104: 355 case MMC_TIMING_UHS_SDR50: 356 clksel = (priv->sdr_timing & 0xfff8ffff) | 357 (priv->ciu_div << 16); 358 break; 359 case MMC_TIMING_UHS_DDR50: 360 clksel = (priv->ddr_timing & 0xfff8ffff) | 361 (priv->ciu_div << 16); 362 break; 363 default: 364 clksel = priv->sdr_timing; 365 } 366 367 /* Set clock timing for the requested speed mode*/ 368 dw_mci_exynos_set_clksel_timing(host, clksel); 369 370 /* Configure setting for HS400 */ 371 dw_mci_exynos_config_hs400(host, timing); 372 373 /* Configure clock rate */ 374 dw_mci_exynos_adjust_clock(host, wanted); 375 } 376 377 static int dw_mci_exynos_parse_dt(struct dw_mci *host) 378 { 379 struct dw_mci_exynos_priv_data *priv; 380 struct device_node *np = host->dev->of_node; 381 u32 timing[2]; 382 u32 div = 0; 383 int idx; 384 int ret; 385 386 priv = devm_kzalloc(host->dev, sizeof(*priv), GFP_KERNEL); 387 if (!priv) 388 return -ENOMEM; 389 390 for (idx = 0; idx < ARRAY_SIZE(exynos_compat); idx++) { 391 if (of_device_is_compatible(np, exynos_compat[idx].compatible)) 392 priv->ctrl_type = exynos_compat[idx].ctrl_type; 393 } 394 395 if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS4412) 396 priv->ciu_div = EXYNOS4412_FIXED_CIU_CLK_DIV - 1; 397 else if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS4210) 398 priv->ciu_div = EXYNOS4210_FIXED_CIU_CLK_DIV - 1; 399 else { 400 of_property_read_u32(np, "samsung,dw-mshc-ciu-div", &div); 401 priv->ciu_div = div; 402 } 403 404 ret = of_property_read_u32_array(np, 405 "samsung,dw-mshc-sdr-timing", timing, 2); 406 if (ret) 407 return ret; 408 409 priv->sdr_timing = SDMMC_CLKSEL_TIMING(timing[0], timing[1], div); 410 411 ret = of_property_read_u32_array(np, 412 "samsung,dw-mshc-ddr-timing", timing, 2); 413 if (ret) 414 return ret; 415 416 priv->ddr_timing = SDMMC_CLKSEL_TIMING(timing[0], timing[1], div); 417 418 ret = of_property_read_u32_array(np, 419 "samsung,dw-mshc-hs400-timing", timing, 2); 420 if (!ret && of_property_read_u32(np, 421 "samsung,read-strobe-delay", &priv->dqs_delay)) 422 dev_dbg(host->dev, 423 "read-strobe-delay is not found, assuming usage of default value\n"); 424 425 priv->hs400_timing = SDMMC_CLKSEL_TIMING(timing[0], timing[1], 426 HS400_FIXED_CIU_CLK_DIV); 427 host->priv = priv; 428 return 0; 429 } 430 431 static inline u8 dw_mci_exynos_get_clksmpl(struct dw_mci *host) 432 { 433 struct dw_mci_exynos_priv_data *priv = host->priv; 434 435 if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || 436 priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU || 437 priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870 || 438 priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870_SMU || 439 priv->ctrl_type == DW_MCI_TYPE_ARTPEC8) 440 return SDMMC_CLKSEL_CCLK_SAMPLE(mci_readl(host, CLKSEL64)); 441 else 442 return SDMMC_CLKSEL_CCLK_SAMPLE(mci_readl(host, CLKSEL)); 443 } 444 445 static inline void dw_mci_exynos_set_clksmpl(struct dw_mci *host, u8 sample) 446 { 447 u32 clksel; 448 struct dw_mci_exynos_priv_data *priv = host->priv; 449 450 if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || 451 priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU || 452 priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870 || 453 priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870_SMU || 454 priv->ctrl_type == DW_MCI_TYPE_ARTPEC8) 455 clksel = mci_readl(host, CLKSEL64); 456 else 457 clksel = mci_readl(host, CLKSEL); 458 clksel = SDMMC_CLKSEL_UP_SAMPLE(clksel, sample); 459 if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || 460 priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU || 461 priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870 || 462 priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870_SMU || 463 priv->ctrl_type == DW_MCI_TYPE_ARTPEC8) 464 mci_writel(host, CLKSEL64, clksel); 465 else 466 mci_writel(host, CLKSEL, clksel); 467 } 468 469 static inline u8 dw_mci_exynos_move_next_clksmpl(struct dw_mci *host) 470 { 471 struct dw_mci_exynos_priv_data *priv = host->priv; 472 u32 clksel; 473 u8 sample; 474 475 if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || 476 priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU || 477 priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870 || 478 priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870_SMU || 479 priv->ctrl_type == DW_MCI_TYPE_ARTPEC8) 480 clksel = mci_readl(host, CLKSEL64); 481 else 482 clksel = mci_readl(host, CLKSEL); 483 484 sample = (clksel + 1) & 0x7; 485 clksel = SDMMC_CLKSEL_UP_SAMPLE(clksel, sample); 486 487 if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || 488 priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU || 489 priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870 || 490 priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870_SMU || 491 priv->ctrl_type == DW_MCI_TYPE_ARTPEC8) 492 mci_writel(host, CLKSEL64, clksel); 493 else 494 mci_writel(host, CLKSEL, clksel); 495 496 return sample; 497 } 498 499 static s8 dw_mci_exynos_get_best_clksmpl(u8 candidates) 500 { 501 const u8 iter = 8; 502 u8 __c; 503 s8 i, loc = -1; 504 505 for (i = 0; i < iter; i++) { 506 __c = ror8(candidates, i); 507 if ((__c & 0xc7) == 0xc7) { 508 loc = i; 509 goto out; 510 } 511 } 512 513 for (i = 0; i < iter; i++) { 514 __c = ror8(candidates, i); 515 if ((__c & 0x83) == 0x83) { 516 loc = i; 517 goto out; 518 } 519 } 520 521 /* 522 * If there is no cadiates value, then it needs to return -EIO. 523 * If there are candidates values and don't find bset clk sample value, 524 * then use a first candidates clock sample value. 525 */ 526 for (i = 0; i < iter; i++) { 527 __c = ror8(candidates, i); 528 if ((__c & 0x1) == 0x1) { 529 loc = i; 530 goto out; 531 } 532 } 533 out: 534 return loc; 535 } 536 537 static int dw_mci_exynos_execute_tuning(struct dw_mci_slot *slot, u32 opcode) 538 { 539 struct dw_mci *host = slot->host; 540 struct dw_mci_exynos_priv_data *priv = host->priv; 541 struct mmc_host *mmc = slot->mmc; 542 u8 start_smpl, smpl, candidates = 0; 543 s8 found; 544 int ret = 0; 545 546 start_smpl = dw_mci_exynos_get_clksmpl(host); 547 548 do { 549 mci_writel(host, TMOUT, ~0); 550 smpl = dw_mci_exynos_move_next_clksmpl(host); 551 552 if (!mmc_send_tuning(mmc, opcode, NULL)) 553 candidates |= (1 << smpl); 554 555 } while (start_smpl != smpl); 556 557 found = dw_mci_exynos_get_best_clksmpl(candidates); 558 if (found >= 0) { 559 dw_mci_exynos_set_clksmpl(host, found); 560 priv->tuned_sample = found; 561 } else { 562 ret = -EIO; 563 dev_warn(&mmc->class_dev, 564 "There is no candidates value about clksmpl!\n"); 565 } 566 567 return ret; 568 } 569 570 static int dw_mci_exynos_prepare_hs400_tuning(struct dw_mci *host, 571 struct mmc_ios *ios) 572 { 573 struct dw_mci_exynos_priv_data *priv = host->priv; 574 575 dw_mci_exynos_set_clksel_timing(host, priv->hs400_timing); 576 dw_mci_exynos_adjust_clock(host, (ios->clock) << 1); 577 578 return 0; 579 } 580 581 static void dw_mci_exynos_set_data_timeout(struct dw_mci *host, 582 unsigned int timeout_ns) 583 { 584 u32 clk_div, tmout; 585 u64 tmp; 586 unsigned int tmp2; 587 588 clk_div = (mci_readl(host, CLKDIV) & 0xFF) * 2; 589 if (clk_div == 0) 590 clk_div = 1; 591 592 tmp = DIV_ROUND_UP_ULL((u64)timeout_ns * host->bus_hz, NSEC_PER_SEC); 593 tmp = DIV_ROUND_UP_ULL(tmp, clk_div); 594 595 /* TMOUT[7:0] (RESPONSE_TIMEOUT) */ 596 tmout = 0xFF; /* Set maximum */ 597 598 /* 599 * Extended HW timer (max = 0x6FFFFF2): 600 * ((TMOUT[10:8] - 1) * 0xFFFFFF + TMOUT[31:11] * 8) 601 */ 602 if (!tmp || tmp > 0x6FFFFF2) 603 tmout |= (0xFFFFFF << 8); 604 else { 605 /* TMOUT[10:8] */ 606 tmp2 = (((unsigned int)tmp / 0xFFFFFF) + 1) & 0x7; 607 tmout |= tmp2 << 8; 608 609 /* TMOUT[31:11] */ 610 tmp = tmp - ((tmp2 - 1) * 0xFFFFFF); 611 tmout |= (tmp & 0xFFFFF8) << 8; 612 } 613 614 mci_writel(host, TMOUT, tmout); 615 dev_dbg(host->dev, "timeout_ns: %u => TMOUT[31:8]: %#08x", 616 timeout_ns, tmout >> 8); 617 } 618 619 static u32 dw_mci_exynos_get_drto_clks(struct dw_mci *host) 620 { 621 u32 drto_clks; 622 623 drto_clks = mci_readl(host, TMOUT) >> 8; 624 625 return (((drto_clks & 0x7) - 1) * 0xFFFFFF) + ((drto_clks & 0xFFFFF8)); 626 } 627 628 /* Common capabilities of Exynos4/Exynos5 SoC */ 629 static unsigned long exynos_dwmmc_caps[4] = { 630 MMC_CAP_1_8V_DDR | MMC_CAP_8_BIT_DATA, 631 0, 632 0, 633 0, 634 }; 635 636 static const struct dw_mci_drv_data exynos_drv_data = { 637 .caps = exynos_dwmmc_caps, 638 .num_caps = ARRAY_SIZE(exynos_dwmmc_caps), 639 .common_caps = MMC_CAP_CMD23, 640 .init = dw_mci_exynos_priv_init, 641 .set_ios = dw_mci_exynos_set_ios, 642 .parse_dt = dw_mci_exynos_parse_dt, 643 .execute_tuning = dw_mci_exynos_execute_tuning, 644 .prepare_hs400_tuning = dw_mci_exynos_prepare_hs400_tuning, 645 }; 646 647 static const struct dw_mci_drv_data artpec_drv_data = { 648 .common_caps = MMC_CAP_CMD23, 649 .init = dw_mci_exynos_priv_init, 650 .set_ios = dw_mci_exynos_set_ios, 651 .parse_dt = dw_mci_exynos_parse_dt, 652 .execute_tuning = dw_mci_exynos_execute_tuning, 653 .set_data_timeout = dw_mci_exynos_set_data_timeout, 654 .get_drto_clks = dw_mci_exynos_get_drto_clks, 655 }; 656 657 static const struct of_device_id dw_mci_exynos_match[] = { 658 { .compatible = "samsung,exynos4412-dw-mshc", 659 .data = &exynos_drv_data, }, 660 { .compatible = "samsung,exynos5250-dw-mshc", 661 .data = &exynos_drv_data, }, 662 { .compatible = "samsung,exynos5420-dw-mshc", 663 .data = &exynos_drv_data, }, 664 { .compatible = "samsung,exynos5420-dw-mshc-smu", 665 .data = &exynos_drv_data, }, 666 { .compatible = "samsung,exynos7-dw-mshc", 667 .data = &exynos_drv_data, }, 668 { .compatible = "samsung,exynos7-dw-mshc-smu", 669 .data = &exynos_drv_data, }, 670 { .compatible = "samsung,exynos7870-dw-mshc", 671 .data = &exynos_drv_data, }, 672 { .compatible = "samsung,exynos7870-dw-mshc-smu", 673 .data = &exynos_drv_data, }, 674 { .compatible = "axis,artpec8-dw-mshc", 675 .data = &artpec_drv_data, }, 676 {}, 677 }; 678 MODULE_DEVICE_TABLE(of, dw_mci_exynos_match); 679 680 static int dw_mci_exynos_probe(struct platform_device *pdev) 681 { 682 const struct dw_mci_drv_data *drv_data; 683 const struct of_device_id *match; 684 int ret; 685 686 match = of_match_node(dw_mci_exynos_match, pdev->dev.of_node); 687 drv_data = match->data; 688 689 pm_runtime_get_noresume(&pdev->dev); 690 pm_runtime_set_active(&pdev->dev); 691 pm_runtime_enable(&pdev->dev); 692 693 ret = dw_mci_pltfm_register(pdev, drv_data); 694 if (ret) { 695 pm_runtime_disable(&pdev->dev); 696 pm_runtime_set_suspended(&pdev->dev); 697 pm_runtime_put_noidle(&pdev->dev); 698 699 return ret; 700 } 701 702 return 0; 703 } 704 705 static void dw_mci_exynos_remove(struct platform_device *pdev) 706 { 707 pm_runtime_disable(&pdev->dev); 708 pm_runtime_set_suspended(&pdev->dev); 709 pm_runtime_put_noidle(&pdev->dev); 710 711 dw_mci_pltfm_remove(pdev); 712 } 713 714 static const struct dev_pm_ops dw_mci_exynos_pmops = { 715 SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(dw_mci_exynos_suspend_noirq, 716 dw_mci_exynos_resume_noirq) 717 SET_RUNTIME_PM_OPS(dw_mci_runtime_suspend, 718 dw_mci_exynos_runtime_resume, 719 NULL) 720 }; 721 722 static struct platform_driver dw_mci_exynos_pltfm_driver = { 723 .probe = dw_mci_exynos_probe, 724 .remove = dw_mci_exynos_remove, 725 .driver = { 726 .name = "dwmmc_exynos", 727 .probe_type = PROBE_PREFER_ASYNCHRONOUS, 728 .of_match_table = dw_mci_exynos_match, 729 .pm = &dw_mci_exynos_pmops, 730 }, 731 }; 732 733 module_platform_driver(dw_mci_exynos_pltfm_driver); 734 735 MODULE_DESCRIPTION("Samsung Specific DW-MSHC Driver Extension"); 736 MODULE_AUTHOR("Thomas Abraham <thomas.ab@samsung.com"); 737 MODULE_LICENSE("GPL v2"); 738 MODULE_ALIAS("platform:dwmmc_exynos"); 739