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 XENON_MMC_MAX_CLK 400000000 98 99 enum soc_pad_ctrl_type { 100 SOC_PAD_SD, 101 SOC_PAD_FIXED_1_8V, 102 }; 103 104 struct xenon_sdhci_plat { 105 struct mmc_config cfg; 106 struct mmc mmc; 107 }; 108 109 struct xenon_sdhci_priv { 110 struct sdhci_host host; 111 112 u8 timing; 113 114 unsigned int clock; 115 116 void *pad_ctrl_reg; 117 int pad_type; 118 }; 119 120 static int xenon_mmc_phy_init(struct sdhci_host *host) 121 { 122 struct xenon_sdhci_priv *priv = host->mmc->priv; 123 u32 clock = priv->clock; 124 u32 time; 125 u32 var; 126 127 /* Enable QSP PHASE SELECT */ 128 var = sdhci_readl(host, EMMC_PHY_TIMING_ADJUST); 129 var |= SAMPL_INV_QSP_PHASE_SELECT; 130 if ((priv->timing == MMC_TIMING_UHS_SDR50) || 131 (priv->timing == MMC_TIMING_UHS_SDR25) || 132 (priv->timing == MMC_TIMING_UHS_SDR12) || 133 (priv->timing == MMC_TIMING_SD_HS) || 134 (priv->timing == MMC_TIMING_LEGACY)) 135 var |= EMMC_PHY_SLOW_MODE; 136 sdhci_writel(host, var, EMMC_PHY_TIMING_ADJUST); 137 138 /* Poll for host MMC PHY clock init to be stable */ 139 /* Wait up to 10ms */ 140 time = 100; 141 while (time--) { 142 var = sdhci_readl(host, SDHCI_CLOCK_CONTROL); 143 if (var & SDHCI_CLOCK_INT_STABLE) 144 break; 145 146 udelay(100); 147 } 148 149 if (time <= 0) { 150 error("Failed to enable MMC internal clock in time\n"); 151 return -ETIMEDOUT; 152 } 153 154 /* Init PHY */ 155 var = sdhci_readl(host, EMMC_PHY_TIMING_ADJUST); 156 var |= PHY_INITIALIZAION; 157 sdhci_writel(host, var, EMMC_PHY_TIMING_ADJUST); 158 159 if (clock == 0) { 160 /* Use the possibly slowest bus frequency value */ 161 clock = 100000; 162 } 163 164 /* Poll for host eMMC PHY init to complete */ 165 /* Wait up to 10ms */ 166 time = 100; 167 while (time--) { 168 var = sdhci_readl(host, EMMC_PHY_TIMING_ADJUST); 169 var &= PHY_INITIALIZAION; 170 if (!var) 171 break; 172 173 /* wait for host eMMC PHY init to complete */ 174 udelay(100); 175 } 176 177 if (time <= 0) { 178 error("Failed to init MMC PHY in time\n"); 179 return -ETIMEDOUT; 180 } 181 182 return 0; 183 } 184 185 #define ARMADA_3700_SOC_PAD_1_8V 0x1 186 #define ARMADA_3700_SOC_PAD_3_3V 0x0 187 188 static void armada_3700_soc_pad_voltage_set(struct sdhci_host *host) 189 { 190 struct xenon_sdhci_priv *priv = host->mmc->priv; 191 192 if (priv->pad_type == SOC_PAD_FIXED_1_8V) 193 writel(ARMADA_3700_SOC_PAD_1_8V, priv->pad_ctrl_reg); 194 else if (priv->pad_type == SOC_PAD_SD) 195 writel(ARMADA_3700_SOC_PAD_3_3V, priv->pad_ctrl_reg); 196 } 197 198 static void xenon_mmc_phy_set(struct sdhci_host *host) 199 { 200 struct xenon_sdhci_priv *priv = host->mmc->priv; 201 u32 var; 202 203 /* Setup pad, set bit[30], bit[28] and bits[26:24] */ 204 var = sdhci_readl(host, EMMC_PHY_PAD_CONTROL); 205 var |= AUTO_RECEN_CTRL | OEN_QSN | FC_QSP_RECEN | 206 FC_CMD_RECEN | FC_DQ_RECEN; 207 sdhci_writel(host, var, EMMC_PHY_PAD_CONTROL); 208 209 /* Set CMD and DQ Pull Up */ 210 var = sdhci_readl(host, EMMC_PHY_PAD_CONTROL1); 211 var |= (EMMC5_1_FC_CMD_PU | EMMC5_1_FC_DQ_PU); 212 var &= ~(EMMC5_1_FC_CMD_PD | EMMC5_1_FC_DQ_PD); 213 sdhci_writel(host, var, EMMC_PHY_PAD_CONTROL1); 214 215 /* 216 * If timing belongs to high speed, set bit[17] of 217 * EMMC_PHY_TIMING_ADJUST register 218 */ 219 if ((priv->timing == MMC_TIMING_MMC_HS400) || 220 (priv->timing == MMC_TIMING_MMC_HS200) || 221 (priv->timing == MMC_TIMING_UHS_SDR50) || 222 (priv->timing == MMC_TIMING_UHS_SDR104) || 223 (priv->timing == MMC_TIMING_UHS_DDR50) || 224 (priv->timing == MMC_TIMING_UHS_SDR25) || 225 (priv->timing == MMC_TIMING_MMC_DDR52)) { 226 var = sdhci_readl(host, EMMC_PHY_TIMING_ADJUST); 227 var |= OUTPUT_QSN_PHASE_SELECT; 228 sdhci_writel(host, var, EMMC_PHY_TIMING_ADJUST); 229 } 230 231 /* 232 * When setting EMMC_PHY_FUNC_CONTROL register, 233 * SD clock should be disabled 234 */ 235 var = sdhci_readl(host, SDHCI_CLOCK_CONTROL); 236 var &= ~SDHCI_CLOCK_CARD_EN; 237 sdhci_writew(host, var, SDHCI_CLOCK_CONTROL); 238 239 var = sdhci_readl(host, EMMC_PHY_FUNC_CONTROL); 240 if (mmc_card_ddr(host->mmc)) { 241 var |= (DQ_DDR_MODE_MASK << DQ_DDR_MODE_SHIFT) | CMD_DDR_MODE; 242 } else { 243 var &= ~((DQ_DDR_MODE_MASK << DQ_DDR_MODE_SHIFT) | 244 CMD_DDR_MODE); 245 } 246 sdhci_writel(host, var, EMMC_PHY_FUNC_CONTROL); 247 248 /* Enable bus clock */ 249 var = sdhci_readl(host, SDHCI_CLOCK_CONTROL); 250 var |= SDHCI_CLOCK_CARD_EN; 251 sdhci_writew(host, var, SDHCI_CLOCK_CONTROL); 252 253 xenon_mmc_phy_init(host); 254 } 255 256 /* Enable/Disable the Auto Clock Gating function of this slot */ 257 static void xenon_mmc_set_acg(struct sdhci_host *host, bool enable) 258 { 259 u32 var; 260 261 var = sdhci_readl(host, SDHC_SYS_OP_CTRL); 262 if (enable) 263 var &= ~AUTO_CLKGATE_DISABLE_MASK; 264 else 265 var |= AUTO_CLKGATE_DISABLE_MASK; 266 267 sdhci_writel(host, var, SDHC_SYS_OP_CTRL); 268 } 269 270 #define SLOT_MASK(slot) BIT(slot) 271 272 /* Enable specific slot */ 273 static void xenon_mmc_enable_slot(struct sdhci_host *host, u8 slot) 274 { 275 u32 var; 276 277 var = sdhci_readl(host, SDHC_SYS_OP_CTRL); 278 var |= SLOT_MASK(slot) << SLOT_ENABLE_SHIFT; 279 sdhci_writel(host, var, SDHC_SYS_OP_CTRL); 280 } 281 282 /* Enable Parallel Transfer Mode */ 283 static void xenon_mmc_enable_parallel_tran(struct sdhci_host *host, u8 slot) 284 { 285 u32 var; 286 287 var = sdhci_readl(host, SDHC_SYS_EXT_OP_CTRL); 288 var |= SLOT_MASK(slot); 289 sdhci_writel(host, var, SDHC_SYS_EXT_OP_CTRL); 290 } 291 292 static void xenon_mmc_disable_tuning(struct sdhci_host *host, u8 slot) 293 { 294 u32 var; 295 296 /* Clear the Re-Tuning Request functionality */ 297 var = sdhci_readl(host, SDHC_SLOT_RETUNING_REQ_CTRL); 298 var &= ~RETUNING_COMPATIBLE; 299 sdhci_writel(host, var, SDHC_SLOT_RETUNING_REQ_CTRL); 300 301 /* Clear the Re-tuning Event Signal Enable */ 302 var = sdhci_readl(host, SDHCI_SIGNAL_ENABLE); 303 var &= ~SDHCI_RETUNE_EVT_INTSIG; 304 sdhci_writel(host, var, SDHCI_SIGNAL_ENABLE); 305 } 306 307 /* Mask command conflict error */ 308 static void xenon_mask_cmd_conflict_err(struct sdhci_host *host) 309 { 310 u32 reg; 311 312 reg = sdhci_readl(host, SDHC_SYS_EXT_OP_CTRL); 313 reg |= MASK_CMD_CONFLICT_ERROR; 314 sdhci_writel(host, reg, SDHC_SYS_EXT_OP_CTRL); 315 } 316 317 /* Platform specific function for post set_ios configuration */ 318 static void xenon_sdhci_set_ios_post(struct sdhci_host *host) 319 { 320 struct xenon_sdhci_priv *priv = host->mmc->priv; 321 uint speed = host->mmc->clock; 322 int pwr_18v = 0; 323 324 if ((sdhci_readb(host, SDHCI_POWER_CONTROL) & ~SDHCI_POWER_ON) == 325 SDHCI_POWER_180) 326 pwr_18v = 1; 327 328 /* Set timing variable according to the configured speed */ 329 if (IS_SD(host->mmc)) { 330 /* SD/SDIO */ 331 if (pwr_18v) { 332 if (mmc_card_ddr(host->mmc)) 333 priv->timing = MMC_TIMING_UHS_DDR50; 334 else if (speed <= 25000000) 335 priv->timing = MMC_TIMING_UHS_SDR25; 336 else 337 priv->timing = MMC_TIMING_UHS_SDR50; 338 } else { 339 if (speed <= 25000000) 340 priv->timing = MMC_TIMING_LEGACY; 341 else 342 priv->timing = MMC_TIMING_SD_HS; 343 } 344 } else { 345 /* eMMC */ 346 if (mmc_card_ddr(host->mmc)) 347 priv->timing = MMC_TIMING_MMC_DDR52; 348 else if (speed <= 26000000) 349 priv->timing = MMC_TIMING_LEGACY; 350 else 351 priv->timing = MMC_TIMING_MMC_HS; 352 } 353 354 /* Re-init the PHY */ 355 xenon_mmc_phy_set(host); 356 } 357 358 /* Install a driver specific handler for post set_ios configuration */ 359 static const struct sdhci_ops xenon_sdhci_ops = { 360 .set_ios_post = xenon_sdhci_set_ios_post 361 }; 362 363 static int xenon_sdhci_probe(struct udevice *dev) 364 { 365 struct xenon_sdhci_plat *plat = dev_get_platdata(dev); 366 struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); 367 struct xenon_sdhci_priv *priv = dev_get_priv(dev); 368 struct sdhci_host *host = dev_get_priv(dev); 369 int ret; 370 371 host->mmc = &plat->mmc; 372 host->mmc->priv = host; 373 host->mmc->dev = dev; 374 upriv->mmc = host->mmc; 375 376 /* Set quirks */ 377 host->quirks = SDHCI_QUIRK_WAIT_SEND_CMD | SDHCI_QUIRK_32BIT_DMA_ADDR; 378 379 /* Set default timing */ 380 priv->timing = MMC_TIMING_LEGACY; 381 382 /* Disable auto clock gating during init */ 383 xenon_mmc_set_acg(host, false); 384 385 /* Enable slot */ 386 xenon_mmc_enable_slot(host, XENON_MMC_SLOT_ID_HYPERION); 387 388 /* 389 * Set default power on SoC PHY PAD register (currently only 390 * available on the Armada 3700) 391 */ 392 if (priv->pad_ctrl_reg) 393 armada_3700_soc_pad_voltage_set(host); 394 395 host->host_caps = MMC_MODE_HS | MMC_MODE_HS_52MHz | MMC_MODE_DDR_52MHz; 396 switch (fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), "bus-width", 397 1)) { 398 case 8: 399 host->host_caps |= MMC_MODE_8BIT; 400 break; 401 case 4: 402 host->host_caps |= MMC_MODE_4BIT; 403 break; 404 case 1: 405 break; 406 default: 407 printf("Invalid \"bus-width\" value\n"); 408 return -EINVAL; 409 } 410 411 host->ops = &xenon_sdhci_ops; 412 413 host->max_clk = XENON_MMC_MAX_CLK; 414 ret = sdhci_setup_cfg(&plat->cfg, host, 0, 0); 415 if (ret) 416 return ret; 417 418 ret = sdhci_probe(dev); 419 if (ret) 420 return ret; 421 422 /* Enable parallel transfer */ 423 xenon_mmc_enable_parallel_tran(host, XENON_MMC_SLOT_ID_HYPERION); 424 425 /* Disable tuning functionality of this slot */ 426 xenon_mmc_disable_tuning(host, XENON_MMC_SLOT_ID_HYPERION); 427 428 /* Enable auto clock gating after init */ 429 xenon_mmc_set_acg(host, true); 430 431 xenon_mask_cmd_conflict_err(host); 432 433 return ret; 434 } 435 436 static int xenon_sdhci_ofdata_to_platdata(struct udevice *dev) 437 { 438 struct sdhci_host *host = dev_get_priv(dev); 439 struct xenon_sdhci_priv *priv = dev_get_priv(dev); 440 const char *name; 441 442 host->name = dev->name; 443 host->ioaddr = (void *)devfdt_get_addr(dev); 444 445 if (device_is_compatible(dev, "marvell,armada-3700-sdhci")) 446 priv->pad_ctrl_reg = (void *)devfdt_get_addr_index(dev, 1); 447 448 name = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), "marvell,pad-type", 449 NULL); 450 if (name) { 451 if (0 == strncmp(name, "sd", 2)) { 452 priv->pad_type = SOC_PAD_SD; 453 } else if (0 == strncmp(name, "fixed-1-8v", 10)) { 454 priv->pad_type = SOC_PAD_FIXED_1_8V; 455 } else { 456 printf("Unsupported SOC PHY PAD ctrl type %s\n", name); 457 return -EINVAL; 458 } 459 } 460 461 return 0; 462 } 463 464 static int xenon_sdhci_bind(struct udevice *dev) 465 { 466 struct xenon_sdhci_plat *plat = dev_get_platdata(dev); 467 468 return sdhci_bind(dev, &plat->mmc, &plat->cfg); 469 } 470 471 static const struct udevice_id xenon_sdhci_ids[] = { 472 { .compatible = "marvell,armada-8k-sdhci",}, 473 { .compatible = "marvell,armada-3700-sdhci",}, 474 { } 475 }; 476 477 U_BOOT_DRIVER(xenon_sdhci_drv) = { 478 .name = "xenon_sdhci", 479 .id = UCLASS_MMC, 480 .of_match = xenon_sdhci_ids, 481 .ofdata_to_platdata = xenon_sdhci_ofdata_to_platdata, 482 .ops = &sdhci_ops, 483 .bind = xenon_sdhci_bind, 484 .probe = xenon_sdhci_probe, 485 .priv_auto_alloc_size = sizeof(struct xenon_sdhci_priv), 486 .platdata_auto_alloc_size = sizeof(struct xenon_sdhci_plat), 487 }; 488