1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Driver for Marvell SOC Platform Group Xenon SDHC as a platform device 4 * 5 * Copyright (C) 2016 Marvell, All Rights Reserved. 6 * 7 * Author: Victor Gu <xigu@marvell.com> 8 * Date: 2016-8-24 9 * 10 * Included parts of the Linux driver version which was written by: 11 * Hu Ziji <huziji@marvell.com> 12 * 13 * Ported to from Marvell 2015.01 to mainline U-Boot 2017.01: 14 * Stefan Roese <sr@denx.de> 15 */ 16 17 #include <common.h> 18 #include <dm.h> 19 #include <fdtdec.h> 20 #include <linux/libfdt.h> 21 #include <malloc.h> 22 #include <sdhci.h> 23 24 DECLARE_GLOBAL_DATA_PTR; 25 26 /* Register Offset of SD Host Controller SOCP self-defined register */ 27 #define SDHC_SYS_CFG_INFO 0x0104 28 #define SLOT_TYPE_SDIO_SHIFT 24 29 #define SLOT_TYPE_EMMC_MASK 0xFF 30 #define SLOT_TYPE_EMMC_SHIFT 16 31 #define SLOT_TYPE_SD_SDIO_MMC_MASK 0xFF 32 #define SLOT_TYPE_SD_SDIO_MMC_SHIFT 8 33 #define NR_SUPPORTED_SLOT_MASK 0x7 34 35 #define SDHC_SYS_OP_CTRL 0x0108 36 #define AUTO_CLKGATE_DISABLE_MASK BIT(20) 37 #define SDCLK_IDLEOFF_ENABLE_SHIFT 8 38 #define SLOT_ENABLE_SHIFT 0 39 40 #define SDHC_SYS_EXT_OP_CTRL 0x010C 41 #define MASK_CMD_CONFLICT_ERROR BIT(8) 42 43 #define SDHC_SLOT_RETUNING_REQ_CTRL 0x0144 44 /* retuning compatible */ 45 #define RETUNING_COMPATIBLE 0x1 46 47 /* Xenon specific Mode Select value */ 48 #define XENON_SDHCI_CTRL_HS200 0x5 49 #define XENON_SDHCI_CTRL_HS400 0x6 50 51 #define EMMC_PHY_REG_BASE 0x170 52 #define EMMC_PHY_TIMING_ADJUST EMMC_PHY_REG_BASE 53 #define OUTPUT_QSN_PHASE_SELECT BIT(17) 54 #define SAMPL_INV_QSP_PHASE_SELECT BIT(18) 55 #define SAMPL_INV_QSP_PHASE_SELECT_SHIFT 18 56 #define EMMC_PHY_SLOW_MODE BIT(29) 57 #define PHY_INITIALIZAION BIT(31) 58 #define WAIT_CYCLE_BEFORE_USING_MASK 0xf 59 #define WAIT_CYCLE_BEFORE_USING_SHIFT 12 60 #define FC_SYNC_EN_DURATION_MASK 0xf 61 #define FC_SYNC_EN_DURATION_SHIFT 8 62 #define FC_SYNC_RST_EN_DURATION_MASK 0xf 63 #define FC_SYNC_RST_EN_DURATION_SHIFT 4 64 #define FC_SYNC_RST_DURATION_MASK 0xf 65 #define FC_SYNC_RST_DURATION_SHIFT 0 66 67 #define EMMC_PHY_FUNC_CONTROL (EMMC_PHY_REG_BASE + 0x4) 68 #define DQ_ASYNC_MODE BIT(4) 69 #define DQ_DDR_MODE_SHIFT 8 70 #define DQ_DDR_MODE_MASK 0xff 71 #define CMD_DDR_MODE BIT(16) 72 73 #define EMMC_PHY_PAD_CONTROL (EMMC_PHY_REG_BASE + 0x8) 74 #define REC_EN_SHIFT 24 75 #define REC_EN_MASK 0xf 76 #define FC_DQ_RECEN BIT(24) 77 #define FC_CMD_RECEN BIT(25) 78 #define FC_QSP_RECEN BIT(26) 79 #define FC_QSN_RECEN BIT(27) 80 #define OEN_QSN BIT(28) 81 #define AUTO_RECEN_CTRL BIT(30) 82 83 #define EMMC_PHY_PAD_CONTROL1 (EMMC_PHY_REG_BASE + 0xc) 84 #define EMMC5_1_FC_QSP_PD BIT(9) 85 #define EMMC5_1_FC_QSP_PU BIT(25) 86 #define EMMC5_1_FC_CMD_PD BIT(8) 87 #define EMMC5_1_FC_CMD_PU BIT(24) 88 #define EMMC5_1_FC_DQ_PD 0xff 89 #define EMMC5_1_FC_DQ_PU (0xff << 16) 90 91 #define SDHCI_RETUNE_EVT_INTSIG 0x00001000 92 93 /* Hyperion only have one slot 0 */ 94 #define XENON_MMC_SLOT_ID_HYPERION 0 95 96 #define MMC_TIMING_LEGACY 0 97 #define MMC_TIMING_MMC_HS 1 98 #define MMC_TIMING_SD_HS 2 99 #define MMC_TIMING_UHS_SDR12 3 100 #define MMC_TIMING_UHS_SDR25 4 101 #define MMC_TIMING_UHS_SDR50 5 102 #define MMC_TIMING_UHS_SDR104 6 103 #define MMC_TIMING_UHS_DDR50 7 104 #define MMC_TIMING_MMC_DDR52 8 105 #define MMC_TIMING_MMC_HS200 9 106 #define MMC_TIMING_MMC_HS400 10 107 108 #define XENON_MMC_MAX_CLK 400000000 109 110 enum soc_pad_ctrl_type { 111 SOC_PAD_SD, 112 SOC_PAD_FIXED_1_8V, 113 }; 114 115 struct xenon_sdhci_plat { 116 struct mmc_config cfg; 117 struct mmc mmc; 118 }; 119 120 struct xenon_sdhci_priv { 121 struct sdhci_host host; 122 123 u8 timing; 124 125 unsigned int clock; 126 127 void *pad_ctrl_reg; 128 int pad_type; 129 }; 130 131 static int xenon_mmc_phy_init(struct sdhci_host *host) 132 { 133 struct xenon_sdhci_priv *priv = host->mmc->priv; 134 u32 clock = priv->clock; 135 u32 time; 136 u32 var; 137 138 /* Enable QSP PHASE SELECT */ 139 var = sdhci_readl(host, EMMC_PHY_TIMING_ADJUST); 140 var |= SAMPL_INV_QSP_PHASE_SELECT; 141 if ((priv->timing == MMC_TIMING_UHS_SDR50) || 142 (priv->timing == MMC_TIMING_UHS_SDR25) || 143 (priv->timing == MMC_TIMING_UHS_SDR12) || 144 (priv->timing == MMC_TIMING_SD_HS) || 145 (priv->timing == MMC_TIMING_LEGACY)) 146 var |= EMMC_PHY_SLOW_MODE; 147 sdhci_writel(host, var, EMMC_PHY_TIMING_ADJUST); 148 149 /* Poll for host MMC PHY clock init to be stable */ 150 /* Wait up to 10ms */ 151 time = 100; 152 while (time--) { 153 var = sdhci_readl(host, SDHCI_CLOCK_CONTROL); 154 if (var & SDHCI_CLOCK_INT_STABLE) 155 break; 156 157 udelay(100); 158 } 159 160 if (time <= 0) { 161 pr_err("Failed to enable MMC internal clock in time\n"); 162 return -ETIMEDOUT; 163 } 164 165 /* Init PHY */ 166 var = sdhci_readl(host, EMMC_PHY_TIMING_ADJUST); 167 var |= PHY_INITIALIZAION; 168 sdhci_writel(host, var, EMMC_PHY_TIMING_ADJUST); 169 170 if (clock == 0) { 171 /* Use the possibly slowest bus frequency value */ 172 clock = 100000; 173 } 174 175 /* Poll for host eMMC PHY init to complete */ 176 /* Wait up to 10ms */ 177 time = 100; 178 while (time--) { 179 var = sdhci_readl(host, EMMC_PHY_TIMING_ADJUST); 180 var &= PHY_INITIALIZAION; 181 if (!var) 182 break; 183 184 /* wait for host eMMC PHY init to complete */ 185 udelay(100); 186 } 187 188 if (time <= 0) { 189 pr_err("Failed to init MMC PHY in time\n"); 190 return -ETIMEDOUT; 191 } 192 193 return 0; 194 } 195 196 #define ARMADA_3700_SOC_PAD_1_8V 0x1 197 #define ARMADA_3700_SOC_PAD_3_3V 0x0 198 199 static void armada_3700_soc_pad_voltage_set(struct sdhci_host *host) 200 { 201 struct xenon_sdhci_priv *priv = host->mmc->priv; 202 203 if (priv->pad_type == SOC_PAD_FIXED_1_8V) 204 writel(ARMADA_3700_SOC_PAD_1_8V, priv->pad_ctrl_reg); 205 else if (priv->pad_type == SOC_PAD_SD) 206 writel(ARMADA_3700_SOC_PAD_3_3V, priv->pad_ctrl_reg); 207 } 208 209 static void xenon_mmc_phy_set(struct sdhci_host *host) 210 { 211 struct xenon_sdhci_priv *priv = host->mmc->priv; 212 u32 var; 213 214 /* Setup pad, set bit[30], bit[28] and bits[26:24] */ 215 var = sdhci_readl(host, EMMC_PHY_PAD_CONTROL); 216 var |= AUTO_RECEN_CTRL | OEN_QSN | FC_QSP_RECEN | 217 FC_CMD_RECEN | FC_DQ_RECEN; 218 sdhci_writel(host, var, EMMC_PHY_PAD_CONTROL); 219 220 /* Set CMD and DQ Pull Up */ 221 var = sdhci_readl(host, EMMC_PHY_PAD_CONTROL1); 222 var |= (EMMC5_1_FC_CMD_PU | EMMC5_1_FC_DQ_PU); 223 var &= ~(EMMC5_1_FC_CMD_PD | EMMC5_1_FC_DQ_PD); 224 sdhci_writel(host, var, EMMC_PHY_PAD_CONTROL1); 225 226 /* 227 * If timing belongs to high speed, set bit[17] of 228 * EMMC_PHY_TIMING_ADJUST register 229 */ 230 if ((priv->timing == MMC_TIMING_MMC_HS400) || 231 (priv->timing == MMC_TIMING_MMC_HS200) || 232 (priv->timing == MMC_TIMING_UHS_SDR50) || 233 (priv->timing == MMC_TIMING_UHS_SDR104) || 234 (priv->timing == MMC_TIMING_UHS_DDR50) || 235 (priv->timing == MMC_TIMING_UHS_SDR25) || 236 (priv->timing == MMC_TIMING_MMC_DDR52)) { 237 var = sdhci_readl(host, EMMC_PHY_TIMING_ADJUST); 238 var |= OUTPUT_QSN_PHASE_SELECT; 239 sdhci_writel(host, var, EMMC_PHY_TIMING_ADJUST); 240 } 241 242 /* 243 * When setting EMMC_PHY_FUNC_CONTROL register, 244 * SD clock should be disabled 245 */ 246 var = sdhci_readl(host, SDHCI_CLOCK_CONTROL); 247 var &= ~SDHCI_CLOCK_CARD_EN; 248 sdhci_writew(host, var, SDHCI_CLOCK_CONTROL); 249 250 var = sdhci_readl(host, EMMC_PHY_FUNC_CONTROL); 251 if (host->mmc->ddr_mode) { 252 var |= (DQ_DDR_MODE_MASK << DQ_DDR_MODE_SHIFT) | CMD_DDR_MODE; 253 } else { 254 var &= ~((DQ_DDR_MODE_MASK << DQ_DDR_MODE_SHIFT) | 255 CMD_DDR_MODE); 256 } 257 sdhci_writel(host, var, EMMC_PHY_FUNC_CONTROL); 258 259 /* Enable bus clock */ 260 var = sdhci_readl(host, SDHCI_CLOCK_CONTROL); 261 var |= SDHCI_CLOCK_CARD_EN; 262 sdhci_writew(host, var, SDHCI_CLOCK_CONTROL); 263 264 xenon_mmc_phy_init(host); 265 } 266 267 /* Enable/Disable the Auto Clock Gating function of this slot */ 268 static void xenon_mmc_set_acg(struct sdhci_host *host, bool enable) 269 { 270 u32 var; 271 272 var = sdhci_readl(host, SDHC_SYS_OP_CTRL); 273 if (enable) 274 var &= ~AUTO_CLKGATE_DISABLE_MASK; 275 else 276 var |= AUTO_CLKGATE_DISABLE_MASK; 277 278 sdhci_writel(host, var, SDHC_SYS_OP_CTRL); 279 } 280 281 #define SLOT_MASK(slot) BIT(slot) 282 283 /* Enable specific slot */ 284 static void xenon_mmc_enable_slot(struct sdhci_host *host, u8 slot) 285 { 286 u32 var; 287 288 var = sdhci_readl(host, SDHC_SYS_OP_CTRL); 289 var |= SLOT_MASK(slot) << SLOT_ENABLE_SHIFT; 290 sdhci_writel(host, var, SDHC_SYS_OP_CTRL); 291 } 292 293 /* Enable Parallel Transfer Mode */ 294 static void xenon_mmc_enable_parallel_tran(struct sdhci_host *host, u8 slot) 295 { 296 u32 var; 297 298 var = sdhci_readl(host, SDHC_SYS_EXT_OP_CTRL); 299 var |= SLOT_MASK(slot); 300 sdhci_writel(host, var, SDHC_SYS_EXT_OP_CTRL); 301 } 302 303 static void xenon_mmc_disable_tuning(struct sdhci_host *host, u8 slot) 304 { 305 u32 var; 306 307 /* Clear the Re-Tuning Request functionality */ 308 var = sdhci_readl(host, SDHC_SLOT_RETUNING_REQ_CTRL); 309 var &= ~RETUNING_COMPATIBLE; 310 sdhci_writel(host, var, SDHC_SLOT_RETUNING_REQ_CTRL); 311 312 /* Clear the Re-tuning Event Signal Enable */ 313 var = sdhci_readl(host, SDHCI_SIGNAL_ENABLE); 314 var &= ~SDHCI_RETUNE_EVT_INTSIG; 315 sdhci_writel(host, var, SDHCI_SIGNAL_ENABLE); 316 } 317 318 /* Mask command conflict error */ 319 static void xenon_mask_cmd_conflict_err(struct sdhci_host *host) 320 { 321 u32 reg; 322 323 reg = sdhci_readl(host, SDHC_SYS_EXT_OP_CTRL); 324 reg |= MASK_CMD_CONFLICT_ERROR; 325 sdhci_writel(host, reg, SDHC_SYS_EXT_OP_CTRL); 326 } 327 328 /* Platform specific function for post set_ios configuration */ 329 static void xenon_sdhci_set_ios_post(struct sdhci_host *host) 330 { 331 struct xenon_sdhci_priv *priv = host->mmc->priv; 332 uint speed = host->mmc->tran_speed; 333 int pwr_18v = 0; 334 335 if ((sdhci_readb(host, SDHCI_POWER_CONTROL) & ~SDHCI_POWER_ON) == 336 SDHCI_POWER_180) 337 pwr_18v = 1; 338 339 /* Set timing variable according to the configured speed */ 340 if (IS_SD(host->mmc)) { 341 /* SD/SDIO */ 342 if (pwr_18v) { 343 if (host->mmc->ddr_mode) 344 priv->timing = MMC_TIMING_UHS_DDR50; 345 else if (speed <= 25000000) 346 priv->timing = MMC_TIMING_UHS_SDR25; 347 else 348 priv->timing = MMC_TIMING_UHS_SDR50; 349 } else { 350 if (speed <= 25000000) 351 priv->timing = MMC_TIMING_LEGACY; 352 else 353 priv->timing = MMC_TIMING_SD_HS; 354 } 355 } else { 356 /* eMMC */ 357 if (host->mmc->ddr_mode) 358 priv->timing = MMC_TIMING_MMC_DDR52; 359 else if (speed <= 26000000) 360 priv->timing = MMC_TIMING_LEGACY; 361 else 362 priv->timing = MMC_TIMING_MMC_HS; 363 } 364 365 /* Re-init the PHY */ 366 xenon_mmc_phy_set(host); 367 } 368 369 /* Install a driver specific handler for post set_ios configuration */ 370 static const struct sdhci_ops xenon_sdhci_ops = { 371 .set_ios_post = xenon_sdhci_set_ios_post 372 }; 373 374 static int xenon_sdhci_probe(struct udevice *dev) 375 { 376 struct xenon_sdhci_plat *plat = dev_get_platdata(dev); 377 struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); 378 struct xenon_sdhci_priv *priv = dev_get_priv(dev); 379 struct sdhci_host *host = dev_get_priv(dev); 380 int ret; 381 382 host->mmc = &plat->mmc; 383 host->mmc->priv = host; 384 host->mmc->dev = dev; 385 upriv->mmc = host->mmc; 386 387 /* Set quirks */ 388 host->quirks = SDHCI_QUIRK_WAIT_SEND_CMD | SDHCI_QUIRK_32BIT_DMA_ADDR; 389 390 /* Set default timing */ 391 priv->timing = MMC_TIMING_LEGACY; 392 393 /* Disable auto clock gating during init */ 394 xenon_mmc_set_acg(host, false); 395 396 /* Enable slot */ 397 xenon_mmc_enable_slot(host, XENON_MMC_SLOT_ID_HYPERION); 398 399 /* 400 * Set default power on SoC PHY PAD register (currently only 401 * available on the Armada 3700) 402 */ 403 if (priv->pad_ctrl_reg) 404 armada_3700_soc_pad_voltage_set(host); 405 406 host->host_caps = MMC_MODE_HS | MMC_MODE_HS_52MHz | MMC_MODE_DDR_52MHz; 407 switch (fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), "bus-width", 408 1)) { 409 case 8: 410 host->host_caps |= MMC_MODE_8BIT; 411 break; 412 case 4: 413 host->host_caps |= MMC_MODE_4BIT; 414 break; 415 case 1: 416 break; 417 default: 418 printf("Invalid \"bus-width\" value\n"); 419 return -EINVAL; 420 } 421 422 host->ops = &xenon_sdhci_ops; 423 424 host->max_clk = XENON_MMC_MAX_CLK; 425 ret = sdhci_setup_cfg(&plat->cfg, host, 0, 0); 426 if (ret) 427 return ret; 428 429 ret = sdhci_probe(dev); 430 if (ret) 431 return ret; 432 433 /* Enable parallel transfer */ 434 xenon_mmc_enable_parallel_tran(host, XENON_MMC_SLOT_ID_HYPERION); 435 436 /* Disable tuning functionality of this slot */ 437 xenon_mmc_disable_tuning(host, XENON_MMC_SLOT_ID_HYPERION); 438 439 /* Enable auto clock gating after init */ 440 xenon_mmc_set_acg(host, true); 441 442 xenon_mask_cmd_conflict_err(host); 443 444 return ret; 445 } 446 447 static int xenon_sdhci_ofdata_to_platdata(struct udevice *dev) 448 { 449 struct sdhci_host *host = dev_get_priv(dev); 450 struct xenon_sdhci_priv *priv = dev_get_priv(dev); 451 const char *name; 452 453 host->name = dev->name; 454 host->ioaddr = (void *)devfdt_get_addr(dev); 455 456 if (device_is_compatible(dev, "marvell,armada-3700-sdhci")) 457 priv->pad_ctrl_reg = (void *)devfdt_get_addr_index(dev, 1); 458 459 name = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), "marvell,pad-type", 460 NULL); 461 if (name) { 462 if (0 == strncmp(name, "sd", 2)) { 463 priv->pad_type = SOC_PAD_SD; 464 } else if (0 == strncmp(name, "fixed-1-8v", 10)) { 465 priv->pad_type = SOC_PAD_FIXED_1_8V; 466 } else { 467 printf("Unsupported SOC PHY PAD ctrl type %s\n", name); 468 return -EINVAL; 469 } 470 } 471 472 return 0; 473 } 474 475 static int xenon_sdhci_bind(struct udevice *dev) 476 { 477 struct xenon_sdhci_plat *plat = dev_get_platdata(dev); 478 479 return sdhci_bind(dev, &plat->mmc, &plat->cfg); 480 } 481 482 static const struct udevice_id xenon_sdhci_ids[] = { 483 { .compatible = "marvell,armada-8k-sdhci",}, 484 { .compatible = "marvell,armada-3700-sdhci",}, 485 { } 486 }; 487 488 U_BOOT_DRIVER(xenon_sdhci_drv) = { 489 .name = "xenon_sdhci", 490 .id = UCLASS_MMC, 491 .of_match = xenon_sdhci_ids, 492 .ofdata_to_platdata = xenon_sdhci_ofdata_to_platdata, 493 .ops = &sdhci_ops, 494 .bind = xenon_sdhci_bind, 495 .probe = xenon_sdhci_probe, 496 .priv_auto_alloc_size = sizeof(struct xenon_sdhci_priv), 497 .platdata_auto_alloc_size = sizeof(struct xenon_sdhci_plat), 498 }; 499