]> Git Repo - linux.git/blob - drivers/mmc/host/mmci_qcom_dml.c
ARM: dts: imx7s: Enable SNVS power key according to board design
[linux.git] / drivers / mmc / host / mmci_qcom_dml.c
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
57 static int qcom_dma_start(struct mmci_host *host, unsigned int *datactrl)
58 {
59         u32 config;
60         void __iomem *base = host->base + DML_OFFSET;
61         struct mmc_data *data = host->data;
62         int ret = mmci_dmae_start(host, datactrl);
63
64         if (ret)
65                 return ret;
66
67         if (data->flags & MMC_DATA_READ) {
68                 /* Read operation: configure DML for producer operation */
69                 /* Set producer CRCI-x and disable consumer CRCI */
70                 config = readl_relaxed(base + DML_CONFIG);
71                 config = (config & ~PRODUCER_CRCI_MSK) | PRODUCER_CRCI_X_SEL;
72                 config = (config & ~CONSUMER_CRCI_MSK) | CONSUMER_CRCI_DISABLE;
73                 writel_relaxed(config, base + DML_CONFIG);
74
75                 /* Set the Producer BAM block size */
76                 writel_relaxed(data->blksz, base + DML_PRODUCER_BAM_BLOCK_SIZE);
77
78                 /* Set Producer BAM Transaction size */
79                 writel_relaxed(data->blocks * data->blksz,
80                                base + DML_PRODUCER_BAM_TRANS_SIZE);
81                 /* Set Producer Transaction End bit */
82                 config = readl_relaxed(base + DML_CONFIG);
83                 config |= PRODUCER_TRANS_END_EN;
84                 writel_relaxed(config, base + DML_CONFIG);
85                 /* Trigger producer */
86                 writel_relaxed(1, base + DML_PRODUCER_START);
87         } else {
88                 /* Write operation: configure DML for consumer operation */
89                 /* Set consumer CRCI-x and disable producer CRCI*/
90                 config = readl_relaxed(base + DML_CONFIG);
91                 config = (config & ~CONSUMER_CRCI_MSK) | CONSUMER_CRCI_X_SEL;
92                 config = (config & ~PRODUCER_CRCI_MSK) | PRODUCER_CRCI_DISABLE;
93                 writel_relaxed(config, base + DML_CONFIG);
94                 /* Clear Producer Transaction End bit */
95                 config = readl_relaxed(base + DML_CONFIG);
96                 config &= ~PRODUCER_TRANS_END_EN;
97                 writel_relaxed(config, base + DML_CONFIG);
98                 /* Trigger consumer */
99                 writel_relaxed(1, base + DML_CONSUMER_START);
100         }
101
102         /* make sure the dml is configured before dma is triggered */
103         wmb();
104         return 0;
105 }
106
107 static int of_get_dml_pipe_index(struct device_node *np, const char *name)
108 {
109         int index;
110         struct of_phandle_args  dma_spec;
111
112         index = of_property_match_string(np, "dma-names", name);
113
114         if (index < 0)
115                 return -ENODEV;
116
117         if (of_parse_phandle_with_args(np, "dmas", "#dma-cells", index,
118                                        &dma_spec))
119                 return -ENODEV;
120
121         if (dma_spec.args_count)
122                 return dma_spec.args[0];
123
124         return -ENODEV;
125 }
126
127 /* Initialize the dml hardware connected to SD Card controller */
128 static int qcom_dma_setup(struct mmci_host *host)
129 {
130         u32 config;
131         void __iomem *base;
132         int consumer_id, producer_id;
133         struct device_node *np = host->mmc->parent->of_node;
134
135         if (mmci_dmae_setup(host))
136                 return -EINVAL;
137
138         consumer_id = of_get_dml_pipe_index(np, "tx");
139         producer_id = of_get_dml_pipe_index(np, "rx");
140
141         if (producer_id < 0 || consumer_id < 0) {
142                 mmci_dmae_release(host);
143                 return -EINVAL;
144         }
145
146         base = host->base + DML_OFFSET;
147
148         /* Reset the DML block */
149         writel_relaxed(1, base + DML_SW_RESET);
150
151         /* Disable the producer and consumer CRCI */
152         config = (PRODUCER_CRCI_DISABLE | CONSUMER_CRCI_DISABLE);
153         /*
154          * Disable the bypass mode. Bypass mode will only be used
155          * if data transfer is to happen in PIO mode and don't
156          * want the BAM interface to connect with SDCC-DML.
157          */
158         config &= ~BYPASS;
159         /*
160          * Disable direct mode as we don't DML to MASTER the AHB bus.
161          * BAM connected with DML should MASTER the AHB bus.
162          */
163         config &= ~DIRECT_MODE;
164         /*
165          * Disable infinite mode transfer as we won't be doing any
166          * infinite size data transfers. All data transfer will be
167          * of finite data size.
168          */
169         config &= ~INFINITE_CONS_TRANS;
170         writel_relaxed(config, base + DML_CONFIG);
171
172         /*
173          * Initialize the logical BAM pipe size for producer
174          * and consumer.
175          */
176         writel_relaxed(PRODUCER_PIPE_LOGICAL_SIZE,
177                        base + DML_PRODUCER_PIPE_LOGICAL_SIZE);
178         writel_relaxed(CONSUMER_PIPE_LOGICAL_SIZE,
179                        base + DML_CONSUMER_PIPE_LOGICAL_SIZE);
180
181         /* Initialize Producer/consumer pipe id */
182         writel_relaxed(producer_id | (consumer_id << CONSUMER_PIPE_ID_SHFT),
183                        base + DML_PIPE_ID);
184
185         /* Make sure dml initialization is finished */
186         mb();
187
188         return 0;
189 }
190
191 static u32 qcom_get_dctrl_cfg(struct mmci_host *host)
192 {
193         return MCI_DPSM_ENABLE | (host->data->blksz << 4);
194 }
195
196 static struct mmci_host_ops qcom_variant_ops = {
197         .prep_data = mmci_dmae_prep_data,
198         .unprep_data = mmci_dmae_unprep_data,
199         .get_datactrl_cfg = qcom_get_dctrl_cfg,
200         .get_next_data = mmci_dmae_get_next_data,
201         .dma_setup = qcom_dma_setup,
202         .dma_release = mmci_dmae_release,
203         .dma_start = qcom_dma_start,
204         .dma_finalize = mmci_dmae_finalize,
205         .dma_error = mmci_dmae_error,
206 };
207
208 void qcom_variant_init(struct mmci_host *host)
209 {
210         host->ops = &qcom_variant_ops;
211 }
This page took 0.044787 seconds and 4 git commands to generate.