root/drivers/mmc/host/renesas_sdhi_internal_dmac.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. renesas_sdhi_internal_dmac_dm_write
  2. renesas_sdhi_internal_dmac_enable_dma
  3. renesas_sdhi_internal_dmac_abort_dma
  4. renesas_sdhi_internal_dmac_dataend_dma
  5. renesas_sdhi_internal_dmac_start_dma
  6. renesas_sdhi_internal_dmac_issue_tasklet_fn
  7. renesas_sdhi_internal_dmac_complete_tasklet_fn
  8. renesas_sdhi_internal_dmac_request_dma
  9. renesas_sdhi_internal_dmac_release_dma
  10. renesas_sdhi_internal_dmac_probe

   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 
  59 /*
  60  * Specification of this driver:
  61  * - host->chan_{rx,tx} will be used as a flag of enabling/disabling the dma
  62  * - Since this SDHI DMAC register set has 16 but 32-bit width, we
  63  *   need a custom accessor.
  64  */
  65 
  66 static unsigned long global_flags;
  67 /*
  68  * Workaround for avoiding to use RX DMAC by multiple channels.
  69  * On R-Car H3 ES1.* and M3-W ES1.0, when multiple SDHI channels use
  70  * RX DMAC simultaneously, sometimes hundreds of bytes data are not
  71  * stored into the system memory even if the DMAC interrupt happened.
  72  * So, this driver then uses one RX DMAC channel only.
  73  */
  74 #define SDHI_INTERNAL_DMAC_ONE_RX_ONLY  0
  75 #define SDHI_INTERNAL_DMAC_RX_IN_USE    1
  76 
  77 /* RZ/A2 does not have the ADRR_MODE bit */
  78 #define SDHI_INTERNAL_DMAC_ADDR_MODE_FIXED_ONLY 2
  79 
  80 /* Definitions for sampling clocks */
  81 static struct renesas_sdhi_scc rcar_gen3_scc_taps[] = {
  82         {
  83                 .clk_rate = 0,
  84                 .tap = 0x00000300,
  85                 .tap_hs400 = 0x00000704,
  86         },
  87 };
  88 
  89 static const struct renesas_sdhi_of_data of_rza2_compatible = {
  90         .tmio_flags     = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_CLK_ACTUAL |
  91                           TMIO_MMC_HAVE_CBSY,
  92         .tmio_ocr_mask  = MMC_VDD_32_33,
  93         .capabilities   = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ |
  94                           MMC_CAP_CMD23,
  95         .bus_shift      = 2,
  96         .scc_offset     = 0 - 0x1000,
  97         .taps           = rcar_gen3_scc_taps,
  98         .taps_num       = ARRAY_SIZE(rcar_gen3_scc_taps),
  99         /* DMAC can handle 32bit blk count but only 1 segment */
 100         .max_blk_count  = UINT_MAX / TMIO_MAX_BLK_SIZE,
 101         .max_segs       = 1,
 102 };
 103 
 104 static const struct renesas_sdhi_of_data of_rcar_gen3_compatible = {
 105         .tmio_flags     = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_CLK_ACTUAL |
 106                           TMIO_MMC_HAVE_CBSY | TMIO_MMC_MIN_RCAR2,
 107         .capabilities   = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ |
 108                           MMC_CAP_CMD23,
 109         .capabilities2  = MMC_CAP2_NO_WRITE_PROTECT | MMC_CAP2_MERGE_CAPABLE,
 110         .bus_shift      = 2,
 111         .scc_offset     = 0x1000,
 112         .taps           = rcar_gen3_scc_taps,
 113         .taps_num       = ARRAY_SIZE(rcar_gen3_scc_taps),
 114         /* DMAC can handle 32bit blk count but only 1 segment */
 115         .max_blk_count  = UINT_MAX / TMIO_MAX_BLK_SIZE,
 116         .max_segs       = 1,
 117 };
 118 
 119 static const struct of_device_id renesas_sdhi_internal_dmac_of_match[] = {
 120         { .compatible = "renesas,sdhi-r7s9210", .data = &of_rza2_compatible, },
 121         { .compatible = "renesas,sdhi-mmc-r8a77470", .data = &of_rcar_gen3_compatible, },
 122         { .compatible = "renesas,sdhi-r8a7795", .data = &of_rcar_gen3_compatible, },
 123         { .compatible = "renesas,sdhi-r8a7796", .data = &of_rcar_gen3_compatible, },
 124         { .compatible = "renesas,rcar-gen3-sdhi", .data = &of_rcar_gen3_compatible, },
 125         {},
 126 };
 127 MODULE_DEVICE_TABLE(of, renesas_sdhi_internal_dmac_of_match);
 128 
 129 static void
 130 renesas_sdhi_internal_dmac_dm_write(struct tmio_mmc_host *host,
 131                                     int addr, u64 val)
 132 {
 133         writeq(val, host->ctl + addr);
 134 }
 135 
 136 static void
 137 renesas_sdhi_internal_dmac_enable_dma(struct tmio_mmc_host *host, bool enable)
 138 {
 139         struct renesas_sdhi *priv = host_to_priv(host);
 140 
 141         if (!host->chan_tx || !host->chan_rx)
 142                 return;
 143 
 144         if (!enable)
 145                 renesas_sdhi_internal_dmac_dm_write(host, DM_CM_INFO1,
 146                                                     INFO1_CLEAR);
 147 
 148         if (priv->dma_priv.enable)
 149                 priv->dma_priv.enable(host, enable);
 150 }
 151 
 152 static void
 153 renesas_sdhi_internal_dmac_abort_dma(struct tmio_mmc_host *host) {
 154         u64 val = RST_DTRANRST1 | RST_DTRANRST0;
 155 
 156         renesas_sdhi_internal_dmac_enable_dma(host, false);
 157 
 158         renesas_sdhi_internal_dmac_dm_write(host, DM_CM_RST,
 159                                             RST_RESERVED_BITS & ~val);
 160         renesas_sdhi_internal_dmac_dm_write(host, DM_CM_RST,
 161                                             RST_RESERVED_BITS | val);
 162 
 163         clear_bit(SDHI_INTERNAL_DMAC_RX_IN_USE, &global_flags);
 164 
 165         renesas_sdhi_internal_dmac_enable_dma(host, true);
 166 }
 167 
 168 static void
 169 renesas_sdhi_internal_dmac_dataend_dma(struct tmio_mmc_host *host) {
 170         struct renesas_sdhi *priv = host_to_priv(host);
 171 
 172         tasklet_schedule(&priv->dma_priv.dma_complete);
 173 }
 174 
 175 static void
 176 renesas_sdhi_internal_dmac_start_dma(struct tmio_mmc_host *host,
 177                                      struct mmc_data *data)
 178 {
 179         struct scatterlist *sg = host->sg_ptr;
 180         u32 dtran_mode = DTRAN_MODE_BUS_WIDTH;
 181 
 182         if (!test_bit(SDHI_INTERNAL_DMAC_ADDR_MODE_FIXED_ONLY, &global_flags))
 183                 dtran_mode |= DTRAN_MODE_ADDR_MODE;
 184 
 185         if (!dma_map_sg(&host->pdev->dev, sg, host->sg_len,
 186                         mmc_get_dma_dir(data)))
 187                 goto force_pio;
 188 
 189         /* This DMAC cannot handle if buffer is not 8-bytes alignment */
 190         if (!IS_ALIGNED(sg_dma_address(sg), 8))
 191                 goto force_pio_with_unmap;
 192 
 193         if (data->flags & MMC_DATA_READ) {
 194                 dtran_mode |= DTRAN_MODE_CH_NUM_CH1;
 195                 if (test_bit(SDHI_INTERNAL_DMAC_ONE_RX_ONLY, &global_flags) &&
 196                     test_and_set_bit(SDHI_INTERNAL_DMAC_RX_IN_USE, &global_flags))
 197                         goto force_pio_with_unmap;
 198         } else {
 199                 dtran_mode |= DTRAN_MODE_CH_NUM_CH0;
 200         }
 201 
 202         renesas_sdhi_internal_dmac_enable_dma(host, true);
 203 
 204         /* set dma parameters */
 205         renesas_sdhi_internal_dmac_dm_write(host, DM_CM_DTRAN_MODE,
 206                                             dtran_mode);
 207         renesas_sdhi_internal_dmac_dm_write(host, DM_DTRAN_ADDR,
 208                                             sg_dma_address(sg));
 209 
 210         host->dma_on = true;
 211 
 212         return;
 213 
 214 force_pio_with_unmap:
 215         dma_unmap_sg(&host->pdev->dev, sg, host->sg_len, mmc_get_dma_dir(data));
 216 
 217 force_pio:
 218         renesas_sdhi_internal_dmac_enable_dma(host, false);
 219 }
 220 
 221 static void renesas_sdhi_internal_dmac_issue_tasklet_fn(unsigned long arg)
 222 {
 223         struct tmio_mmc_host *host = (struct tmio_mmc_host *)arg;
 224 
 225         tmio_mmc_enable_mmc_irqs(host, TMIO_STAT_DATAEND);
 226 
 227         /* start the DMAC */
 228         renesas_sdhi_internal_dmac_dm_write(host, DM_CM_DTRAN_CTRL,
 229                                             DTRAN_CTRL_DM_START);
 230 }
 231 
 232 static void renesas_sdhi_internal_dmac_complete_tasklet_fn(unsigned long arg)
 233 {
 234         struct tmio_mmc_host *host = (struct tmio_mmc_host *)arg;
 235         enum dma_data_direction dir;
 236 
 237         spin_lock_irq(&host->lock);
 238 
 239         if (!host->data)
 240                 goto out;
 241 
 242         if (host->data->flags & MMC_DATA_READ)
 243                 dir = DMA_FROM_DEVICE;
 244         else
 245                 dir = DMA_TO_DEVICE;
 246 
 247         renesas_sdhi_internal_dmac_enable_dma(host, false);
 248         dma_unmap_sg(&host->pdev->dev, host->sg_ptr, host->sg_len, dir);
 249 
 250         if (dir == DMA_FROM_DEVICE)
 251                 clear_bit(SDHI_INTERNAL_DMAC_RX_IN_USE, &global_flags);
 252 
 253         tmio_mmc_do_data_irq(host);
 254 out:
 255         spin_unlock_irq(&host->lock);
 256 }
 257 
 258 static void
 259 renesas_sdhi_internal_dmac_request_dma(struct tmio_mmc_host *host,
 260                                        struct tmio_mmc_data *pdata)
 261 {
 262         struct renesas_sdhi *priv = host_to_priv(host);
 263 
 264         /* Disable DMAC interrupts, we don't use them */
 265         renesas_sdhi_internal_dmac_dm_write(host, DM_CM_INFO1_MASK,
 266                                             INFO1_MASK_CLEAR);
 267         renesas_sdhi_internal_dmac_dm_write(host, DM_CM_INFO2_MASK,
 268                                             INFO2_MASK_CLEAR);
 269 
 270         /* Each value is set to non-zero to assume "enabling" each DMA */
 271         host->chan_rx = host->chan_tx = (void *)0xdeadbeaf;
 272 
 273         tasklet_init(&priv->dma_priv.dma_complete,
 274                      renesas_sdhi_internal_dmac_complete_tasklet_fn,
 275                      (unsigned long)host);
 276         tasklet_init(&host->dma_issue,
 277                      renesas_sdhi_internal_dmac_issue_tasklet_fn,
 278                      (unsigned long)host);
 279 }
 280 
 281 static void
 282 renesas_sdhi_internal_dmac_release_dma(struct tmio_mmc_host *host)
 283 {
 284         /* Each value is set to zero to assume "disabling" each DMA */
 285         host->chan_rx = host->chan_tx = NULL;
 286 }
 287 
 288 static const struct tmio_mmc_dma_ops renesas_sdhi_internal_dmac_dma_ops = {
 289         .start = renesas_sdhi_internal_dmac_start_dma,
 290         .enable = renesas_sdhi_internal_dmac_enable_dma,
 291         .request = renesas_sdhi_internal_dmac_request_dma,
 292         .release = renesas_sdhi_internal_dmac_release_dma,
 293         .abort = renesas_sdhi_internal_dmac_abort_dma,
 294         .dataend = renesas_sdhi_internal_dmac_dataend_dma,
 295 };
 296 
 297 /*
 298  * Whitelist of specific R-Car Gen3 SoC ES versions to use this DMAC
 299  * implementation as others may use a different implementation.
 300  */
 301 static const struct soc_device_attribute soc_whitelist[] = {
 302         /* specific ones */
 303         { .soc_id = "r7s9210",
 304           .data = (void *)BIT(SDHI_INTERNAL_DMAC_ADDR_MODE_FIXED_ONLY) },
 305         { .soc_id = "r8a7795", .revision = "ES1.*",
 306           .data = (void *)BIT(SDHI_INTERNAL_DMAC_ONE_RX_ONLY) },
 307         { .soc_id = "r8a7796", .revision = "ES1.0",
 308           .data = (void *)BIT(SDHI_INTERNAL_DMAC_ONE_RX_ONLY) },
 309         /* generic ones */
 310         { .soc_id = "r8a774a1" },
 311         { .soc_id = "r8a774c0" },
 312         { .soc_id = "r8a77470" },
 313         { .soc_id = "r8a7795" },
 314         { .soc_id = "r8a7796" },
 315         { .soc_id = "r8a77965" },
 316         { .soc_id = "r8a77970" },
 317         { .soc_id = "r8a77980" },
 318         { .soc_id = "r8a77990" },
 319         { .soc_id = "r8a77995" },
 320         { /* sentinel */ }
 321 };
 322 
 323 static int renesas_sdhi_internal_dmac_probe(struct platform_device *pdev)
 324 {
 325         const struct soc_device_attribute *soc = soc_device_match(soc_whitelist);
 326         struct device *dev = &pdev->dev;
 327 
 328         if (!soc)
 329                 return -ENODEV;
 330 
 331         global_flags |= (unsigned long)soc->data;
 332 
 333         dev->dma_parms = devm_kzalloc(dev, sizeof(*dev->dma_parms), GFP_KERNEL);
 334         if (!dev->dma_parms)
 335                 return -ENOMEM;
 336 
 337         /* value is max of SD_SECCNT. Confirmed by HW engineers */
 338         dma_set_max_seg_size(dev, 0xffffffff);
 339 
 340         return renesas_sdhi_probe(pdev, &renesas_sdhi_internal_dmac_dma_ops);
 341 }
 342 
 343 static const struct dev_pm_ops renesas_sdhi_internal_dmac_dev_pm_ops = {
 344         SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
 345                                 pm_runtime_force_resume)
 346         SET_RUNTIME_PM_OPS(tmio_mmc_host_runtime_suspend,
 347                            tmio_mmc_host_runtime_resume,
 348                            NULL)
 349 };
 350 
 351 static struct platform_driver renesas_internal_dmac_sdhi_driver = {
 352         .driver         = {
 353                 .name   = "renesas_sdhi_internal_dmac",
 354                 .pm     = &renesas_sdhi_internal_dmac_dev_pm_ops,
 355                 .of_match_table = renesas_sdhi_internal_dmac_of_match,
 356         },
 357         .probe          = renesas_sdhi_internal_dmac_probe,
 358         .remove         = renesas_sdhi_remove,
 359 };
 360 
 361 module_platform_driver(renesas_internal_dmac_sdhi_driver);
 362 
 363 MODULE_DESCRIPTION("Renesas SDHI driver for internal DMAC");
 364 MODULE_AUTHOR("Yoshihiro Shimoda");
 365 MODULE_LICENSE("GPL v2");

/* [<][>][^][v][top][bottom][index][help] */