1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Driver for Synopsys DesignWare Cores Mobile Storage Host Controller 4 * 5 * Copyright (C) 2018 Synaptics Incorporated 6 * 7 * Author: Jisheng Zhang <jszhang@kernel.org> 8 */ 9 10#include <linux/clk.h> 11#include <linux/dma-mapping.h> 12#include <linux/iopoll.h> 13#include <linux/kernel.h> 14#include <linux/module.h> 15#include <linux/of.h> 16#include <linux/of_device.h> 17#include <linux/pm_runtime.h> 18#include <linux/sizes.h> 19 20#include "sdhci-pltfm.h" 21 22#define SDHCI_DWCMSHC_ARG2_STUFF GENMASK(31, 16) 23 24/* DWCMSHC specific Mode Select value */ 25#define DWCMSHC_CTRL_HS400 0x7 26 27#define DWCMSHC_VER_ID 0x500 28#define DWCMSHC_VER_TYPE 0x504 29#define DWCMSHC_HOST_CTRL3 0x508 30#define DWCMSHC_EMMC_CONTROL 0x52c 31#define DWCMSHC_EMMC_ATCTRL 0x540 32 33/* Rockchip specific Registers */ 34#define DWCMSHC_EMMC_DLL_CTRL 0x800 35#define DWCMSHC_EMMC_DLL_RXCLK 0x804 36#define DWCMSHC_EMMC_DLL_TXCLK 0x808 37#define DWCMSHC_EMMC_DLL_STRBIN 0x80c 38#define DWCMSHC_EMMC_DLL_STATUS0 0x840 39#define DWCMSHC_EMMC_DLL_START BIT(0) 40#define DWCMSHC_EMMC_DLL_RXCLK_SRCSEL 29 41#define DWCMSHC_EMMC_DLL_START_POINT 16 42#define DWCMSHC_EMMC_DLL_INC 8 43#define DWCMSHC_EMMC_DLL_DLYENA BIT(27) 44#define DLL_TXCLK_TAPNUM_DEFAULT 0x10 45#define DLL_STRBIN_TAPNUM_DEFAULT 0x8 46#define DLL_TXCLK_TAPNUM_FROM_SW BIT(24) 47#define DLL_STRBIN_TAPNUM_FROM_SW BIT(24) 48#define DWCMSHC_EMMC_DLL_LOCKED BIT(8) 49#define DWCMSHC_EMMC_DLL_TIMEOUT BIT(9) 50#define DLL_RXCLK_NO_INVERTER 1 51#define DLL_RXCLK_INVERTER 0 52#define DWCMSHC_ENHANCED_STROBE BIT(8) 53#define DLL_LOCK_WO_TMOUT(x) \ 54 ((((x)&DWCMSHC_EMMC_DLL_LOCKED) == DWCMSHC_EMMC_DLL_LOCKED) && (((x)&DWCMSHC_EMMC_DLL_TIMEOUT) == 0)) 55#define ROCKCHIP_MAX_CLKS 3 56 57#define BOUNDARY_OK(addr, len) (((addr) | (SZ_128M - 1)) == (((addr) + (len)-1) | (SZ_128M - 1))) 58 59struct dwcmshc_priv { 60 struct clk *bus_clk; 61 62 /* Rockchip specified optional clocks */ 63 struct clk_bulk_data rockchip_clks[ROCKCHIP_MAX_CLKS]; 64 int txclk_tapnum; 65 unsigned int actual_clk; 66}; 67 68/* 69 * If DMA addr spans 128MB boundary, we split the DMA transfer into two 70 * so that each DMA transfer doesn't exceed the boundary. 71 */ 72static void dwcmshc_adma_write_desc(struct sdhci_host *host, void **desc, dma_addr_t addr, int len, unsigned int cmd) 73{ 74 int tmplen, offset; 75 76 if (likely(!len || BOUNDARY_OK(addr, len))) { 77 sdhci_adma_write_desc(host, desc, addr, len, cmd); 78 return; 79 } 80 81 offset = addr & (SZ_128M - 1); 82 tmplen = SZ_128M - offset; 83 sdhci_adma_write_desc(host, desc, addr, tmplen, cmd); 84 85 addr += tmplen; 86 len -= tmplen; 87 sdhci_adma_write_desc(host, desc, addr, len, cmd); 88} 89 90static void dwcmshc_check_auto_cmd23(struct mmc_host *mmc, struct mmc_request *mrq) 91{ 92 struct sdhci_host *host = mmc_priv(mmc); 93 94 /* 95 * No matter V4 is enabled or not, ARGUMENT2 register is 32-bit 96 * block count register which doesn't support stuff bits of 97 * CMD23 argument on dwcmsch host controller. 98 */ 99 if (mrq->sbc && (mrq->sbc->arg & SDHCI_DWCMSHC_ARG2_STUFF)) { 100 host->flags &= ~SDHCI_AUTO_CMD23; 101 } else { 102 host->flags |= SDHCI_AUTO_CMD23; 103 } 104} 105 106static void dwcmshc_request(struct mmc_host *mmc, struct mmc_request *mrq) 107{ 108 dwcmshc_check_auto_cmd23(mmc, mrq); 109 110 sdhci_request(mmc, mrq); 111} 112 113static void dwcmshc_set_uhs_signaling(struct sdhci_host *host, unsigned int timing) 114{ 115 u16 ctrl_2; 116 117 ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2); 118 /* Select Bus Speed Mode for host */ 119 ctrl_2 &= ~SDHCI_CTRL_UHS_MASK; 120 if ((timing == MMC_TIMING_MMC_HS200) || (timing == MMC_TIMING_UHS_SDR104)) { 121 ctrl_2 |= SDHCI_CTRL_UHS_SDR104; 122 } else if (timing == MMC_TIMING_UHS_SDR12) { 123 ctrl_2 |= SDHCI_CTRL_UHS_SDR12; 124 } else if ((timing == MMC_TIMING_UHS_SDR25) || (timing == MMC_TIMING_MMC_HS)) { 125 ctrl_2 |= SDHCI_CTRL_UHS_SDR25; 126 } else if (timing == MMC_TIMING_UHS_SDR50) { 127 ctrl_2 |= SDHCI_CTRL_UHS_SDR50; 128 } else if ((timing == MMC_TIMING_UHS_DDR50) || (timing == MMC_TIMING_MMC_DDR52)) { 129 ctrl_2 |= SDHCI_CTRL_UHS_DDR50; 130 } else if (timing == MMC_TIMING_MMC_HS400) { 131 ctrl_2 |= DWCMSHC_CTRL_HS400; 132 } 133 sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2); 134} 135 136static void dwcmshc_hs400_enhanced_strobe(struct mmc_host *mmc, struct mmc_ios *ios) 137{ 138 u32 vendor; 139 struct sdhci_host *host = mmc_priv(mmc); 140 141 vendor = sdhci_readl(host, DWCMSHC_EMMC_CONTROL); 142 if (ios->enhanced_strobe) { 143 vendor |= DWCMSHC_ENHANCED_STROBE; 144 } else { 145 vendor &= ~DWCMSHC_ENHANCED_STROBE; 146 } 147 148 sdhci_writel(host, vendor, DWCMSHC_EMMC_CONTROL); 149} 150 151static void dwcmshc_rk_set_clock(struct sdhci_host *host, unsigned int clock) 152{ 153 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 154 struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host); 155 u32 txclk_tapnum = DLL_TXCLK_TAPNUM_DEFAULT, extra; 156 int err; 157 158 host->mmc->actual_clock = 0; 159 160 if (clock == 0) { 161 return; 162 } 163 164 /* Rockchip platform only support 375KHz for identify mode */ 165 if (clock <= 0x61a80) { 166 clock = 0x5b8d8; 167 } 168 169 err = clk_set_rate(pltfm_host->clk, clock); 170 if (err) { 171 dev_err(mmc_dev(host->mmc), "fail to set clock %d", clock); 172 } 173 174 sdhci_set_clock(host, clock); 175 176 /* Disable cmd conflict check */ 177 extra = sdhci_readl(host, DWCMSHC_HOST_CTRL3); 178 extra &= ~BIT(0); 179 sdhci_writel(host, extra, DWCMSHC_HOST_CTRL3); 180 181 if (clock <= 0x3197500) { 182 /* Disable DLL and reset both of sample and drive clock */ 183 sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_CTRL); 184 sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_RXCLK); 185 sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_TXCLK); 186 return; 187 } 188 189 /* Reset DLL */ 190 sdhci_writel(host, BIT(1), DWCMSHC_EMMC_DLL_CTRL); 191 udelay(1); 192 sdhci_writel(host, 0x0, DWCMSHC_EMMC_DLL_CTRL); 193 194 /* 195 * We shouldn't set DLL_RXCLK_NO_INVERTER for identify mode but 196 * we must set it in higher speed mode. 197 */ 198 extra = DWCMSHC_EMMC_DLL_DLYENA | DLL_RXCLK_NO_INVERTER << DWCMSHC_EMMC_DLL_RXCLK_SRCSEL; 199 200 sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_RXCLK); 201 202 /* Init DLL settings */ 203 extra = 0x5 << DWCMSHC_EMMC_DLL_START_POINT | 0x2 << DWCMSHC_EMMC_DLL_INC | DWCMSHC_EMMC_DLL_START; 204 sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_CTRL); 205 err = readl_poll_timeout(host->ioaddr + DWCMSHC_EMMC_DLL_STATUS0, extra, DLL_LOCK_WO_TMOUT(extra), 1, 206 0x1f4 * USEC_PER_MSEC); 207 if (err) { 208 dev_err(mmc_dev(host->mmc), "DLL lock timeout!\n"); 209 return; 210 } 211 212 extra = 0x1 << 0x10 | /* tune clock stop en */ 213 0x2 << 0x11 | /* pre-change delay */ 214 0x3 << 0x13; /* post-change delay */ 215 sdhci_writel(host, extra, DWCMSHC_EMMC_ATCTRL); 216 217 if (host->mmc->ios.timing == MMC_TIMING_MMC_HS200 || host->mmc->ios.timing == MMC_TIMING_MMC_HS400) { 218 txclk_tapnum = priv->txclk_tapnum; 219 } 220 221 extra = DWCMSHC_EMMC_DLL_DLYENA | DLL_TXCLK_TAPNUM_FROM_SW | txclk_tapnum; 222 sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_TXCLK); 223 224 extra = DWCMSHC_EMMC_DLL_DLYENA | DLL_STRBIN_TAPNUM_DEFAULT | DLL_STRBIN_TAPNUM_FROM_SW; 225 sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_STRBIN); 226} 227 228static const struct sdhci_ops sdhci_dwcmshc_ops = { 229 .set_clock = sdhci_set_clock, 230 .set_bus_width = sdhci_set_bus_width, 231 .set_uhs_signaling = dwcmshc_set_uhs_signaling, 232 .get_max_clock = sdhci_pltfm_clk_get_max_clock, 233 .reset = sdhci_reset, 234 .adma_write_desc = dwcmshc_adma_write_desc, 235}; 236 237static const struct sdhci_ops sdhci_dwcmshc_rk_ops = { 238 .set_clock = dwcmshc_rk_set_clock, 239 .set_bus_width = sdhci_set_bus_width, 240 .set_uhs_signaling = dwcmshc_set_uhs_signaling, 241 .get_max_clock = sdhci_pltfm_clk_get_max_clock, 242 .reset = sdhci_reset, 243 .adma_write_desc = dwcmshc_adma_write_desc, 244}; 245 246static const struct sdhci_pltfm_data sdhci_dwcmshc_pdata = { 247 .ops = &sdhci_dwcmshc_ops, 248 .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, 249 .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN, 250}; 251 252static const struct sdhci_pltfm_data sdhci_dwcmshc_rk_pdata = { 253 .ops = &sdhci_dwcmshc_rk_ops, 254 .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN | SDHCI_QUIRK_BROKEN_TIMEOUT_VAL, 255 .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN, 256}; 257 258static int rockchip_pltf_init(struct sdhci_host *host, struct dwcmshc_priv *priv) 259{ 260 int err; 261 262 priv->rockchip_clks[0x0].id = "axi"; 263 priv->rockchip_clks[0x1].id = "block"; 264 priv->rockchip_clks[0x2].id = "timer"; 265 err = devm_clk_bulk_get_optional(mmc_dev(host->mmc), ROCKCHIP_MAX_CLKS, priv->rockchip_clks); 266 if (err) { 267 dev_err(mmc_dev(host->mmc), "failed to get clocks %d\n", err); 268 return err; 269 } 270 271 err = clk_bulk_prepare_enable(ROCKCHIP_MAX_CLKS, priv->rockchip_clks); 272 if (err) { 273 dev_err(mmc_dev(host->mmc), "failed to enable clocks %d\n", err); 274 return err; 275 } 276 277 if (of_property_read_u32(mmc_dev(host->mmc)->of_node, "rockchip,txclk-tapnum", &priv->txclk_tapnum)) { 278 priv->txclk_tapnum = DLL_TXCLK_TAPNUM_DEFAULT; 279 } 280 281 /* Disable cmd conflict check */ 282 sdhci_writel(host, 0x0, DWCMSHC_HOST_CTRL3); 283 /* Reset previous settings */ 284 sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_TXCLK); 285 sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_STRBIN); 286 return 0; 287} 288 289static const struct of_device_id sdhci_dwcmshc_dt_ids[] = { 290 { 291 .compatible = "snps,dwcmshc-sdhci", 292 .data = &sdhci_dwcmshc_pdata, 293 }, 294 { 295 .compatible = "rockchip,dwcmshc-sdhci", 296 .data = &sdhci_dwcmshc_rk_pdata, 297 }, 298 {}, 299}; 300 301static int dwcmshc_probe(struct platform_device *pdev) 302{ 303 struct sdhci_pltfm_host *pltfm_host; 304 struct sdhci_host *host; 305 struct dwcmshc_priv *priv; 306 const struct sdhci_pltfm_data *pltfm_data; 307 int err; 308 u32 extra; 309 310 pltfm_data = of_device_get_match_data(&pdev->dev); 311 if (!pltfm_data) { 312 dev_err(&pdev->dev, "Error: No device match data found\n"); 313 return -ENODEV; 314 } 315 316 host = sdhci_pltfm_init(pdev, pltfm_data, sizeof(struct dwcmshc_priv)); 317 if (IS_ERR(host)) { 318 return PTR_ERR(host); 319 } 320 321 /* 322 * extra adma table cnt for cross 128M boundary handling. 323 */ 324 extra = DIV_ROUND_UP_ULL(dma_get_required_mask(&pdev->dev), SZ_128M); 325 if (extra > SDHCI_MAX_SEGS) { 326 extra = SDHCI_MAX_SEGS; 327 } 328 host->adma_table_cnt += extra; 329 330 pltfm_host = sdhci_priv(host); 331 priv = sdhci_pltfm_priv(pltfm_host); 332 333 pltfm_host->clk = devm_clk_get(&pdev->dev, "core"); 334 if (IS_ERR(pltfm_host->clk)) { 335 err = PTR_ERR(pltfm_host->clk); 336 dev_err(&pdev->dev, "failed to get core clk: %d\n", err); 337 goto free_pltfm; 338 } 339 err = clk_prepare_enable(pltfm_host->clk); 340 if (err) { 341 goto free_pltfm; 342 } 343 344 priv->bus_clk = devm_clk_get(&pdev->dev, "bus"); 345 if (!IS_ERR(priv->bus_clk)) { 346 clk_prepare_enable(priv->bus_clk); 347 } 348 349 err = mmc_of_parse(host->mmc); 350 if (err) { 351 goto err_clk; 352 } 353 354 sdhci_get_of_property(pdev); 355 356 host->mmc_host_ops.request = dwcmshc_request; 357 host->mmc_host_ops.hs400_enhanced_strobe = dwcmshc_hs400_enhanced_strobe; 358 359 if (pltfm_data == &sdhci_dwcmshc_rk_pdata) { 360 err = rockchip_pltf_init(host, priv); 361 if (err) { 362 goto err_clk; 363 } 364 } 365 366 err = sdhci_add_host(host); 367 if (err) { 368 goto err_clk; 369 } 370 371 pm_runtime_get_noresume(&pdev->dev); 372 pm_runtime_set_active(&pdev->dev); 373 pm_runtime_enable(&pdev->dev); 374 pm_runtime_set_autosuspend_delay(&pdev->dev, 0x32); 375 pm_runtime_use_autosuspend(&pdev->dev); 376 pm_runtime_put_autosuspend(&pdev->dev); 377 378 return 0; 379 380err_clk: 381 clk_disable_unprepare(pltfm_host->clk); 382 clk_disable_unprepare(priv->bus_clk); 383 clk_bulk_disable_unprepare(ROCKCHIP_MAX_CLKS, priv->rockchip_clks); 384free_pltfm: 385 sdhci_pltfm_free(pdev); 386 return err; 387} 388 389static int dwcmshc_remove(struct platform_device *pdev) 390{ 391 struct sdhci_host *host = platform_get_drvdata(pdev); 392 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 393 struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host); 394 395 sdhci_remove_host(host, 0); 396 397 clk_disable_unprepare(pltfm_host->clk); 398 clk_disable_unprepare(priv->bus_clk); 399 clk_bulk_disable_unprepare(ROCKCHIP_MAX_CLKS, priv->rockchip_clks); 400 401 sdhci_pltfm_free(pdev); 402 403 return 0; 404} 405 406#ifdef CONFIG_PM_SLEEP 407static int dwcmshc_suspend(struct device *dev) 408{ 409 struct sdhci_host *host = dev_get_drvdata(dev); 410 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 411 struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host); 412 int ret; 413 414 ret = sdhci_suspend_host(host); 415 if (ret) { 416 return ret; 417 } 418 419 clk_disable_unprepare(pltfm_host->clk); 420 if (!IS_ERR(priv->bus_clk)) { 421 clk_disable_unprepare(priv->bus_clk); 422 } 423 424 clk_bulk_disable_unprepare(ROCKCHIP_MAX_CLKS, priv->rockchip_clks); 425 return ret; 426} 427 428static int dwcmshc_resume(struct device *dev) 429{ 430 struct sdhci_host *host = dev_get_drvdata(dev); 431 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 432 struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host); 433 int ret; 434 435 ret = clk_prepare_enable(pltfm_host->clk); 436 if (ret) { 437 return ret; 438 } 439 440 if (!IS_ERR(priv->bus_clk)) { 441 ret = clk_prepare_enable(priv->bus_clk); 442 if (ret) { 443 return ret; 444 } 445 } 446 447 ret = clk_bulk_prepare_enable(ROCKCHIP_MAX_CLKS, priv->rockchip_clks); 448 if (ret) { 449 return ret; 450 } 451 452 return sdhci_resume_host(host); 453} 454 455static int dwcmshc_runtime_suspend(struct device *dev) 456{ 457 struct sdhci_host *host = dev_get_drvdata(dev); 458 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 459 struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host); 460 461 priv->actual_clk = host->mmc->actual_clock; 462 sdhci_set_clock(host, 0); 463 464 return 0; 465} 466 467static int dwcmshc_runtime_resume(struct device *dev) 468{ 469 struct sdhci_host *host = dev_get_drvdata(dev); 470 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 471 struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host); 472 473 sdhci_set_clock(host, priv->actual_clk); 474 475 return 0; 476} 477#endif 478 479static const struct dev_pm_ops dwcmshc_pmops = {SET_SYSTEM_SLEEP_PM_OPS( 480 dwcmshc_suspend, dwcmshc_resume) SET_RUNTIME_PM_OPS(dwcmshc_runtime_suspend, dwcmshc_runtime_resume, NULL)}; 481MODULE_DEVICE_TABLE(of, sdhci_dwcmshc_dt_ids); 482 483static struct platform_driver sdhci_dwcmshc_driver = { 484 .driver = 485 { 486 .name = "sdhci-dwcmshc", 487 .probe_type = PROBE_PREFER_ASYNCHRONOUS, 488 .of_match_table = sdhci_dwcmshc_dt_ids, 489 .pm = &dwcmshc_pmops, 490 }, 491 .probe = dwcmshc_probe, 492 .remove = dwcmshc_remove, 493}; 494module_platform_driver(sdhci_dwcmshc_driver); 495 496MODULE_DESCRIPTION("SDHCI platform driver for Synopsys DWC MSHC"); 497MODULE_AUTHOR("Jisheng Zhang <jszhang@kernel.org>"); 498MODULE_LICENSE("GPL v2"); 499