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