20940514eb4418df1c0b9677f4de2af13a003e01
[openwrt/openwrt.git] / target / linux / ipq806x / patches-4.9 / 860-qcom-mtd-nand-Add-bam_dma-support-in-qcom_nand-drive.patch
1 From 074036f9de6b8c5fc642e8e2540950f6a35aa804 Mon Sep 17 00:00:00 2001
2 From: Ram Chandra Jangir <rjangir@codeaurora.org>
3 Date: Thu, 20 Apr 2017 10:31:10 +0530
4 Subject: [PATCH] qcom: mtd: nand: Add bam_dma support in qcom_nand driver
5
6 The current driver only support ADM DMA so this patch adds the
7 BAM DMA support in current NAND driver with compatible string
8 qcom,ebi2-nandc-bam.
9 Added bam channels and data buffers, NAND BAM uses 3 channels:
10 command, data tx and data rx, while ADM uses only single channel.
11 So this patch adds the BAM channel in device tree and using the
12 same in NAND driver allocation function.
13
14 Signed-off-by: Ram Chandra Jangir <rjangir@codeaurora.org>
15 ---
16 .../devicetree/bindings/mtd/qcom_nandc.txt | 69 +++++++--
17 drivers/mtd/nand/qcom_nandc.c | 160 +++++++++++++++++----
18 2 files changed, 190 insertions(+), 39 deletions(-)
19
20 --- a/Documentation/devicetree/bindings/mtd/qcom_nandc.txt
21 +++ b/Documentation/devicetree/bindings/mtd/qcom_nandc.txt
22 @@ -1,21 +1,26 @@
23 * Qualcomm NAND controller
24
25 Required properties:
26 -- compatible: should be "qcom,ipq806x-nand"
27 +- compatible: "qcom,ipq806x-nand" for IPQ8064 which uses
28 + ADM DMA.
29 + "qcom,ebi2-nand-bam" - nand drivers using BAM DMA
30 + like IPQ4019.
31 - reg: MMIO address range
32 - clocks: must contain core clock and always on clock
33 - clock-names: must contain "core" for the core clock and "aon" for the
34 always on clock
35 - dmas: DMA specifier, consisting of a phandle to the ADM DMA
36 - controller node and the channel number to be used for
37 - NAND. Refer to dma.txt and qcom_adm.txt for more details
38 -- dma-names: must be "rxtx"
39 -- qcom,cmd-crci: must contain the ADM command type CRCI block instance
40 - number specified for the NAND controller on the given
41 - platform
42 -- qcom,data-crci: must contain the ADM data type CRCI block instance
43 - number specified for the NAND controller on the given
44 - platform
45 + or BAM DMA controller node and the channel number to
46 + be used for NAND. Refer to dma.txt, qcom_adm.txt(ADM)
47 + and qcom_bam_dma.txt(BAM) for more details
48 +- dma-names: "rxtx" - ADM
49 + "tx", "rx", "cmd" - BAM
50 +- qcom,cmd-crci: Only required for ADM DMA. must contain the ADM command
51 + type CRCI block instance number specified for the NAND
52 + controller on the given platform.
53 +- qcom,data-crci: Only required for ADM DMA. must contain the ADM data
54 + type CRCI block instance number specified for the NAND
55 + controller on the given platform.
56 - #address-cells: <1> - subnodes give the chip-select number
57 - #size-cells: <0>
58
59 @@ -44,7 +49,7 @@ partition.txt for more detail.
60 Example:
61
62 nand@1ac00000 {
63 - compatible = "qcom,ebi2-nandc";
64 + compatible = "qcom,ipq806x-nand","qcom.qcom_nand";
65 reg = <0x1ac00000 0x800>;
66
67 clocks = <&gcc EBI2_CLK>,
68 @@ -58,6 +63,48 @@ nand@1ac00000 {
69
70 #address-cells = <1>;
71 #size-cells = <0>;
72 +
73 + nandcs@0 {
74 + compatible = "qcom,nandcs";
75 + reg = <0>;
76 +
77 + nand-ecc-strength = <4>;
78 + nand-ecc-step-size = <512>;
79 + nand-bus-width = <8>;
80 +
81 + partitions {
82 + compatible = "fixed-partitions";
83 + #address-cells = <1>;
84 + #size-cells = <1>;
85 +
86 + partition@0 {
87 + label = "boot-nand";
88 + reg = <0 0x58a0000>;
89 + };
90 +
91 + partition@58a0000 {
92 + label = "fs-nand";
93 + reg = <0x58a0000 0x4000000>;
94 + };
95 + };
96 + };
97 +};
98 +
99 +nand@79B0000 {
100 + compatible = "qcom,ebi2-nandc-bam";
101 + reg = <0x79B0000 0x1000>;
102 +
103 + clocks = <&gcc EBI2_CLK>,
104 + <&gcc EBI2_AON_CLK>;
105 + clock-names = "core", "aon";
106 +
107 + dmas = <&qpicbam 0>,
108 + <&qpicbam 1>,
109 + <&qpicbam 2>;
110 + dma-names = "tx", "rx", "cmd";
111 +
112 + #address-cells = <1>;
113 + #size-cells = <0>;
114
115 nandcs@0 {
116 compatible = "qcom,nandcs";
117 --- a/drivers/mtd/nand/qcom_nandc.c
118 +++ b/drivers/mtd/nand/qcom_nandc.c
119 @@ -226,6 +226,7 @@ struct nandc_regs {
120 * by upper layers directly
121 * @buf_size/count/start: markers for chip->read_buf/write_buf functions
122 * @reg_read_buf: local buffer for reading back registers via DMA
123 + * @reg_read_buf_phys: contains dma address for register read buffer
124 * @reg_read_pos: marker for data read in reg_read_buf
125 *
126 * @regs: a contiguous chunk of memory for DMA register
127 @@ -234,7 +235,10 @@ struct nandc_regs {
128 * @cmd1/vld: some fixed controller register values
129 * @ecc_modes: supported ECC modes by the current controller,
130 * initialized via DT match data
131 - */
132 + * @bch_enabled: flag to tell whether BCH or RS ECC mode is used
133 + * @dma_bam_enabled: flag to tell whether nand controller is using
134 + * bam dma
135 +*/
136 struct qcom_nand_controller {
137 struct nand_hw_control controller;
138 struct list_head host_list;
139 @@ -247,17 +251,28 @@ struct qcom_nand_controller {
140 struct clk *core_clk;
141 struct clk *aon_clk;
142
143 - struct dma_chan *chan;
144 - unsigned int cmd_crci;
145 - unsigned int data_crci;
146 struct list_head desc_list;
147 + union {
148 + struct {
149 + struct dma_chan *tx_chan;
150 + struct dma_chan *rx_chan;
151 + struct dma_chan *cmd_chan;
152 + };
153 + struct {
154 + struct dma_chan *chan;
155 + unsigned int cmd_crci;
156 + unsigned int data_crci;
157 + };
158 + };
159
160 u8 *data_buffer;
161 + bool dma_bam_enabled;
162 int buf_size;
163 int buf_count;
164 int buf_start;
165
166 __le32 *reg_read_buf;
167 + dma_addr_t reg_read_buf_phys;
168 int reg_read_pos;
169
170 struct nandc_regs *regs;
171 @@ -316,6 +331,17 @@ struct qcom_nand_host {
172 u32 clrreadstatus;
173 };
174
175 +/*
176 + * This data type corresponds to the nand driver data which will be used at
177 + * driver probe time
178 + * @ecc_modes - ecc mode for nand
179 + * @dma_bam_enabled - whether this driver is using bam
180 + */
181 +struct qcom_nand_driver_data {
182 + u32 ecc_modes;
183 + bool dma_bam_enabled;
184 +};
185 +
186 static inline struct qcom_nand_host *to_qcom_nand_host(struct nand_chip *chip)
187 {
188 return container_of(chip, struct qcom_nand_host, chip);
189 @@ -1893,7 +1919,7 @@ static int qcom_nand_host_setup(struct q
190 | wide_bus << WIDE_FLASH
191 | 1 << DEV0_CFG1_ECC_DISABLE;
192
193 - host->ecc_bch_cfg = host->bch_enabled << ECC_CFG_ECC_DISABLE
194 + host->ecc_bch_cfg = !host->bch_enabled << ECC_CFG_ECC_DISABLE
195 | 0 << ECC_SW_RESET
196 | host->cw_data << ECC_NUM_DATA_BYTES
197 | 1 << ECC_FORCE_CLK_OPEN
198 @@ -1942,16 +1968,46 @@ static int qcom_nandc_alloc(struct qcom_
199 if (!nandc->regs)
200 return -ENOMEM;
201
202 - nandc->reg_read_buf = devm_kzalloc(nandc->dev,
203 - MAX_REG_RD * sizeof(*nandc->reg_read_buf),
204 - GFP_KERNEL);
205 - if (!nandc->reg_read_buf)
206 - return -ENOMEM;
207 + if (!nandc->dma_bam_enabled) {
208 + nandc->reg_read_buf = devm_kzalloc(nandc->dev,
209 + MAX_REG_RD *
210 + sizeof(*nandc->reg_read_buf),
211 + GFP_KERNEL);
212
213 - nandc->chan = dma_request_slave_channel(nandc->dev, "rxtx");
214 - if (!nandc->chan) {
215 - dev_err(nandc->dev, "failed to request slave channel\n");
216 - return -ENODEV;
217 + if (!nandc->reg_read_buf)
218 + return -ENOMEM;
219 +
220 + nandc->chan = dma_request_slave_channel(nandc->dev, "rxtx");
221 + if (!nandc->chan) {
222 + dev_err(nandc->dev, "failed to request slave channel\n");
223 + return -ENODEV;
224 + }
225 + } else {
226 + nandc->reg_read_buf = dmam_alloc_coherent(nandc->dev,
227 + MAX_REG_RD *
228 + sizeof(*nandc->reg_read_buf),
229 + &nandc->reg_read_buf_phys, GFP_KERNEL);
230 +
231 + if (!nandc->reg_read_buf)
232 + return -ENOMEM;
233 +
234 + nandc->tx_chan = dma_request_slave_channel(nandc->dev, "tx");
235 + if (!nandc->tx_chan) {
236 + dev_err(nandc->dev, "failed to request tx channel\n");
237 + return -ENODEV;
238 + }
239 +
240 + nandc->rx_chan = dma_request_slave_channel(nandc->dev, "rx");
241 + if (!nandc->rx_chan) {
242 + dev_err(nandc->dev, "failed to request rx channel\n");
243 + return -ENODEV;
244 + }
245 +
246 + nandc->cmd_chan = dma_request_slave_channel(nandc->dev, "cmd");
247 + if (!nandc->cmd_chan) {
248 + dev_err(nandc->dev, "failed to request cmd channel\n");
249 + return -ENODEV;
250 + }
251 }
252
253 INIT_LIST_HEAD(&nandc->desc_list);
254 @@ -1964,8 +2020,35 @@ static int qcom_nandc_alloc(struct qcom_
255
256 static void qcom_nandc_unalloc(struct qcom_nand_controller *nandc)
257 {
258 - dma_release_channel(nandc->chan);
259 -}
260 + if (nandc->dma_bam_enabled) {
261 + if (nandc->tx_chan)
262 + dma_release_channel(nandc->tx_chan);
263 +
264 + if (nandc->rx_chan)
265 + dma_release_channel(nandc->rx_chan);
266 +
267 + if (nandc->cmd_chan)
268 + dma_release_channel(nandc->tx_chan);
269 +
270 + if (nandc->reg_read_buf)
271 + dmam_free_coherent(nandc->dev, MAX_REG_RD *
272 + sizeof(*nandc->reg_read_buf),
273 + nandc->reg_read_buf,
274 + nandc->reg_read_buf_phys);
275 + } else {
276 + if (nandc->chan)
277 + dma_release_channel(nandc->chan);
278 +
279 + if (nandc->reg_read_buf)
280 + devm_kfree(nandc->dev, nandc->reg_read_buf);
281 + }
282 +
283 + if (nandc->regs)
284 + devm_kfree(nandc->dev, nandc->regs);
285 +
286 + if (nandc->data_buffer)
287 + devm_kfree(nandc->dev, nandc->data_buffer);
288 + }
289
290 /* one time setup of a few nand controller registers */
291 static int qcom_nandc_setup(struct qcom_nand_controller *nandc)
292 @@ -2002,6 +2085,8 @@ static int qcom_nand_host_init(struct qc
293 mtd->name = devm_kasprintf(dev, GFP_KERNEL, "qcom_nand.%d", host->cs);
294 mtd->owner = THIS_MODULE;
295 mtd->dev.parent = dev;
296 + mtd->priv = chip;
297 + chip->priv = nandc;
298
299 chip->cmdfunc = qcom_nandc_command;
300 chip->select_chip = qcom_nandc_select_chip;
301 @@ -2049,16 +2134,20 @@ static int qcom_nandc_parse_dt(struct pl
302 struct device_node *np = nandc->dev->of_node;
303 int ret;
304
305 - ret = of_property_read_u32(np, "qcom,cmd-crci", &nandc->cmd_crci);
306 - if (ret) {
307 - dev_err(nandc->dev, "command CRCI unspecified\n");
308 - return ret;
309 - }
310 + if (!nandc->dma_bam_enabled) {
311 + ret = of_property_read_u32(np, "qcom,cmd-crci",
312 + &nandc->cmd_crci);
313 + if (ret) {
314 + dev_err(nandc->dev, "command CRCI unspecified\n");
315 + return ret;
316 + }
317
318 - ret = of_property_read_u32(np, "qcom,data-crci", &nandc->data_crci);
319 - if (ret) {
320 - dev_err(nandc->dev, "data CRCI unspecified\n");
321 - return ret;
322 + ret = of_property_read_u32(np, "qcom,data-crci",
323 + &nandc->data_crci);
324 + if (ret) {
325 + dev_err(nandc->dev, "data CRCI unspecified\n");
326 + return ret;
327 + }
328 }
329
330 return 0;
331 @@ -2073,6 +2162,7 @@ static int qcom_nandc_probe(struct platf
332 struct device_node *dn = dev->of_node, *child;
333 struct resource *res;
334 int ret;
335 + struct qcom_nand_driver_data *driver_data;
336
337 nandc = devm_kzalloc(&pdev->dev, sizeof(*nandc), GFP_KERNEL);
338 if (!nandc)
339 @@ -2087,7 +2177,10 @@ static int qcom_nandc_probe(struct platf
340 return -ENODEV;
341 }
342
343 - nandc->ecc_modes = (unsigned long)dev_data;
344 + driver_data = (struct qcom_nand_driver_data *)dev_data;
345 +
346 + nandc->ecc_modes = driver_data->ecc_modes;
347 + nandc->dma_bam_enabled = driver_data->dma_bam_enabled;
348
349 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
350 nandc->base = devm_ioremap_resource(dev, res);
351 @@ -2179,7 +2272,15 @@ static int qcom_nandc_remove(struct plat
352 return 0;
353 }
354
355 -#define EBI2_NANDC_ECC_MODES (ECC_RS_4BIT | ECC_BCH_8BIT)
356 +struct qcom_nand_driver_data ebi2_nandc_bam_data = {
357 + .ecc_modes = (ECC_BCH_4BIT | ECC_BCH_8BIT),
358 + .dma_bam_enabled = true,
359 +};
360 +
361 +struct qcom_nand_driver_data ebi2_nandc_data = {
362 + .ecc_modes = (ECC_RS_4BIT | ECC_BCH_8BIT),
363 + .dma_bam_enabled = false,
364 +};
365
366 /*
367 * data will hold a struct pointer containing more differences once we support
368 @@ -2187,7 +2288,10 @@ static int qcom_nandc_remove(struct plat
369 */
370 static const struct of_device_id qcom_nandc_of_match[] = {
371 { .compatible = "qcom,ipq806x-nand",
372 - .data = (void *)EBI2_NANDC_ECC_MODES,
373 + .data = (void *) &ebi2_nandc_data,
374 + },
375 + { .compatible = "qcom,ebi2-nandc-bam",
376 + .data = (void *) &ebi2_nandc_bam_data,
377 },
378 {}
379 };