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