brcm2708: update linux 4.4 patches to latest version
[openwrt.git] / target / linux / brcm2708 / patches-4.4 / 0042-Add-SMI-NAND-driver.patch
1 From f4d44b2c447c401791645627e88d0ef9830c1239 Mon Sep 17 00:00:00 2001
2 From: Luke Wren <wren6991@gmail.com>
3 Date: Sat, 5 Sep 2015 01:16:10 +0100
4 Subject: [PATCH 042/170] Add SMI NAND driver
5
6 Signed-off-by: Luke Wren <wren6991@gmail.com>
7 ---
8  .../bindings/mtd/brcm,bcm2835-smi-nand.txt         |  42 ++++
9  drivers/mtd/nand/Kconfig                           |   7 +
10  drivers/mtd/nand/Makefile                          |   1 +
11  drivers/mtd/nand/bcm2835_smi_nand.c                | 268 +++++++++++++++++++++
12  4 files changed, 318 insertions(+)
13  create mode 100644 Documentation/devicetree/bindings/mtd/brcm,bcm2835-smi-nand.txt
14  create mode 100644 drivers/mtd/nand/bcm2835_smi_nand.c
15
16 --- /dev/null
17 +++ b/Documentation/devicetree/bindings/mtd/brcm,bcm2835-smi-nand.txt
18 @@ -0,0 +1,42 @@
19 +* BCM2835 SMI NAND flash
20 +
21 +This driver is a shim between the BCM2835 SMI driver (SMI is a peripheral for
22 +talking to parallel register interfaces) and Linux's MTD layer.
23 +
24 +Required properties:
25 +- compatible: "brcm,bcm2835-smi-nand"
26 +- status: "okay"
27 +
28 +Optional properties:
29 +- partition@n, where n is an integer from a consecutive sequence starting at 0
30 +       - Difficult to store partition table on NAND device - normally put it
31 +       in the source code, kernel bootparams, or device tree (the best way!)
32 +       - Sub-properties:
33 +               - label: the partition name, as shown by mtdinfo /dev/mtd*
34 +               - reg: the size and offset of this partition.
35 +               - (optional) read-only: an empty property flagging as read only
36 +
37 +Example:
38 +
39 +nand: flash@0 {
40 +       compatible = "brcm,bcm2835-smi-nand";
41 +       status = "okay";
42 +
43 +       partition@0 {
44 +               label = "stage2";
45 +               // 128k
46 +               reg = <0 0x20000>;
47 +               read-only;
48 +       };
49 +       partition@1 {
50 +               label = "firmware";
51 +               // 16M
52 +               reg = <0x20000 0x1000000>;
53 +               read-only;
54 +       };
55 +       partition@2 {
56 +               label = "root";
57 +               // 2G
58 +               reg = <0x1020000 0x80000000>;
59 +       };
60 +};
61 \ No newline at end of file
62 --- a/drivers/mtd/nand/Kconfig
63 +++ b/drivers/mtd/nand/Kconfig
64 @@ -41,6 +41,13 @@ config MTD_SM_COMMON
65         tristate
66         default n
67  
68 +config MTD_NAND_BCM2835_SMI
69 +        tristate "Use Broadcom's Secondary Memory Interface as a NAND controller (BCM283x)"
70 +        depends on (MACH_BCM2708 || MACH_BCM2709 || ARCH_BCM2835) && BCM2835_SMI && MTD_NAND
71 +        default m
72 +        help
73 +         Uses the BCM2835's SMI peripheral as a NAND controller.
74 +
75  config MTD_NAND_DENALI
76         tristate
77  
78 --- a/drivers/mtd/nand/Makefile
79 +++ b/drivers/mtd/nand/Makefile
80 @@ -14,6 +14,7 @@ obj-$(CONFIG_MTD_NAND_DENALI)         += denali
81  obj-$(CONFIG_MTD_NAND_DENALI_PCI)      += denali_pci.o
82  obj-$(CONFIG_MTD_NAND_DENALI_DT)       += denali_dt.o
83  obj-$(CONFIG_MTD_NAND_AU1550)          += au1550nd.o
84 +obj-$(CONFIG_MTD_NAND_BCM2835_SMI)     += bcm2835_smi_nand.o
85  obj-$(CONFIG_MTD_NAND_BF5XX)           += bf5xx_nand.o
86  obj-$(CONFIG_MTD_NAND_S3C2410)         += s3c2410.o
87  obj-$(CONFIG_MTD_NAND_DAVINCI)         += davinci_nand.o
88 --- /dev/null
89 +++ b/drivers/mtd/nand/bcm2835_smi_nand.c
90 @@ -0,0 +1,268 @@
91 +/**
92 + * NAND flash driver for Broadcom Secondary Memory Interface
93 + *
94 + * Written by Luke Wren <luke@raspberrypi.org>
95 + * Copyright (c) 2015, Raspberry Pi (Trading) Ltd.
96 + *
97 + * Redistribution and use in source and binary forms, with or without
98 + * modification, are permitted provided that the following conditions
99 + * are met:
100 + * 1. Redistributions of source code must retain the above copyright
101 + *    notice, this list of conditions, and the following disclaimer,
102 + *    without modification.
103 + * 2. Redistributions in binary form must reproduce the above copyright
104 + *    notice, this list of conditions and the following disclaimer in the
105 + *    documentation and/or other materials provided with the distribution.
106 + * 3. The names of the above-listed copyright holders may not be used
107 + *    to endorse or promote products derived from this software without
108 + *    specific prior written permission.
109 + *
110 + * ALTERNATIVELY, this software may be distributed under the terms of the
111 + * GNU General Public License ("GPL") version 2, as published by the Free
112 + * Software Foundation.
113 + *
114 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
115 + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
116 + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
117 + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
118 + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
119 + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
120 + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
121 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
122 + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
123 + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
124 + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
125 + */
126 +
127 +#include <linux/kernel.h>
128 +#include <linux/module.h>
129 +#include <linux/of.h>
130 +#include <linux/platform_device.h>
131 +#include <linux/slab.h>
132 +#include <linux/mtd/nand.h>
133 +#include <linux/mtd/partitions.h>
134 +
135 +#include <linux/broadcom/bcm2835_smi.h>
136 +
137 +#define DEVICE_NAME "bcm2835-smi-nand"
138 +#define DRIVER_NAME "smi-nand-bcm2835"
139 +
140 +struct bcm2835_smi_nand_host {
141 +       struct bcm2835_smi_instance *smi_inst;
142 +       struct nand_chip nand_chip;
143 +       struct mtd_info mtd;
144 +       struct device *dev;
145 +};
146 +
147 +/****************************************************************************
148 +*
149 +*   NAND functionality implementation
150 +*
151 +****************************************************************************/
152 +
153 +#define SMI_NAND_CLE_PIN 0x01
154 +#define SMI_NAND_ALE_PIN 0x02
155 +
156 +static inline void bcm2835_smi_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
157 +                                            unsigned int ctrl)
158 +{
159 +       uint32_t cmd32 = cmd;
160 +       uint32_t addr = ~(SMI_NAND_CLE_PIN | SMI_NAND_ALE_PIN);
161 +       struct bcm2835_smi_nand_host *host = dev_get_drvdata(mtd->dev.parent);
162 +       struct bcm2835_smi_instance *inst = host->smi_inst;
163 +
164 +       if (ctrl & NAND_CLE)
165 +               addr |= SMI_NAND_CLE_PIN;
166 +       if (ctrl & NAND_ALE)
167 +               addr |= SMI_NAND_ALE_PIN;
168 +       /* Lower ALL the CS pins! */
169 +       if (ctrl & NAND_NCE)
170 +               addr &= (SMI_NAND_CLE_PIN | SMI_NAND_ALE_PIN);
171 +
172 +       bcm2835_smi_set_address(inst, addr);
173 +
174 +       if (cmd != NAND_CMD_NONE)
175 +               bcm2835_smi_write_buf(inst, &cmd32, 1);
176 +}
177 +
178 +static inline uint8_t bcm2835_smi_nand_read_byte(struct mtd_info *mtd)
179 +{
180 +       uint8_t byte;
181 +       struct bcm2835_smi_nand_host *host = dev_get_drvdata(mtd->dev.parent);
182 +       struct bcm2835_smi_instance *inst = host->smi_inst;
183 +
184 +       bcm2835_smi_read_buf(inst, &byte, 1);
185 +       return byte;
186 +}
187 +
188 +static inline void bcm2835_smi_nand_write_byte(struct mtd_info *mtd,
189 +                                              uint8_t byte)
190 +{
191 +       struct bcm2835_smi_nand_host *host = dev_get_drvdata(mtd->dev.parent);
192 +       struct bcm2835_smi_instance *inst = host->smi_inst;
193 +
194 +       bcm2835_smi_write_buf(inst, &byte, 1);
195 +}
196 +
197 +static inline void bcm2835_smi_nand_write_buf(struct mtd_info *mtd,
198 +                                             const uint8_t *buf, int len)
199 +{
200 +       struct bcm2835_smi_nand_host *host = dev_get_drvdata(mtd->dev.parent);
201 +       struct bcm2835_smi_instance *inst = host->smi_inst;
202 +
203 +       bcm2835_smi_write_buf(inst, buf, len);
204 +}
205 +
206 +static inline void bcm2835_smi_nand_read_buf(struct mtd_info *mtd,
207 +                                            uint8_t *buf, int len)
208 +{
209 +       struct bcm2835_smi_nand_host *host = dev_get_drvdata(mtd->dev.parent);
210 +       struct bcm2835_smi_instance *inst = host->smi_inst;
211 +
212 +       bcm2835_smi_read_buf(inst, buf, len);
213 +}
214 +
215 +/****************************************************************************
216 +*
217 +*   Probe and remove functions
218 +*
219 +***************************************************************************/
220 +
221 +static int bcm2835_smi_nand_probe(struct platform_device *pdev)
222 +{
223 +       struct bcm2835_smi_nand_host *host;
224 +       struct nand_chip *this;
225 +       struct mtd_info *mtd;
226 +       struct device *dev = &pdev->dev;
227 +       struct device_node *node = dev->of_node, *smi_node;
228 +       struct mtd_part_parser_data ppdata;
229 +       struct smi_settings *smi_settings;
230 +       struct bcm2835_smi_instance *smi_inst;
231 +       int ret = -ENXIO;
232 +
233 +       if (!node) {
234 +               dev_err(dev, "No device tree node supplied!");
235 +               return -EINVAL;
236 +       }
237 +
238 +       smi_node = of_parse_phandle(node, "smi_handle", 0);
239 +
240 +       /* Request use of SMI peripheral: */
241 +       smi_inst = bcm2835_smi_get(smi_node);
242 +
243 +       if (!smi_inst) {
244 +               dev_err(dev, "Could not register with SMI.");
245 +               return -EPROBE_DEFER;
246 +       }
247 +
248 +       /* Set SMI timing and bus width */
249 +
250 +       smi_settings = bcm2835_smi_get_settings_from_regs(smi_inst);
251 +
252 +       smi_settings->data_width = SMI_WIDTH_8BIT;
253 +       smi_settings->read_setup_time = 2;
254 +       smi_settings->read_hold_time = 1;
255 +       smi_settings->read_pace_time = 1;
256 +       smi_settings->read_strobe_time = 3;
257 +
258 +       smi_settings->write_setup_time = 2;
259 +       smi_settings->write_hold_time = 1;
260 +       smi_settings->write_pace_time = 1;
261 +       smi_settings->write_strobe_time = 3;
262 +
263 +       bcm2835_smi_set_regs_from_settings(smi_inst);
264 +
265 +       host = devm_kzalloc(dev, sizeof(struct bcm2835_smi_nand_host),
266 +               GFP_KERNEL);
267 +       if (!host)
268 +               return -ENOMEM;
269 +
270 +       host->dev = dev;
271 +       host->smi_inst = smi_inst;
272 +
273 +       platform_set_drvdata(pdev, host);
274 +
275 +       /* Link the structures together */
276 +
277 +       this = &host->nand_chip;
278 +       mtd = &host->mtd;
279 +       mtd->priv = this;
280 +       mtd->owner = THIS_MODULE;
281 +       mtd->dev.parent = dev;
282 +       mtd->name = DRIVER_NAME;
283 +       ppdata.of_node = node;
284 +
285 +       /* 20 us command delay time... */
286 +       this->chip_delay = 20;
287 +
288 +       this->priv = host;
289 +       this->cmd_ctrl = bcm2835_smi_nand_cmd_ctrl;
290 +       this->read_byte = bcm2835_smi_nand_read_byte;
291 +       this->write_byte = bcm2835_smi_nand_write_byte;
292 +       this->write_buf = bcm2835_smi_nand_write_buf;
293 +       this->read_buf = bcm2835_smi_nand_read_buf;
294 +
295 +       this->ecc.mode = NAND_ECC_SOFT;
296 +
297 +       /* Should never be accessed directly: */
298 +
299 +       this->IO_ADDR_R = (void *)0xdeadbeef;
300 +       this->IO_ADDR_W = (void *)0xdeadbeef;
301 +
302 +       /* First scan to find the device and get the page size */
303 +
304 +       if (nand_scan_ident(mtd, 1, NULL))
305 +               return -ENXIO;
306 +
307 +       /* Second phase scan */
308 +
309 +       if (nand_scan_tail(mtd))
310 +               return -ENXIO;
311 +
312 +       ret = mtd_device_parse_register(mtd, NULL, &ppdata, NULL, 0);
313 +       if (!ret)
314 +               return 0;
315 +
316 +       nand_release(mtd);
317 +       return -EINVAL;
318 +}
319 +
320 +static int bcm2835_smi_nand_remove(struct platform_device *pdev)
321 +{
322 +       struct bcm2835_smi_nand_host *host = platform_get_drvdata(pdev);
323 +
324 +       nand_release(&host->mtd);
325 +
326 +       return 0;
327 +}
328 +
329 +/****************************************************************************
330 +*
331 +*   Register the driver with device tree
332 +*
333 +***************************************************************************/
334 +
335 +static const struct of_device_id bcm2835_smi_nand_of_match[] = {
336 +       {.compatible = "brcm,bcm2835-smi-nand",},
337 +       { /* sentinel */ }
338 +};
339 +
340 +MODULE_DEVICE_TABLE(of, bcm2835_smi_nand_of_match);
341 +
342 +static struct platform_driver bcm2835_smi_nand_driver = {
343 +       .probe = bcm2835_smi_nand_probe,
344 +       .remove = bcm2835_smi_nand_remove,
345 +       .driver = {
346 +               .name = DRIVER_NAME,
347 +               .owner = THIS_MODULE,
348 +               .of_match_table = bcm2835_smi_nand_of_match,
349 +       },
350 +};
351 +
352 +module_platform_driver(bcm2835_smi_nand_driver);
353 +
354 +MODULE_ALIAS("platform:smi-nand-bcm2835");
355 +MODULE_LICENSE("GPL");
356 +MODULE_DESCRIPTION
357 +       ("Driver for NAND chips using Broadcom Secondary Memory Interface");
358 +MODULE_AUTHOR("Luke Wren <luke@raspberrypi.org>");