linux/drivers/mmc/host/renesas_sdhi_internal_dmac.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * DMA support for Internal DMAC with SDHI SD/SDIO controller
   4 *
   5 * Copyright (C) 2016-19 Renesas Electronics Corporation
   6 * Copyright (C) 2016-17 Horms Solutions, Simon Horman
   7 * Copyright (C) 2018-19 Sang Engineering, Wolfram Sang
   8 */
   9
  10#include <linux/bitops.h>
  11#include <linux/device.h>
  12#include <linux/dma-mapping.h>
  13#include <linux/io-64-nonatomic-hi-lo.h>
  14#include <linux/mfd/tmio.h>
  15#include <linux/mmc/host.h>
  16#include <linux/mod_devicetable.h>
  17#include <linux/module.h>
  18#include <linux/pagemap.h>
  19#include <linux/scatterlist.h>
  20#include <linux/sys_soc.h>
  21
  22#include "renesas_sdhi.h"
  23#include "tmio_mmc.h"
  24
  25#define DM_CM_DTRAN_MODE        0x820
  26#define DM_CM_DTRAN_CTRL        0x828
  27#define DM_CM_RST               0x830
  28#define DM_CM_INFO1             0x840
  29#define DM_CM_INFO1_MASK        0x848
  30#define DM_CM_INFO2             0x850
  31#define DM_CM_INFO2_MASK        0x858
  32#define DM_DTRAN_ADDR           0x880
  33
  34/* DM_CM_DTRAN_MODE */
  35#define DTRAN_MODE_CH_NUM_CH0   0       /* "downstream" = for write commands */
  36#define DTRAN_MODE_CH_NUM_CH1   BIT(16) /* "upstream" = for read commands */
  37#define DTRAN_MODE_BUS_WIDTH    (BIT(5) | BIT(4))
  38#define DTRAN_MODE_ADDR_MODE    BIT(0)  /* 1 = Increment address, 0 = Fixed */
  39
  40/* DM_CM_DTRAN_CTRL */
  41#define DTRAN_CTRL_DM_START     BIT(0)
  42
  43/* DM_CM_RST */
  44#define RST_DTRANRST1           BIT(9)
  45#define RST_DTRANRST0           BIT(8)
  46#define RST_RESERVED_BITS       GENMASK_ULL(31, 0)
  47
  48/* DM_CM_INFO1 and DM_CM_INFO1_MASK */
  49#define INFO1_CLEAR             0
  50#define INFO1_MASK_CLEAR        GENMASK_ULL(31, 0)
  51#define INFO1_DTRANEND1         BIT(17)
  52#define INFO1_DTRANEND0         BIT(16)
  53
  54/* DM_CM_INFO2 and DM_CM_INFO2_MASK */
  55#define INFO2_MASK_CLEAR        GENMASK_ULL(31, 0)
  56#define INFO2_DTRANERR1         BIT(17)
  57#define INFO2_DTRANERR0         BIT(16)
  58
  59enum renesas_sdhi_dma_cookie {
  60        COOKIE_UNMAPPED,
  61        COOKIE_PRE_MAPPED,
  62        COOKIE_MAPPED,
  63};
  64
  65/*
  66 * Specification of this driver:
  67 * - host->chan_{rx,tx} will be used as a flag of enabling/disabling the dma
  68 * - Since this SDHI DMAC register set has 16 but 32-bit width, we
  69 *   need a custom accessor.
  70 */
  71
  72static unsigned long global_flags;
  73/*
  74 * Workaround for avoiding to use RX DMAC by multiple channels.
  75 * On R-Car H3 ES1.* and M3-W ES1.0, when multiple SDHI channels use
  76 * RX DMAC simultaneously, sometimes hundreds of bytes data are not
  77 * stored into the system memory even if the DMAC interrupt happened.
  78 * So, this driver then uses one RX DMAC channel only.
  79 */
  80#define SDHI_INTERNAL_DMAC_ONE_RX_ONLY  0
  81#define SDHI_INTERNAL_DMAC_RX_IN_USE    1
  82
  83/* RZ/A2 does not have the ADRR_MODE bit */
  84#define SDHI_INTERNAL_DMAC_ADDR_MODE_FIXED_ONLY 2
  85
  86/* Definitions for sampling clocks */
  87static struct renesas_sdhi_scc rcar_gen3_scc_taps[] = {
  88        {
  89                .clk_rate = 0,
  90                .tap = 0x00000300,
  91                .tap_hs400_4tap = 0x00000100,
  92        },
  93};
  94
  95static const struct renesas_sdhi_of_data of_rza2_compatible = {
  96        .tmio_flags     = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_CLK_ACTUAL |
  97                          TMIO_MMC_HAVE_CBSY,
  98        .tmio_ocr_mask  = MMC_VDD_32_33,
  99        .capabilities   = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ |
 100                          MMC_CAP_CMD23 | MMC_CAP_WAIT_WHILE_BUSY,
 101        .bus_shift      = 2,
 102        .scc_offset     = 0 - 0x1000,
 103        .taps           = rcar_gen3_scc_taps,
 104        .taps_num       = ARRAY_SIZE(rcar_gen3_scc_taps),
 105        /* DMAC can handle 32bit blk count but only 1 segment */
 106        .max_blk_count  = UINT_MAX / TMIO_MAX_BLK_SIZE,
 107        .max_segs       = 1,
 108};
 109
 110static const struct renesas_sdhi_of_data of_rcar_gen3_compatible = {
 111        .tmio_flags     = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_CLK_ACTUAL |
 112                          TMIO_MMC_HAVE_CBSY | TMIO_MMC_MIN_RCAR2,
 113        .capabilities   = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ |
 114                          MMC_CAP_CMD23 | MMC_CAP_WAIT_WHILE_BUSY,
 115        .capabilities2  = MMC_CAP2_NO_WRITE_PROTECT | MMC_CAP2_MERGE_CAPABLE,
 116        .bus_shift      = 2,
 117        .scc_offset     = 0x1000,
 118        .taps           = rcar_gen3_scc_taps,
 119        .taps_num       = ARRAY_SIZE(rcar_gen3_scc_taps),
 120        /* DMAC can handle 32bit blk count but only 1 segment */
 121        .max_blk_count  = UINT_MAX / TMIO_MAX_BLK_SIZE,
 122        .max_segs       = 1,
 123};
 124
 125static const struct of_device_id renesas_sdhi_internal_dmac_of_match[] = {
 126        { .compatible = "renesas,sdhi-r7s9210", .data = &of_rza2_compatible, },
 127        { .compatible = "renesas,sdhi-mmc-r8a77470", .data = &of_rcar_gen3_compatible, },
 128        { .compatible = "renesas,sdhi-r8a7795", .data = &of_rcar_gen3_compatible, },
 129        { .compatible = "renesas,sdhi-r8a7796", .data = &of_rcar_gen3_compatible, },
 130        { .compatible = "renesas,rcar-gen3-sdhi", .data = &of_rcar_gen3_compatible, },
 131        {},
 132};
 133MODULE_DEVICE_TABLE(of, renesas_sdhi_internal_dmac_of_match);
 134
 135static void
 136renesas_sdhi_internal_dmac_dm_write(struct tmio_mmc_host *host,
 137                                    int addr, u64 val)
 138{
 139        writeq(val, host->ctl + addr);
 140}
 141
 142static void
 143renesas_sdhi_internal_dmac_enable_dma(struct tmio_mmc_host *host, bool enable)
 144{
 145        struct renesas_sdhi *priv = host_to_priv(host);
 146
 147        if (!host->chan_tx || !host->chan_rx)
 148                return;
 149
 150        if (!enable)
 151                renesas_sdhi_internal_dmac_dm_write(host, DM_CM_INFO1,
 152                                                    INFO1_CLEAR);
 153
 154        if (priv->dma_priv.enable)
 155                priv->dma_priv.enable(host, enable);
 156}
 157
 158static void
 159renesas_sdhi_internal_dmac_abort_dma(struct tmio_mmc_host *host) {
 160        u64 val = RST_DTRANRST1 | RST_DTRANRST0;
 161
 162        renesas_sdhi_internal_dmac_enable_dma(host, false);
 163
 164        renesas_sdhi_internal_dmac_dm_write(host, DM_CM_RST,
 165                                            RST_RESERVED_BITS & ~val);
 166        renesas_sdhi_internal_dmac_dm_write(host, DM_CM_RST,
 167                                            RST_RESERVED_BITS | val);
 168
 169        clear_bit(SDHI_INTERNAL_DMAC_RX_IN_USE, &global_flags);
 170
 171        renesas_sdhi_internal_dmac_enable_dma(host, true);
 172}
 173
 174static void
 175renesas_sdhi_internal_dmac_dataend_dma(struct tmio_mmc_host *host) {
 176        struct renesas_sdhi *priv = host_to_priv(host);
 177
 178        tasklet_schedule(&priv->dma_priv.dma_complete);
 179}
 180
 181/*
 182 * renesas_sdhi_internal_dmac_map() will be called with two difference
 183 * sg pointers in two mmc_data by .pre_req(), but tmio host can have a single
 184 * sg_ptr only. So, renesas_sdhi_internal_dmac_{un}map() should use a sg
 185 * pointer in a mmc_data instead of host->sg_ptr.
 186 */
 187static void
 188renesas_sdhi_internal_dmac_unmap(struct tmio_mmc_host *host,
 189                                 struct mmc_data *data,
 190                                 enum renesas_sdhi_dma_cookie cookie)
 191{
 192        bool unmap = cookie == COOKIE_UNMAPPED ? (data->host_cookie != cookie) :
 193                                                 (data->host_cookie == cookie);
 194
 195        if (unmap) {
 196                dma_unmap_sg(&host->pdev->dev, data->sg, data->sg_len,
 197                             mmc_get_dma_dir(data));
 198                data->host_cookie = COOKIE_UNMAPPED;
 199        }
 200}
 201
 202static bool
 203renesas_sdhi_internal_dmac_map(struct tmio_mmc_host *host,
 204                               struct mmc_data *data,
 205                               enum renesas_sdhi_dma_cookie cookie)
 206{
 207        if (data->host_cookie == COOKIE_PRE_MAPPED)
 208                return true;
 209
 210        if (!dma_map_sg(&host->pdev->dev, data->sg, data->sg_len,
 211                            mmc_get_dma_dir(data)))
 212                return false;
 213
 214        data->host_cookie = cookie;
 215
 216        /* This DMAC cannot handle if buffer is not 128-bytes alignment */
 217        if (!IS_ALIGNED(sg_dma_address(data->sg), 128)) {
 218                renesas_sdhi_internal_dmac_unmap(host, data, cookie);
 219                return false;
 220        }
 221
 222        return true;
 223}
 224
 225static void
 226renesas_sdhi_internal_dmac_start_dma(struct tmio_mmc_host *host,
 227                                     struct mmc_data *data)
 228{
 229        struct scatterlist *sg = host->sg_ptr;
 230        u32 dtran_mode = DTRAN_MODE_BUS_WIDTH;
 231
 232        if (!test_bit(SDHI_INTERNAL_DMAC_ADDR_MODE_FIXED_ONLY, &global_flags))
 233                dtran_mode |= DTRAN_MODE_ADDR_MODE;
 234
 235        if (!renesas_sdhi_internal_dmac_map(host, data, COOKIE_MAPPED))
 236                goto force_pio;
 237
 238        if (data->flags & MMC_DATA_READ) {
 239                dtran_mode |= DTRAN_MODE_CH_NUM_CH1;
 240                if (test_bit(SDHI_INTERNAL_DMAC_ONE_RX_ONLY, &global_flags) &&
 241                    test_and_set_bit(SDHI_INTERNAL_DMAC_RX_IN_USE, &global_flags))
 242                        goto force_pio_with_unmap;
 243        } else {
 244                dtran_mode |= DTRAN_MODE_CH_NUM_CH0;
 245        }
 246
 247        renesas_sdhi_internal_dmac_enable_dma(host, true);
 248
 249        /* set dma parameters */
 250        renesas_sdhi_internal_dmac_dm_write(host, DM_CM_DTRAN_MODE,
 251                                            dtran_mode);
 252        renesas_sdhi_internal_dmac_dm_write(host, DM_DTRAN_ADDR,
 253                                            sg_dma_address(sg));
 254
 255        host->dma_on = true;
 256
 257        return;
 258
 259force_pio_with_unmap:
 260        renesas_sdhi_internal_dmac_unmap(host, data, COOKIE_UNMAPPED);
 261
 262force_pio:
 263        renesas_sdhi_internal_dmac_enable_dma(host, false);
 264}
 265
 266static void renesas_sdhi_internal_dmac_issue_tasklet_fn(unsigned long arg)
 267{
 268        struct tmio_mmc_host *host = (struct tmio_mmc_host *)arg;
 269
 270        tmio_mmc_enable_mmc_irqs(host, TMIO_STAT_DATAEND);
 271
 272        /* start the DMAC */
 273        renesas_sdhi_internal_dmac_dm_write(host, DM_CM_DTRAN_CTRL,
 274                                            DTRAN_CTRL_DM_START);
 275}
 276
 277static bool renesas_sdhi_internal_dmac_complete(struct tmio_mmc_host *host)
 278{
 279        enum dma_data_direction dir;
 280
 281        if (!host->dma_on)
 282                return false;
 283
 284        if (!host->data)
 285                return false;
 286
 287        if (host->data->flags & MMC_DATA_READ)
 288                dir = DMA_FROM_DEVICE;
 289        else
 290                dir = DMA_TO_DEVICE;
 291
 292        renesas_sdhi_internal_dmac_enable_dma(host, false);
 293        renesas_sdhi_internal_dmac_unmap(host, host->data, COOKIE_MAPPED);
 294
 295        if (dir == DMA_FROM_DEVICE)
 296                clear_bit(SDHI_INTERNAL_DMAC_RX_IN_USE, &global_flags);
 297
 298        host->dma_on = false;
 299
 300        return true;
 301}
 302
 303static void renesas_sdhi_internal_dmac_complete_tasklet_fn(unsigned long arg)
 304{
 305        struct tmio_mmc_host *host = (struct tmio_mmc_host *)arg;
 306
 307        spin_lock_irq(&host->lock);
 308        if (!renesas_sdhi_internal_dmac_complete(host))
 309                goto out;
 310
 311        tmio_mmc_do_data_irq(host);
 312out:
 313        spin_unlock_irq(&host->lock);
 314}
 315
 316static void renesas_sdhi_internal_dmac_end_dma(struct tmio_mmc_host *host)
 317{
 318        if (host->data)
 319                renesas_sdhi_internal_dmac_complete(host);
 320}
 321
 322static void renesas_sdhi_internal_dmac_post_req(struct mmc_host *mmc,
 323                                                struct mmc_request *mrq,
 324                                                int err)
 325{
 326        struct tmio_mmc_host *host = mmc_priv(mmc);
 327        struct mmc_data *data = mrq->data;
 328
 329        if (!data)
 330                return;
 331
 332        renesas_sdhi_internal_dmac_unmap(host, data, COOKIE_UNMAPPED);
 333}
 334
 335static void renesas_sdhi_internal_dmac_pre_req(struct mmc_host *mmc,
 336                                               struct mmc_request *mrq)
 337{
 338        struct tmio_mmc_host *host = mmc_priv(mmc);
 339        struct mmc_data *data = mrq->data;
 340
 341        if (!data)
 342                return;
 343
 344        data->host_cookie = COOKIE_UNMAPPED;
 345        renesas_sdhi_internal_dmac_map(host, data, COOKIE_PRE_MAPPED);
 346}
 347
 348static void
 349renesas_sdhi_internal_dmac_request_dma(struct tmio_mmc_host *host,
 350                                       struct tmio_mmc_data *pdata)
 351{
 352        struct renesas_sdhi *priv = host_to_priv(host);
 353
 354        /* Disable DMAC interrupts, we don't use them */
 355        renesas_sdhi_internal_dmac_dm_write(host, DM_CM_INFO1_MASK,
 356                                            INFO1_MASK_CLEAR);
 357        renesas_sdhi_internal_dmac_dm_write(host, DM_CM_INFO2_MASK,
 358                                            INFO2_MASK_CLEAR);
 359
 360        /* Each value is set to non-zero to assume "enabling" each DMA */
 361        host->chan_rx = host->chan_tx = (void *)0xdeadbeaf;
 362
 363        tasklet_init(&priv->dma_priv.dma_complete,
 364                     renesas_sdhi_internal_dmac_complete_tasklet_fn,
 365                     (unsigned long)host);
 366        tasklet_init(&host->dma_issue,
 367                     renesas_sdhi_internal_dmac_issue_tasklet_fn,
 368                     (unsigned long)host);
 369
 370        /* Add pre_req and post_req */
 371        host->ops.pre_req = renesas_sdhi_internal_dmac_pre_req;
 372        host->ops.post_req = renesas_sdhi_internal_dmac_post_req;
 373}
 374
 375static void
 376renesas_sdhi_internal_dmac_release_dma(struct tmio_mmc_host *host)
 377{
 378        /* Each value is set to zero to assume "disabling" each DMA */
 379        host->chan_rx = host->chan_tx = NULL;
 380}
 381
 382static const struct tmio_mmc_dma_ops renesas_sdhi_internal_dmac_dma_ops = {
 383        .start = renesas_sdhi_internal_dmac_start_dma,
 384        .enable = renesas_sdhi_internal_dmac_enable_dma,
 385        .request = renesas_sdhi_internal_dmac_request_dma,
 386        .release = renesas_sdhi_internal_dmac_release_dma,
 387        .abort = renesas_sdhi_internal_dmac_abort_dma,
 388        .dataend = renesas_sdhi_internal_dmac_dataend_dma,
 389        .end = renesas_sdhi_internal_dmac_end_dma,
 390};
 391
 392/*
 393 * Whitelist of specific R-Car Gen3 SoC ES versions to use this DMAC
 394 * implementation as others may use a different implementation.
 395 */
 396static const struct soc_device_attribute soc_dma_quirks[] = {
 397        { .soc_id = "r7s9210",
 398          .data = (void *)BIT(SDHI_INTERNAL_DMAC_ADDR_MODE_FIXED_ONLY) },
 399        { .soc_id = "r8a7795", .revision = "ES1.*",
 400          .data = (void *)BIT(SDHI_INTERNAL_DMAC_ONE_RX_ONLY) },
 401        { .soc_id = "r8a7796", .revision = "ES1.0",
 402          .data = (void *)BIT(SDHI_INTERNAL_DMAC_ONE_RX_ONLY) },
 403        { /* sentinel */ }
 404};
 405
 406static int renesas_sdhi_internal_dmac_probe(struct platform_device *pdev)
 407{
 408        const struct soc_device_attribute *soc = soc_device_match(soc_dma_quirks);
 409        struct device *dev = &pdev->dev;
 410
 411        if (soc)
 412                global_flags |= (unsigned long)soc->data;
 413
 414        /* value is max of SD_SECCNT. Confirmed by HW engineers */
 415        dma_set_max_seg_size(dev, 0xffffffff);
 416
 417        return renesas_sdhi_probe(pdev, &renesas_sdhi_internal_dmac_dma_ops);
 418}
 419
 420static const struct dev_pm_ops renesas_sdhi_internal_dmac_dev_pm_ops = {
 421        SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
 422                                pm_runtime_force_resume)
 423        SET_RUNTIME_PM_OPS(tmio_mmc_host_runtime_suspend,
 424                           tmio_mmc_host_runtime_resume,
 425                           NULL)
 426};
 427
 428static struct platform_driver renesas_internal_dmac_sdhi_driver = {
 429        .driver         = {
 430                .name   = "renesas_sdhi_internal_dmac",
 431                .probe_type = PROBE_PREFER_ASYNCHRONOUS,
 432                .pm     = &renesas_sdhi_internal_dmac_dev_pm_ops,
 433                .of_match_table = renesas_sdhi_internal_dmac_of_match,
 434        },
 435        .probe          = renesas_sdhi_internal_dmac_probe,
 436        .remove         = renesas_sdhi_remove,
 437};
 438
 439module_platform_driver(renesas_internal_dmac_sdhi_driver);
 440
 441MODULE_DESCRIPTION("Renesas SDHI driver for internal DMAC");
 442MODULE_AUTHOR("Yoshihiro Shimoda");
 443MODULE_LICENSE("GPL v2");
 444