linux/drivers/mmc/host/mmci_qcom_dml.c
<<
>>
Prefs
   1/*
   2 *
   3 * Copyright (c) 2011, The Linux Foundation. All rights reserved.
   4 *
   5 * This program is free software; you can redistribute it and/or modify
   6 * it under the terms of the GNU General Public License version 2 and
   7 * only version 2 as published by the Free Software Foundation.
   8 *
   9 * This program is distributed in the hope that it will be useful,
  10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12 * GNU General Public License for more details.
  13 *
  14 */
  15#include <linux/of.h>
  16#include <linux/of_dma.h>
  17#include <linux/bitops.h>
  18#include <linux/mmc/host.h>
  19#include <linux/mmc/card.h>
  20#include "mmci.h"
  21
  22/* Registers */
  23#define DML_CONFIG                      0x00
  24#define PRODUCER_CRCI_MSK               GENMASK(1, 0)
  25#define PRODUCER_CRCI_DISABLE           0
  26#define PRODUCER_CRCI_X_SEL             BIT(0)
  27#define PRODUCER_CRCI_Y_SEL             BIT(1)
  28#define CONSUMER_CRCI_MSK               GENMASK(3, 2)
  29#define CONSUMER_CRCI_DISABLE           0
  30#define CONSUMER_CRCI_X_SEL             BIT(2)
  31#define CONSUMER_CRCI_Y_SEL             BIT(3)
  32#define PRODUCER_TRANS_END_EN           BIT(4)
  33#define BYPASS                          BIT(16)
  34#define DIRECT_MODE                     BIT(17)
  35#define INFINITE_CONS_TRANS             BIT(18)
  36
  37#define DML_SW_RESET                    0x08
  38#define DML_PRODUCER_START              0x0c
  39#define DML_CONSUMER_START              0x10
  40#define DML_PRODUCER_PIPE_LOGICAL_SIZE  0x14
  41#define DML_CONSUMER_PIPE_LOGICAL_SIZE  0x18
  42#define DML_PIPE_ID                     0x1c
  43#define PRODUCER_PIPE_ID_SHFT           0
  44#define PRODUCER_PIPE_ID_MSK            GENMASK(4, 0)
  45#define CONSUMER_PIPE_ID_SHFT           16
  46#define CONSUMER_PIPE_ID_MSK            GENMASK(20, 16)
  47
  48#define DML_PRODUCER_BAM_BLOCK_SIZE     0x24
  49#define DML_PRODUCER_BAM_TRANS_SIZE     0x28
  50
  51/* other definitions */
  52#define PRODUCER_PIPE_LOGICAL_SIZE      4096
  53#define CONSUMER_PIPE_LOGICAL_SIZE      4096
  54
  55#define DML_OFFSET                      0x800
  56
  57void dml_start_xfer(struct mmci_host *host, struct mmc_data *data)
  58{
  59        u32 config;
  60        void __iomem *base = host->base + DML_OFFSET;
  61
  62        if (data->flags & MMC_DATA_READ) {
  63                /* Read operation: configure DML for producer operation */
  64                /* Set producer CRCI-x and disable consumer CRCI */
  65                config = readl_relaxed(base + DML_CONFIG);
  66                config = (config & ~PRODUCER_CRCI_MSK) | PRODUCER_CRCI_X_SEL;
  67                config = (config & ~CONSUMER_CRCI_MSK) | CONSUMER_CRCI_DISABLE;
  68                writel_relaxed(config, base + DML_CONFIG);
  69
  70                /* Set the Producer BAM block size */
  71                writel_relaxed(data->blksz, base + DML_PRODUCER_BAM_BLOCK_SIZE);
  72
  73                /* Set Producer BAM Transaction size */
  74                writel_relaxed(data->blocks * data->blksz,
  75                               base + DML_PRODUCER_BAM_TRANS_SIZE);
  76                /* Set Producer Transaction End bit */
  77                config = readl_relaxed(base + DML_CONFIG);
  78                config |= PRODUCER_TRANS_END_EN;
  79                writel_relaxed(config, base + DML_CONFIG);
  80                /* Trigger producer */
  81                writel_relaxed(1, base + DML_PRODUCER_START);
  82        } else {
  83                /* Write operation: configure DML for consumer operation */
  84                /* Set consumer CRCI-x and disable producer CRCI*/
  85                config = readl_relaxed(base + DML_CONFIG);
  86                config = (config & ~CONSUMER_CRCI_MSK) | CONSUMER_CRCI_X_SEL;
  87                config = (config & ~PRODUCER_CRCI_MSK) | PRODUCER_CRCI_DISABLE;
  88                writel_relaxed(config, base + DML_CONFIG);
  89                /* Clear Producer Transaction End bit */
  90                config = readl_relaxed(base + DML_CONFIG);
  91                config &= ~PRODUCER_TRANS_END_EN;
  92                writel_relaxed(config, base + DML_CONFIG);
  93                /* Trigger consumer */
  94                writel_relaxed(1, base + DML_CONSUMER_START);
  95        }
  96
  97        /* make sure the dml is configured before dma is triggered */
  98        wmb();
  99}
 100
 101static int of_get_dml_pipe_index(struct device_node *np, const char *name)
 102{
 103        int index;
 104        struct of_phandle_args  dma_spec;
 105
 106        index = of_property_match_string(np, "dma-names", name);
 107
 108        if (index < 0)
 109                return -ENODEV;
 110
 111        if (of_parse_phandle_with_args(np, "dmas", "#dma-cells", index,
 112                                       &dma_spec))
 113                return -ENODEV;
 114
 115        if (dma_spec.args_count)
 116                return dma_spec.args[0];
 117
 118        return -ENODEV;
 119}
 120
 121/* Initialize the dml hardware connected to SD Card controller */
 122int dml_hw_init(struct mmci_host *host, struct device_node *np)
 123{
 124        u32 config;
 125        void __iomem *base;
 126        int consumer_id, producer_id;
 127
 128        consumer_id = of_get_dml_pipe_index(np, "tx");
 129        producer_id = of_get_dml_pipe_index(np, "rx");
 130
 131        if (producer_id < 0 || consumer_id < 0)
 132                return -ENODEV;
 133
 134        base = host->base + DML_OFFSET;
 135
 136        /* Reset the DML block */
 137        writel_relaxed(1, base + DML_SW_RESET);
 138
 139        /* Disable the producer and consumer CRCI */
 140        config = (PRODUCER_CRCI_DISABLE | CONSUMER_CRCI_DISABLE);
 141        /*
 142         * Disable the bypass mode. Bypass mode will only be used
 143         * if data transfer is to happen in PIO mode and don't
 144         * want the BAM interface to connect with SDCC-DML.
 145         */
 146        config &= ~BYPASS;
 147        /*
 148         * Disable direct mode as we don't DML to MASTER the AHB bus.
 149         * BAM connected with DML should MASTER the AHB bus.
 150         */
 151        config &= ~DIRECT_MODE;
 152        /*
 153         * Disable infinite mode transfer as we won't be doing any
 154         * infinite size data transfers. All data transfer will be
 155         * of finite data size.
 156         */
 157        config &= ~INFINITE_CONS_TRANS;
 158        writel_relaxed(config, base + DML_CONFIG);
 159
 160        /*
 161         * Initialize the logical BAM pipe size for producer
 162         * and consumer.
 163         */
 164        writel_relaxed(PRODUCER_PIPE_LOGICAL_SIZE,
 165                       base + DML_PRODUCER_PIPE_LOGICAL_SIZE);
 166        writel_relaxed(CONSUMER_PIPE_LOGICAL_SIZE,
 167                       base + DML_CONSUMER_PIPE_LOGICAL_SIZE);
 168
 169        /* Initialize Producer/consumer pipe id */
 170        writel_relaxed(producer_id | (consumer_id << CONSUMER_PIPE_ID_SHFT),
 171                       base + DML_PIPE_ID);
 172
 173        /* Make sure dml intialization is finished */
 174        mb();
 175
 176        return 0;
 177}
 178