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