diff options
author | Boris BREZILLON <boris.brezillon@free-electrons.com> | 2014-10-21 09:08:41 -0400 |
---|---|---|
committer | Brian Norris <computersforpeace@gmail.com> | 2014-10-29 13:08:00 -0400 |
commit | 1fef62c1423b694da517b18dc80d59a7eaf7dd74 (patch) | |
tree | c276ece06a86ce5a5923e0906116363e53c328d5 /drivers/mtd | |
parent | b00358a5632bdfc5048fdee04b548ebf8ca1c79c (diff) |
mtd: nand: add sunxi NAND flash controller support
Add support for the sunxi NAND Flash Controller (NFC).
Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
[Brian: tweaked to fix ecc->steps issue]
Signed-off-by: Brian Norris <computersforpeace@gmail.com>
Diffstat (limited to 'drivers/mtd')
-rw-r--r-- | drivers/mtd/nand/Kconfig | 6 | ||||
-rw-r--r-- | drivers/mtd/nand/Makefile | 1 | ||||
-rw-r--r-- | drivers/mtd/nand/sunxi_nand.c | 1432 |
3 files changed, 1439 insertions, 0 deletions
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index dd10646982ae..4c51d2c9acc1 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig | |||
@@ -516,4 +516,10 @@ config MTD_NAND_XWAY | |||
516 | Enables support for NAND Flash chips on Lantiq XWAY SoCs. NAND is attached | 516 | Enables support for NAND Flash chips on Lantiq XWAY SoCs. NAND is attached |
517 | to the External Bus Unit (EBU). | 517 | to the External Bus Unit (EBU). |
518 | 518 | ||
519 | config MTD_NAND_SUNXI | ||
520 | tristate "Support for NAND on Allwinner SoCs" | ||
521 | depends on ARCH_SUNXI | ||
522 | help | ||
523 | Enables support for NAND Flash chips on Allwinner SoCs. | ||
524 | |||
519 | endif # MTD_NAND | 525 | endif # MTD_NAND |
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index 9c847e469ca7..bd38f21d2e28 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile | |||
@@ -50,5 +50,6 @@ obj-$(CONFIG_MTD_NAND_JZ4740) += jz4740_nand.o | |||
50 | obj-$(CONFIG_MTD_NAND_GPMI_NAND) += gpmi-nand/ | 50 | obj-$(CONFIG_MTD_NAND_GPMI_NAND) += gpmi-nand/ |
51 | obj-$(CONFIG_MTD_NAND_XWAY) += xway_nand.o | 51 | obj-$(CONFIG_MTD_NAND_XWAY) += xway_nand.o |
52 | obj-$(CONFIG_MTD_NAND_BCM47XXNFLASH) += bcm47xxnflash/ | 52 | obj-$(CONFIG_MTD_NAND_BCM47XXNFLASH) += bcm47xxnflash/ |
53 | obj-$(CONFIG_MTD_NAND_SUNXI) += sunxi_nand.o | ||
53 | 54 | ||
54 | nand-objs := nand_base.o nand_bbt.o nand_timings.o | 55 | nand-objs := nand_base.o nand_bbt.o nand_timings.o |
diff --git a/drivers/mtd/nand/sunxi_nand.c b/drivers/mtd/nand/sunxi_nand.c new file mode 100644 index 000000000000..ccaa8e283388 --- /dev/null +++ b/drivers/mtd/nand/sunxi_nand.c | |||
@@ -0,0 +1,1432 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2013 Boris BREZILLON <b.brezillon.dev@gmail.com> | ||
3 | * | ||
4 | * Derived from: | ||
5 | * https://github.com/yuq/sunxi-nfc-mtd | ||
6 | * Copyright (C) 2013 Qiang Yu <yuq825@gmail.com> | ||
7 | * | ||
8 | * https://github.com/hno/Allwinner-Info | ||
9 | * Copyright (C) 2013 Henrik Nordström <Henrik Nordström> | ||
10 | * | ||
11 | * Copyright (C) 2013 Dmitriy B. <rzk333@gmail.com> | ||
12 | * Copyright (C) 2013 Sergey Lapin <slapin@ossfans.org> | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or modify | ||
15 | * it under the terms of the GNU General Public License as published by | ||
16 | * the Free Software Foundation; either version 2 of the License, or | ||
17 | * (at your option) any later version. | ||
18 | * | ||
19 | * This program is distributed in the hope that it will be useful, | ||
20 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
21 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
22 | * GNU General Public License for more details. | ||
23 | */ | ||
24 | |||
25 | #include <linux/dma-mapping.h> | ||
26 | #include <linux/slab.h> | ||
27 | #include <linux/module.h> | ||
28 | #include <linux/moduleparam.h> | ||
29 | #include <linux/platform_device.h> | ||
30 | #include <linux/of.h> | ||
31 | #include <linux/of_device.h> | ||
32 | #include <linux/of_gpio.h> | ||
33 | #include <linux/of_mtd.h> | ||
34 | #include <linux/mtd/mtd.h> | ||
35 | #include <linux/mtd/nand.h> | ||
36 | #include <linux/mtd/partitions.h> | ||
37 | #include <linux/clk.h> | ||
38 | #include <linux/delay.h> | ||
39 | #include <linux/dmaengine.h> | ||
40 | #include <linux/gpio.h> | ||
41 | #include <linux/interrupt.h> | ||
42 | #include <linux/io.h> | ||
43 | |||
44 | #define NFC_REG_CTL 0x0000 | ||
45 | #define NFC_REG_ST 0x0004 | ||
46 | #define NFC_REG_INT 0x0008 | ||
47 | #define NFC_REG_TIMING_CTL 0x000C | ||
48 | #define NFC_REG_TIMING_CFG 0x0010 | ||
49 | #define NFC_REG_ADDR_LOW 0x0014 | ||
50 | #define NFC_REG_ADDR_HIGH 0x0018 | ||
51 | #define NFC_REG_SECTOR_NUM 0x001C | ||
52 | #define NFC_REG_CNT 0x0020 | ||
53 | #define NFC_REG_CMD 0x0024 | ||
54 | #define NFC_REG_RCMD_SET 0x0028 | ||
55 | #define NFC_REG_WCMD_SET 0x002C | ||
56 | #define NFC_REG_IO_DATA 0x0030 | ||
57 | #define NFC_REG_ECC_CTL 0x0034 | ||
58 | #define NFC_REG_ECC_ST 0x0038 | ||
59 | #define NFC_REG_DEBUG 0x003C | ||
60 | #define NFC_REG_ECC_CNT0 0x0040 | ||
61 | #define NFC_REG_ECC_CNT1 0x0044 | ||
62 | #define NFC_REG_ECC_CNT2 0x0048 | ||
63 | #define NFC_REG_ECC_CNT3 0x004c | ||
64 | #define NFC_REG_USER_DATA_BASE 0x0050 | ||
65 | #define NFC_REG_SPARE_AREA 0x00A0 | ||
66 | #define NFC_RAM0_BASE 0x0400 | ||
67 | #define NFC_RAM1_BASE 0x0800 | ||
68 | |||
69 | /* define bit use in NFC_CTL */ | ||
70 | #define NFC_EN BIT(0) | ||
71 | #define NFC_RESET BIT(1) | ||
72 | #define NFC_BUS_WIDYH BIT(2) | ||
73 | #define NFC_RB_SEL BIT(3) | ||
74 | #define NFC_CE_SEL GENMASK(26, 24) | ||
75 | #define NFC_CE_CTL BIT(6) | ||
76 | #define NFC_CE_CTL1 BIT(7) | ||
77 | #define NFC_PAGE_SIZE GENMASK(11, 8) | ||
78 | #define NFC_SAM BIT(12) | ||
79 | #define NFC_RAM_METHOD BIT(14) | ||
80 | #define NFC_DEBUG_CTL BIT(31) | ||
81 | |||
82 | /* define bit use in NFC_ST */ | ||
83 | #define NFC_RB_B2R BIT(0) | ||
84 | #define NFC_CMD_INT_FLAG BIT(1) | ||
85 | #define NFC_DMA_INT_FLAG BIT(2) | ||
86 | #define NFC_CMD_FIFO_STATUS BIT(3) | ||
87 | #define NFC_STA BIT(4) | ||
88 | #define NFC_NATCH_INT_FLAG BIT(5) | ||
89 | #define NFC_RB_STATE0 BIT(8) | ||
90 | #define NFC_RB_STATE1 BIT(9) | ||
91 | #define NFC_RB_STATE2 BIT(10) | ||
92 | #define NFC_RB_STATE3 BIT(11) | ||
93 | |||
94 | /* define bit use in NFC_INT */ | ||
95 | #define NFC_B2R_INT_ENABLE BIT(0) | ||
96 | #define NFC_CMD_INT_ENABLE BIT(1) | ||
97 | #define NFC_DMA_INT_ENABLE BIT(2) | ||
98 | #define NFC_INT_MASK (NFC_B2R_INT_ENABLE | \ | ||
99 | NFC_CMD_INT_ENABLE | \ | ||
100 | NFC_DMA_INT_ENABLE) | ||
101 | |||
102 | /* define bit use in NFC_CMD */ | ||
103 | #define NFC_CMD_LOW_BYTE GENMASK(7, 0) | ||
104 | #define NFC_CMD_HIGH_BYTE GENMASK(15, 8) | ||
105 | #define NFC_ADR_NUM GENMASK(18, 16) | ||
106 | #define NFC_SEND_ADR BIT(19) | ||
107 | #define NFC_ACCESS_DIR BIT(20) | ||
108 | #define NFC_DATA_TRANS BIT(21) | ||
109 | #define NFC_SEND_CMD1 BIT(22) | ||
110 | #define NFC_WAIT_FLAG BIT(23) | ||
111 | #define NFC_SEND_CMD2 BIT(24) | ||
112 | #define NFC_SEQ BIT(25) | ||
113 | #define NFC_DATA_SWAP_METHOD BIT(26) | ||
114 | #define NFC_ROW_AUTO_INC BIT(27) | ||
115 | #define NFC_SEND_CMD3 BIT(28) | ||
116 | #define NFC_SEND_CMD4 BIT(29) | ||
117 | #define NFC_CMD_TYPE GENMASK(31, 30) | ||
118 | |||
119 | /* define bit use in NFC_RCMD_SET */ | ||
120 | #define NFC_READ_CMD GENMASK(7, 0) | ||
121 | #define NFC_RANDOM_READ_CMD0 GENMASK(15, 8) | ||
122 | #define NFC_RANDOM_READ_CMD1 GENMASK(23, 16) | ||
123 | |||
124 | /* define bit use in NFC_WCMD_SET */ | ||
125 | #define NFC_PROGRAM_CMD GENMASK(7, 0) | ||
126 | #define NFC_RANDOM_WRITE_CMD GENMASK(15, 8) | ||
127 | #define NFC_READ_CMD0 GENMASK(23, 16) | ||
128 | #define NFC_READ_CMD1 GENMASK(31, 24) | ||
129 | |||
130 | /* define bit use in NFC_ECC_CTL */ | ||
131 | #define NFC_ECC_EN BIT(0) | ||
132 | #define NFC_ECC_PIPELINE BIT(3) | ||
133 | #define NFC_ECC_EXCEPTION BIT(4) | ||
134 | #define NFC_ECC_BLOCK_SIZE BIT(5) | ||
135 | #define NFC_RANDOM_EN BIT(9) | ||
136 | #define NFC_RANDOM_DIRECTION BIT(10) | ||
137 | #define NFC_ECC_MODE_SHIFT 12 | ||
138 | #define NFC_ECC_MODE GENMASK(15, 12) | ||
139 | #define NFC_RANDOM_SEED GENMASK(30, 16) | ||
140 | |||
141 | #define NFC_DEFAULT_TIMEOUT_MS 1000 | ||
142 | |||
143 | #define NFC_SRAM_SIZE 1024 | ||
144 | |||
145 | #define NFC_MAX_CS 7 | ||
146 | |||
147 | /* | ||
148 | * Ready/Busy detection type: describes the Ready/Busy detection modes | ||
149 | * | ||
150 | * @RB_NONE: no external detection available, rely on STATUS command | ||
151 | * and software timeouts | ||
152 | * @RB_NATIVE: use sunxi NAND controller Ready/Busy support. The Ready/Busy | ||
153 | * pin of the NAND flash chip must be connected to one of the | ||
154 | * native NAND R/B pins (those which can be muxed to the NAND | ||
155 | * Controller) | ||
156 | * @RB_GPIO: use a simple GPIO to handle Ready/Busy status. The Ready/Busy | ||
157 | * pin of the NAND flash chip must be connected to a GPIO capable | ||
158 | * pin. | ||
159 | */ | ||
160 | enum sunxi_nand_rb_type { | ||
161 | RB_NONE, | ||
162 | RB_NATIVE, | ||
163 | RB_GPIO, | ||
164 | }; | ||
165 | |||
166 | /* | ||
167 | * Ready/Busy structure: stores information related to Ready/Busy detection | ||
168 | * | ||
169 | * @type: the Ready/Busy detection mode | ||
170 | * @info: information related to the R/B detection mode. Either a gpio | ||
171 | * id or a native R/B id (those supported by the NAND controller). | ||
172 | */ | ||
173 | struct sunxi_nand_rb { | ||
174 | enum sunxi_nand_rb_type type; | ||
175 | union { | ||
176 | int gpio; | ||
177 | int nativeid; | ||
178 | } info; | ||
179 | }; | ||
180 | |||
181 | /* | ||
182 | * Chip Select structure: stores information related to NAND Chip Select | ||
183 | * | ||
184 | * @cs: the NAND CS id used to communicate with a NAND Chip | ||
185 | * @rb: the Ready/Busy description | ||
186 | */ | ||
187 | struct sunxi_nand_chip_sel { | ||
188 | u8 cs; | ||
189 | struct sunxi_nand_rb rb; | ||
190 | }; | ||
191 | |||
192 | /* | ||
193 | * sunxi HW ECC infos: stores information related to HW ECC support | ||
194 | * | ||
195 | * @mode: the sunxi ECC mode field deduced from ECC requirements | ||
196 | * @layout: the OOB layout depending on the ECC requirements and the | ||
197 | * selected ECC mode | ||
198 | */ | ||
199 | struct sunxi_nand_hw_ecc { | ||
200 | int mode; | ||
201 | struct nand_ecclayout layout; | ||
202 | }; | ||
203 | |||
204 | /* | ||
205 | * NAND chip structure: stores NAND chip device related information | ||
206 | * | ||
207 | * @node: used to store NAND chips into a list | ||
208 | * @nand: base NAND chip structure | ||
209 | * @mtd: base MTD structure | ||
210 | * @clk_rate: clk_rate required for this NAND chip | ||
211 | * @selected: current active CS | ||
212 | * @nsels: number of CS lines required by the NAND chip | ||
213 | * @sels: array of CS lines descriptions | ||
214 | */ | ||
215 | struct sunxi_nand_chip { | ||
216 | struct list_head node; | ||
217 | struct nand_chip nand; | ||
218 | struct mtd_info mtd; | ||
219 | unsigned long clk_rate; | ||
220 | int selected; | ||
221 | int nsels; | ||
222 | struct sunxi_nand_chip_sel sels[0]; | ||
223 | }; | ||
224 | |||
225 | static inline struct sunxi_nand_chip *to_sunxi_nand(struct nand_chip *nand) | ||
226 | { | ||
227 | return container_of(nand, struct sunxi_nand_chip, nand); | ||
228 | } | ||
229 | |||
230 | /* | ||
231 | * NAND Controller structure: stores sunxi NAND controller information | ||
232 | * | ||
233 | * @controller: base controller structure | ||
234 | * @dev: parent device (used to print error messages) | ||
235 | * @regs: NAND controller registers | ||
236 | * @ahb_clk: NAND Controller AHB clock | ||
237 | * @mod_clk: NAND Controller mod clock | ||
238 | * @assigned_cs: bitmask describing already assigned CS lines | ||
239 | * @clk_rate: NAND controller current clock rate | ||
240 | * @chips: a list containing all the NAND chips attached to | ||
241 | * this NAND controller | ||
242 | * @complete: a completion object used to wait for NAND | ||
243 | * controller events | ||
244 | */ | ||
245 | struct sunxi_nfc { | ||
246 | struct nand_hw_control controller; | ||
247 | struct device *dev; | ||
248 | void __iomem *regs; | ||
249 | struct clk *ahb_clk; | ||
250 | struct clk *mod_clk; | ||
251 | unsigned long assigned_cs; | ||
252 | unsigned long clk_rate; | ||
253 | struct list_head chips; | ||
254 | struct completion complete; | ||
255 | }; | ||
256 | |||
257 | static inline struct sunxi_nfc *to_sunxi_nfc(struct nand_hw_control *ctrl) | ||
258 | { | ||
259 | return container_of(ctrl, struct sunxi_nfc, controller); | ||
260 | } | ||
261 | |||
262 | static irqreturn_t sunxi_nfc_interrupt(int irq, void *dev_id) | ||
263 | { | ||
264 | struct sunxi_nfc *nfc = dev_id; | ||
265 | u32 st = readl(nfc->regs + NFC_REG_ST); | ||
266 | u32 ien = readl(nfc->regs + NFC_REG_INT); | ||
267 | |||
268 | if (!(ien & st)) | ||
269 | return IRQ_NONE; | ||
270 | |||
271 | if ((ien & st) == ien) | ||
272 | complete(&nfc->complete); | ||
273 | |||
274 | writel(st & NFC_INT_MASK, nfc->regs + NFC_REG_ST); | ||
275 | writel(~st & ien & NFC_INT_MASK, nfc->regs + NFC_REG_INT); | ||
276 | |||
277 | return IRQ_HANDLED; | ||
278 | } | ||
279 | |||
280 | static int sunxi_nfc_wait_int(struct sunxi_nfc *nfc, u32 flags, | ||
281 | unsigned int timeout_ms) | ||
282 | { | ||
283 | init_completion(&nfc->complete); | ||
284 | |||
285 | writel(flags, nfc->regs + NFC_REG_INT); | ||
286 | |||
287 | if (!timeout_ms) | ||
288 | timeout_ms = NFC_DEFAULT_TIMEOUT_MS; | ||
289 | |||
290 | if (!wait_for_completion_timeout(&nfc->complete, | ||
291 | msecs_to_jiffies(timeout_ms))) { | ||
292 | dev_err(nfc->dev, "wait interrupt timedout\n"); | ||
293 | return -ETIMEDOUT; | ||
294 | } | ||
295 | |||
296 | return 0; | ||
297 | } | ||
298 | |||
299 | static int sunxi_nfc_wait_cmd_fifo_empty(struct sunxi_nfc *nfc) | ||
300 | { | ||
301 | unsigned long timeout = jiffies + | ||
302 | msecs_to_jiffies(NFC_DEFAULT_TIMEOUT_MS); | ||
303 | |||
304 | do { | ||
305 | if (!(readl(nfc->regs + NFC_REG_ST) & NFC_CMD_FIFO_STATUS)) | ||
306 | return 0; | ||
307 | } while (time_before(jiffies, timeout)); | ||
308 | |||
309 | dev_err(nfc->dev, "wait for empty cmd FIFO timedout\n"); | ||
310 | return -ETIMEDOUT; | ||
311 | } | ||
312 | |||
313 | static int sunxi_nfc_rst(struct sunxi_nfc *nfc) | ||
314 | { | ||
315 | unsigned long timeout = jiffies + | ||
316 | msecs_to_jiffies(NFC_DEFAULT_TIMEOUT_MS); | ||
317 | |||
318 | writel(0, nfc->regs + NFC_REG_ECC_CTL); | ||
319 | writel(NFC_RESET, nfc->regs + NFC_REG_CTL); | ||
320 | |||
321 | do { | ||
322 | if (!(readl(nfc->regs + NFC_REG_CTL) & NFC_RESET)) | ||
323 | return 0; | ||
324 | } while (time_before(jiffies, timeout)); | ||
325 | |||
326 | dev_err(nfc->dev, "wait for NAND controller reset timedout\n"); | ||
327 | return -ETIMEDOUT; | ||
328 | } | ||
329 | |||
330 | static int sunxi_nfc_dev_ready(struct mtd_info *mtd) | ||
331 | { | ||
332 | struct nand_chip *nand = mtd->priv; | ||
333 | struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand); | ||
334 | struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller); | ||
335 | struct sunxi_nand_rb *rb; | ||
336 | unsigned long timeo = (sunxi_nand->nand.state == FL_ERASING ? 400 : 20); | ||
337 | int ret; | ||
338 | |||
339 | if (sunxi_nand->selected < 0) | ||
340 | return 0; | ||
341 | |||
342 | rb = &sunxi_nand->sels[sunxi_nand->selected].rb; | ||
343 | |||
344 | switch (rb->type) { | ||
345 | case RB_NATIVE: | ||
346 | ret = !!(readl(nfc->regs + NFC_REG_ST) & | ||
347 | (NFC_RB_STATE0 << rb->info.nativeid)); | ||
348 | if (ret) | ||
349 | break; | ||
350 | |||
351 | sunxi_nfc_wait_int(nfc, NFC_RB_B2R, timeo); | ||
352 | ret = !!(readl(nfc->regs + NFC_REG_ST) & | ||
353 | (NFC_RB_STATE0 << rb->info.nativeid)); | ||
354 | break; | ||
355 | case RB_GPIO: | ||
356 | ret = gpio_get_value(rb->info.gpio); | ||
357 | break; | ||
358 | case RB_NONE: | ||
359 | default: | ||
360 | ret = 0; | ||
361 | dev_err(nfc->dev, "cannot check R/B NAND status!\n"); | ||
362 | break; | ||
363 | } | ||
364 | |||
365 | return ret; | ||
366 | } | ||
367 | |||
368 | static void sunxi_nfc_select_chip(struct mtd_info *mtd, int chip) | ||
369 | { | ||
370 | struct nand_chip *nand = mtd->priv; | ||
371 | struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand); | ||
372 | struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller); | ||
373 | struct sunxi_nand_chip_sel *sel; | ||
374 | u32 ctl; | ||
375 | |||
376 | if (chip > 0 && chip >= sunxi_nand->nsels) | ||
377 | return; | ||
378 | |||
379 | if (chip == sunxi_nand->selected) | ||
380 | return; | ||
381 | |||
382 | ctl = readl(nfc->regs + NFC_REG_CTL) & | ||
383 | ~(NFC_CE_SEL | NFC_RB_SEL | NFC_EN); | ||
384 | |||
385 | if (chip >= 0) { | ||
386 | sel = &sunxi_nand->sels[chip]; | ||
387 | |||
388 | ctl |= (sel->cs << 24) | NFC_EN | | ||
389 | (((nand->page_shift - 10) & 0xf) << 8); | ||
390 | if (sel->rb.type == RB_NONE) { | ||
391 | nand->dev_ready = NULL; | ||
392 | } else { | ||
393 | nand->dev_ready = sunxi_nfc_dev_ready; | ||
394 | if (sel->rb.type == RB_NATIVE) | ||
395 | ctl |= (sel->rb.info.nativeid << 3); | ||
396 | } | ||
397 | |||
398 | writel(mtd->writesize, nfc->regs + NFC_REG_SPARE_AREA); | ||
399 | |||
400 | if (nfc->clk_rate != sunxi_nand->clk_rate) { | ||
401 | clk_set_rate(nfc->mod_clk, sunxi_nand->clk_rate); | ||
402 | nfc->clk_rate = sunxi_nand->clk_rate; | ||
403 | } | ||
404 | } | ||
405 | |||
406 | writel(ctl, nfc->regs + NFC_REG_CTL); | ||
407 | |||
408 | sunxi_nand->selected = chip; | ||
409 | } | ||
410 | |||
411 | static void sunxi_nfc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) | ||
412 | { | ||
413 | struct nand_chip *nand = mtd->priv; | ||
414 | struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand); | ||
415 | struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller); | ||
416 | int ret; | ||
417 | int cnt; | ||
418 | int offs = 0; | ||
419 | u32 tmp; | ||
420 | |||
421 | while (len > offs) { | ||
422 | cnt = min(len - offs, NFC_SRAM_SIZE); | ||
423 | |||
424 | ret = sunxi_nfc_wait_cmd_fifo_empty(nfc); | ||
425 | if (ret) | ||
426 | break; | ||
427 | |||
428 | writel(cnt, nfc->regs + NFC_REG_CNT); | ||
429 | tmp = NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD; | ||
430 | writel(tmp, nfc->regs + NFC_REG_CMD); | ||
431 | |||
432 | ret = sunxi_nfc_wait_int(nfc, NFC_CMD_INT_FLAG, 0); | ||
433 | if (ret) | ||
434 | break; | ||
435 | |||
436 | if (buf) | ||
437 | memcpy_fromio(buf + offs, nfc->regs + NFC_RAM0_BASE, | ||
438 | cnt); | ||
439 | offs += cnt; | ||
440 | } | ||
441 | } | ||
442 | |||
443 | static void sunxi_nfc_write_buf(struct mtd_info *mtd, const uint8_t *buf, | ||
444 | int len) | ||
445 | { | ||
446 | struct nand_chip *nand = mtd->priv; | ||
447 | struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand); | ||
448 | struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller); | ||
449 | int ret; | ||
450 | int cnt; | ||
451 | int offs = 0; | ||
452 | u32 tmp; | ||
453 | |||
454 | while (len > offs) { | ||
455 | cnt = min(len - offs, NFC_SRAM_SIZE); | ||
456 | |||
457 | ret = sunxi_nfc_wait_cmd_fifo_empty(nfc); | ||
458 | if (ret) | ||
459 | break; | ||
460 | |||
461 | writel(cnt, nfc->regs + NFC_REG_CNT); | ||
462 | memcpy_toio(nfc->regs + NFC_RAM0_BASE, buf + offs, cnt); | ||
463 | tmp = NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD | | ||
464 | NFC_ACCESS_DIR; | ||
465 | writel(tmp, nfc->regs + NFC_REG_CMD); | ||
466 | |||
467 | ret = sunxi_nfc_wait_int(nfc, NFC_CMD_INT_FLAG, 0); | ||
468 | if (ret) | ||
469 | break; | ||
470 | |||
471 | offs += cnt; | ||
472 | } | ||
473 | } | ||
474 | |||
475 | static uint8_t sunxi_nfc_read_byte(struct mtd_info *mtd) | ||
476 | { | ||
477 | uint8_t ret; | ||
478 | |||
479 | sunxi_nfc_read_buf(mtd, &ret, 1); | ||
480 | |||
481 | return ret; | ||
482 | } | ||
483 | |||
484 | static void sunxi_nfc_cmd_ctrl(struct mtd_info *mtd, int dat, | ||
485 | unsigned int ctrl) | ||
486 | { | ||
487 | struct nand_chip *nand = mtd->priv; | ||
488 | struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand); | ||
489 | struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller); | ||
490 | int ret; | ||
491 | u32 tmp; | ||
492 | |||
493 | ret = sunxi_nfc_wait_cmd_fifo_empty(nfc); | ||
494 | if (ret) | ||
495 | return; | ||
496 | |||
497 | if (ctrl & NAND_CTRL_CHANGE) { | ||
498 | tmp = readl(nfc->regs + NFC_REG_CTL); | ||
499 | if (ctrl & NAND_NCE) | ||
500 | tmp |= NFC_CE_CTL; | ||
501 | else | ||
502 | tmp &= ~NFC_CE_CTL; | ||
503 | writel(tmp, nfc->regs + NFC_REG_CTL); | ||
504 | } | ||
505 | |||
506 | if (dat == NAND_CMD_NONE) | ||
507 | return; | ||
508 | |||
509 | if (ctrl & NAND_CLE) { | ||
510 | writel(NFC_SEND_CMD1 | dat, nfc->regs + NFC_REG_CMD); | ||
511 | } else { | ||
512 | writel(dat, nfc->regs + NFC_REG_ADDR_LOW); | ||
513 | writel(NFC_SEND_ADR, nfc->regs + NFC_REG_CMD); | ||
514 | } | ||
515 | |||
516 | sunxi_nfc_wait_int(nfc, NFC_CMD_INT_FLAG, 0); | ||
517 | } | ||
518 | |||
519 | static int sunxi_nfc_hw_ecc_read_page(struct mtd_info *mtd, | ||
520 | struct nand_chip *chip, uint8_t *buf, | ||
521 | int oob_required, int page) | ||
522 | { | ||
523 | struct sunxi_nfc *nfc = to_sunxi_nfc(chip->controller); | ||
524 | struct nand_ecc_ctrl *ecc = &chip->ecc; | ||
525 | struct nand_ecclayout *layout = ecc->layout; | ||
526 | struct sunxi_nand_hw_ecc *data = ecc->priv; | ||
527 | unsigned int max_bitflips = 0; | ||
528 | int offset; | ||
529 | int ret; | ||
530 | u32 tmp; | ||
531 | int i; | ||
532 | int cnt; | ||
533 | |||
534 | tmp = readl(nfc->regs + NFC_REG_ECC_CTL); | ||
535 | tmp &= ~(NFC_ECC_MODE | NFC_ECC_PIPELINE | NFC_ECC_BLOCK_SIZE); | ||
536 | tmp |= NFC_ECC_EN | (data->mode << NFC_ECC_MODE_SHIFT) | | ||
537 | NFC_ECC_EXCEPTION; | ||
538 | |||
539 | writel(tmp, nfc->regs + NFC_REG_ECC_CTL); | ||
540 | |||
541 | for (i = 0; i < ecc->steps; i++) { | ||
542 | if (i) | ||
543 | chip->cmdfunc(mtd, NAND_CMD_RNDOUT, i * ecc->size, -1); | ||
544 | |||
545 | offset = mtd->writesize + layout->eccpos[i * ecc->bytes] - 4; | ||
546 | |||
547 | chip->read_buf(mtd, NULL, ecc->size); | ||
548 | |||
549 | chip->cmdfunc(mtd, NAND_CMD_RNDOUT, offset, -1); | ||
550 | |||
551 | ret = sunxi_nfc_wait_cmd_fifo_empty(nfc); | ||
552 | if (ret) | ||
553 | return ret; | ||
554 | |||
555 | tmp = NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD | (1 << 30); | ||
556 | writel(tmp, nfc->regs + NFC_REG_CMD); | ||
557 | |||
558 | ret = sunxi_nfc_wait_int(nfc, NFC_CMD_INT_FLAG, 0); | ||
559 | if (ret) | ||
560 | return ret; | ||
561 | |||
562 | memcpy_fromio(buf + (i * ecc->size), | ||
563 | nfc->regs + NFC_RAM0_BASE, ecc->size); | ||
564 | |||
565 | if (readl(nfc->regs + NFC_REG_ECC_ST) & 0x1) { | ||
566 | mtd->ecc_stats.failed++; | ||
567 | } else { | ||
568 | tmp = readl(nfc->regs + NFC_REG_ECC_CNT0) & 0xff; | ||
569 | mtd->ecc_stats.corrected += tmp; | ||
570 | max_bitflips = max_t(unsigned int, max_bitflips, tmp); | ||
571 | } | ||
572 | |||
573 | if (oob_required) { | ||
574 | chip->cmdfunc(mtd, NAND_CMD_RNDOUT, offset, -1); | ||
575 | |||
576 | ret = sunxi_nfc_wait_cmd_fifo_empty(nfc); | ||
577 | if (ret) | ||
578 | return ret; | ||
579 | |||
580 | offset -= mtd->writesize; | ||
581 | chip->read_buf(mtd, chip->oob_poi + offset, | ||
582 | ecc->bytes + 4); | ||
583 | } | ||
584 | } | ||
585 | |||
586 | if (oob_required) { | ||
587 | cnt = ecc->layout->oobfree[ecc->steps].length; | ||
588 | if (cnt > 0) { | ||
589 | offset = mtd->writesize + | ||
590 | ecc->layout->oobfree[ecc->steps].offset; | ||
591 | chip->cmdfunc(mtd, NAND_CMD_RNDOUT, offset, -1); | ||
592 | offset -= mtd->writesize; | ||
593 | chip->read_buf(mtd, chip->oob_poi + offset, cnt); | ||
594 | } | ||
595 | } | ||
596 | |||
597 | tmp = readl(nfc->regs + NFC_REG_ECC_CTL); | ||
598 | tmp &= ~NFC_ECC_EN; | ||
599 | |||
600 | writel(tmp, nfc->regs + NFC_REG_ECC_CTL); | ||
601 | |||
602 | return max_bitflips; | ||
603 | } | ||
604 | |||
605 | static int sunxi_nfc_hw_ecc_write_page(struct mtd_info *mtd, | ||
606 | struct nand_chip *chip, | ||
607 | const uint8_t *buf, int oob_required) | ||
608 | { | ||
609 | struct sunxi_nfc *nfc = to_sunxi_nfc(chip->controller); | ||
610 | struct nand_ecc_ctrl *ecc = &chip->ecc; | ||
611 | struct nand_ecclayout *layout = ecc->layout; | ||
612 | struct sunxi_nand_hw_ecc *data = ecc->priv; | ||
613 | int offset; | ||
614 | int ret; | ||
615 | u32 tmp; | ||
616 | int i; | ||
617 | int cnt; | ||
618 | |||
619 | tmp = readl(nfc->regs + NFC_REG_ECC_CTL); | ||
620 | tmp &= ~(NFC_ECC_MODE | NFC_ECC_PIPELINE | NFC_ECC_BLOCK_SIZE); | ||
621 | tmp |= NFC_ECC_EN | (data->mode << NFC_ECC_MODE_SHIFT) | | ||
622 | NFC_ECC_EXCEPTION; | ||
623 | |||
624 | writel(tmp, nfc->regs + NFC_REG_ECC_CTL); | ||
625 | |||
626 | for (i = 0; i < ecc->steps; i++) { | ||
627 | if (i) | ||
628 | chip->cmdfunc(mtd, NAND_CMD_RNDIN, i * ecc->size, -1); | ||
629 | |||
630 | chip->write_buf(mtd, buf + (i * ecc->size), ecc->size); | ||
631 | |||
632 | offset = layout->eccpos[i * ecc->bytes] - 4 + mtd->writesize; | ||
633 | |||
634 | /* Fill OOB data in */ | ||
635 | if (oob_required) { | ||
636 | tmp = 0xffffffff; | ||
637 | memcpy_toio(nfc->regs + NFC_REG_USER_DATA_BASE, &tmp, | ||
638 | 4); | ||
639 | } else { | ||
640 | memcpy_toio(nfc->regs + NFC_REG_USER_DATA_BASE, | ||
641 | chip->oob_poi + offset - mtd->writesize, | ||
642 | 4); | ||
643 | } | ||
644 | |||
645 | chip->cmdfunc(mtd, NAND_CMD_RNDIN, offset, -1); | ||
646 | |||
647 | ret = sunxi_nfc_wait_cmd_fifo_empty(nfc); | ||
648 | if (ret) | ||
649 | return ret; | ||
650 | |||
651 | tmp = NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD | NFC_ACCESS_DIR | | ||
652 | (1 << 30); | ||
653 | writel(tmp, nfc->regs + NFC_REG_CMD); | ||
654 | ret = sunxi_nfc_wait_int(nfc, NFC_CMD_INT_FLAG, 0); | ||
655 | if (ret) | ||
656 | return ret; | ||
657 | } | ||
658 | |||
659 | if (oob_required) { | ||
660 | cnt = ecc->layout->oobfree[i].length; | ||
661 | if (cnt > 0) { | ||
662 | offset = mtd->writesize + | ||
663 | ecc->layout->oobfree[i].offset; | ||
664 | chip->cmdfunc(mtd, NAND_CMD_RNDIN, offset, -1); | ||
665 | offset -= mtd->writesize; | ||
666 | chip->write_buf(mtd, chip->oob_poi + offset, cnt); | ||
667 | } | ||
668 | } | ||
669 | |||
670 | tmp = readl(nfc->regs + NFC_REG_ECC_CTL); | ||
671 | tmp &= ~NFC_ECC_EN; | ||
672 | |||
673 | writel(tmp, nfc->regs + NFC_REG_ECC_CTL); | ||
674 | |||
675 | return 0; | ||
676 | } | ||
677 | |||
678 | static int sunxi_nfc_hw_syndrome_ecc_read_page(struct mtd_info *mtd, | ||
679 | struct nand_chip *chip, | ||
680 | uint8_t *buf, int oob_required, | ||
681 | int page) | ||
682 | { | ||
683 | struct sunxi_nfc *nfc = to_sunxi_nfc(chip->controller); | ||
684 | struct nand_ecc_ctrl *ecc = &chip->ecc; | ||
685 | struct sunxi_nand_hw_ecc *data = ecc->priv; | ||
686 | unsigned int max_bitflips = 0; | ||
687 | uint8_t *oob = chip->oob_poi; | ||
688 | int offset = 0; | ||
689 | int ret; | ||
690 | int cnt; | ||
691 | u32 tmp; | ||
692 | int i; | ||
693 | |||
694 | tmp = readl(nfc->regs + NFC_REG_ECC_CTL); | ||
695 | tmp &= ~(NFC_ECC_MODE | NFC_ECC_PIPELINE | NFC_ECC_BLOCK_SIZE); | ||
696 | tmp |= NFC_ECC_EN | (data->mode << NFC_ECC_MODE_SHIFT) | | ||
697 | NFC_ECC_EXCEPTION; | ||
698 | |||
699 | writel(tmp, nfc->regs + NFC_REG_ECC_CTL); | ||
700 | |||
701 | for (i = 0; i < ecc->steps; i++) { | ||
702 | chip->read_buf(mtd, NULL, ecc->size); | ||
703 | |||
704 | tmp = NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD | (1 << 30); | ||
705 | writel(tmp, nfc->regs + NFC_REG_CMD); | ||
706 | |||
707 | ret = sunxi_nfc_wait_int(nfc, NFC_CMD_INT_FLAG, 0); | ||
708 | if (ret) | ||
709 | return ret; | ||
710 | |||
711 | memcpy_fromio(buf, nfc->regs + NFC_RAM0_BASE, ecc->size); | ||
712 | buf += ecc->size; | ||
713 | offset += ecc->size; | ||
714 | |||
715 | if (readl(nfc->regs + NFC_REG_ECC_ST) & 0x1) { | ||
716 | mtd->ecc_stats.failed++; | ||
717 | } else { | ||
718 | tmp = readl(nfc->regs + NFC_REG_ECC_CNT0) & 0xff; | ||
719 | mtd->ecc_stats.corrected += tmp; | ||
720 | max_bitflips = max_t(unsigned int, max_bitflips, tmp); | ||
721 | } | ||
722 | |||
723 | if (oob_required) { | ||
724 | chip->cmdfunc(mtd, NAND_CMD_RNDOUT, offset, -1); | ||
725 | chip->read_buf(mtd, oob, ecc->bytes + ecc->prepad); | ||
726 | oob += ecc->bytes + ecc->prepad; | ||
727 | } | ||
728 | |||
729 | offset += ecc->bytes + ecc->prepad; | ||
730 | } | ||
731 | |||
732 | if (oob_required) { | ||
733 | cnt = mtd->oobsize - (oob - chip->oob_poi); | ||
734 | if (cnt > 0) { | ||
735 | chip->cmdfunc(mtd, NAND_CMD_RNDOUT, offset, -1); | ||
736 | chip->read_buf(mtd, oob, cnt); | ||
737 | } | ||
738 | } | ||
739 | |||
740 | writel(readl(nfc->regs + NFC_REG_ECC_CTL) & ~NFC_ECC_EN, | ||
741 | nfc->regs + NFC_REG_ECC_CTL); | ||
742 | |||
743 | return max_bitflips; | ||
744 | } | ||
745 | |||
746 | static int sunxi_nfc_hw_syndrome_ecc_write_page(struct mtd_info *mtd, | ||
747 | struct nand_chip *chip, | ||
748 | const uint8_t *buf, | ||
749 | int oob_required) | ||
750 | { | ||
751 | struct sunxi_nfc *nfc = to_sunxi_nfc(chip->controller); | ||
752 | struct nand_ecc_ctrl *ecc = &chip->ecc; | ||
753 | struct sunxi_nand_hw_ecc *data = ecc->priv; | ||
754 | uint8_t *oob = chip->oob_poi; | ||
755 | int offset = 0; | ||
756 | int ret; | ||
757 | int cnt; | ||
758 | u32 tmp; | ||
759 | int i; | ||
760 | |||
761 | tmp = readl(nfc->regs + NFC_REG_ECC_CTL); | ||
762 | tmp &= ~(NFC_ECC_MODE | NFC_ECC_PIPELINE | NFC_ECC_BLOCK_SIZE); | ||
763 | tmp |= NFC_ECC_EN | (data->mode << NFC_ECC_MODE_SHIFT) | | ||
764 | NFC_ECC_EXCEPTION; | ||
765 | |||
766 | writel(tmp, nfc->regs + NFC_REG_ECC_CTL); | ||
767 | |||
768 | for (i = 0; i < ecc->steps; i++) { | ||
769 | chip->write_buf(mtd, buf + (i * ecc->size), ecc->size); | ||
770 | offset += ecc->size; | ||
771 | |||
772 | /* Fill OOB data in */ | ||
773 | if (oob_required) { | ||
774 | tmp = 0xffffffff; | ||
775 | memcpy_toio(nfc->regs + NFC_REG_USER_DATA_BASE, &tmp, | ||
776 | 4); | ||
777 | } else { | ||
778 | memcpy_toio(nfc->regs + NFC_REG_USER_DATA_BASE, oob, | ||
779 | 4); | ||
780 | } | ||
781 | |||
782 | tmp = NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD | NFC_ACCESS_DIR | | ||
783 | (1 << 30); | ||
784 | writel(tmp, nfc->regs + NFC_REG_CMD); | ||
785 | |||
786 | ret = sunxi_nfc_wait_int(nfc, NFC_CMD_INT_FLAG, 0); | ||
787 | if (ret) | ||
788 | return ret; | ||
789 | |||
790 | offset += ecc->bytes + ecc->prepad; | ||
791 | oob += ecc->bytes + ecc->prepad; | ||
792 | } | ||
793 | |||
794 | if (oob_required) { | ||
795 | cnt = mtd->oobsize - (oob - chip->oob_poi); | ||
796 | if (cnt > 0) { | ||
797 | chip->cmdfunc(mtd, NAND_CMD_RNDIN, offset, -1); | ||
798 | chip->write_buf(mtd, oob, cnt); | ||
799 | } | ||
800 | } | ||
801 | |||
802 | tmp = readl(nfc->regs + NFC_REG_ECC_CTL); | ||
803 | tmp &= ~NFC_ECC_EN; | ||
804 | |||
805 | writel(tmp, nfc->regs + NFC_REG_ECC_CTL); | ||
806 | |||
807 | return 0; | ||
808 | } | ||
809 | |||
810 | static int sunxi_nand_chip_set_timings(struct sunxi_nand_chip *chip, | ||
811 | const struct nand_sdr_timings *timings) | ||
812 | { | ||
813 | u32 min_clk_period = 0; | ||
814 | |||
815 | /* T1 <=> tCLS */ | ||
816 | if (timings->tCLS_min > min_clk_period) | ||
817 | min_clk_period = timings->tCLS_min; | ||
818 | |||
819 | /* T2 <=> tCLH */ | ||
820 | if (timings->tCLH_min > min_clk_period) | ||
821 | min_clk_period = timings->tCLH_min; | ||
822 | |||
823 | /* T3 <=> tCS */ | ||
824 | if (timings->tCS_min > min_clk_period) | ||
825 | min_clk_period = timings->tCS_min; | ||
826 | |||
827 | /* T4 <=> tCH */ | ||
828 | if (timings->tCH_min > min_clk_period) | ||
829 | min_clk_period = timings->tCH_min; | ||
830 | |||
831 | /* T5 <=> tWP */ | ||
832 | if (timings->tWP_min > min_clk_period) | ||
833 | min_clk_period = timings->tWP_min; | ||
834 | |||
835 | /* T6 <=> tWH */ | ||
836 | if (timings->tWH_min > min_clk_period) | ||
837 | min_clk_period = timings->tWH_min; | ||
838 | |||
839 | /* T7 <=> tALS */ | ||
840 | if (timings->tALS_min > min_clk_period) | ||
841 | min_clk_period = timings->tALS_min; | ||
842 | |||
843 | /* T8 <=> tDS */ | ||
844 | if (timings->tDS_min > min_clk_period) | ||
845 | min_clk_period = timings->tDS_min; | ||
846 | |||
847 | /* T9 <=> tDH */ | ||
848 | if (timings->tDH_min > min_clk_period) | ||
849 | min_clk_period = timings->tDH_min; | ||
850 | |||
851 | /* T10 <=> tRR */ | ||
852 | if (timings->tRR_min > (min_clk_period * 3)) | ||
853 | min_clk_period = DIV_ROUND_UP(timings->tRR_min, 3); | ||
854 | |||
855 | /* T11 <=> tALH */ | ||
856 | if (timings->tALH_min > min_clk_period) | ||
857 | min_clk_period = timings->tALH_min; | ||
858 | |||
859 | /* T12 <=> tRP */ | ||
860 | if (timings->tRP_min > min_clk_period) | ||
861 | min_clk_period = timings->tRP_min; | ||
862 | |||
863 | /* T13 <=> tREH */ | ||
864 | if (timings->tREH_min > min_clk_period) | ||
865 | min_clk_period = timings->tREH_min; | ||
866 | |||
867 | /* T14 <=> tRC */ | ||
868 | if (timings->tRC_min > (min_clk_period * 2)) | ||
869 | min_clk_period = DIV_ROUND_UP(timings->tRC_min, 2); | ||
870 | |||
871 | /* T15 <=> tWC */ | ||
872 | if (timings->tWC_min > (min_clk_period * 2)) | ||
873 | min_clk_period = DIV_ROUND_UP(timings->tWC_min, 2); | ||
874 | |||
875 | |||
876 | /* Convert min_clk_period from picoseconds to nanoseconds */ | ||
877 | min_clk_period = DIV_ROUND_UP(min_clk_period, 1000); | ||
878 | |||
879 | /* | ||
880 | * Convert min_clk_period into a clk frequency, then get the | ||
881 | * appropriate rate for the NAND controller IP given this formula | ||
882 | * (specified in the datasheet): | ||
883 | * nand clk_rate = 2 * min_clk_rate | ||
884 | */ | ||
885 | chip->clk_rate = (2 * NSEC_PER_SEC) / min_clk_period; | ||
886 | |||
887 | /* TODO: configure T16-T19 */ | ||
888 | |||
889 | return 0; | ||
890 | } | ||
891 | |||
892 | static int sunxi_nand_chip_init_timings(struct sunxi_nand_chip *chip, | ||
893 | struct device_node *np) | ||
894 | { | ||
895 | const struct nand_sdr_timings *timings; | ||
896 | int ret; | ||
897 | int mode; | ||
898 | |||
899 | mode = onfi_get_async_timing_mode(&chip->nand); | ||
900 | if (mode == ONFI_TIMING_MODE_UNKNOWN) { | ||
901 | mode = chip->nand.onfi_timing_mode_default; | ||
902 | } else { | ||
903 | uint8_t feature[ONFI_SUBFEATURE_PARAM_LEN] = {}; | ||
904 | |||
905 | mode = fls(mode) - 1; | ||
906 | if (mode < 0) | ||
907 | mode = 0; | ||
908 | |||
909 | feature[0] = mode; | ||
910 | ret = chip->nand.onfi_set_features(&chip->mtd, &chip->nand, | ||
911 | ONFI_FEATURE_ADDR_TIMING_MODE, | ||
912 | feature); | ||
913 | if (ret) | ||
914 | return ret; | ||
915 | } | ||
916 | |||
917 | timings = onfi_async_timing_mode_to_sdr_timings(mode); | ||
918 | if (IS_ERR(timings)) | ||
919 | return PTR_ERR(timings); | ||
920 | |||
921 | return sunxi_nand_chip_set_timings(chip, timings); | ||
922 | } | ||
923 | |||
924 | static int sunxi_nand_hw_common_ecc_ctrl_init(struct mtd_info *mtd, | ||
925 | struct nand_ecc_ctrl *ecc, | ||
926 | struct device_node *np) | ||
927 | { | ||
928 | static const u8 strengths[] = { 16, 24, 28, 32, 40, 48, 56, 60, 64 }; | ||
929 | struct nand_chip *nand = mtd->priv; | ||
930 | struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand); | ||
931 | struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller); | ||
932 | struct sunxi_nand_hw_ecc *data; | ||
933 | struct nand_ecclayout *layout; | ||
934 | int nsectors; | ||
935 | int ret; | ||
936 | int i; | ||
937 | |||
938 | data = kzalloc(sizeof(*data), GFP_KERNEL); | ||
939 | if (!data) | ||
940 | return -ENOMEM; | ||
941 | |||
942 | /* Add ECC info retrieval from DT */ | ||
943 | for (i = 0; i < ARRAY_SIZE(strengths); i++) { | ||
944 | if (ecc->strength <= strengths[i]) | ||
945 | break; | ||
946 | } | ||
947 | |||
948 | if (i >= ARRAY_SIZE(strengths)) { | ||
949 | dev_err(nfc->dev, "unsupported strength\n"); | ||
950 | ret = -ENOTSUPP; | ||
951 | goto err; | ||
952 | } | ||
953 | |||
954 | data->mode = i; | ||
955 | |||
956 | /* HW ECC always request ECC bytes for 1024 bytes blocks */ | ||
957 | ecc->bytes = DIV_ROUND_UP(ecc->strength * fls(8 * 1024), 8); | ||
958 | |||
959 | /* HW ECC always work with even numbers of ECC bytes */ | ||
960 | ecc->bytes = ALIGN(ecc->bytes, 2); | ||
961 | |||
962 | layout = &data->layout; | ||
963 | nsectors = mtd->writesize / ecc->size; | ||
964 | |||
965 | if (mtd->oobsize < ((ecc->bytes + 4) * nsectors)) { | ||
966 | ret = -EINVAL; | ||
967 | goto err; | ||
968 | } | ||
969 | |||
970 | layout->eccbytes = (ecc->bytes * nsectors); | ||
971 | |||
972 | ecc->layout = layout; | ||
973 | ecc->priv = data; | ||
974 | |||
975 | return 0; | ||
976 | |||
977 | err: | ||
978 | kfree(data); | ||
979 | |||
980 | return ret; | ||
981 | } | ||
982 | |||
983 | static void sunxi_nand_hw_common_ecc_ctrl_cleanup(struct nand_ecc_ctrl *ecc) | ||
984 | { | ||
985 | kfree(ecc->priv); | ||
986 | } | ||
987 | |||
988 | static int sunxi_nand_hw_ecc_ctrl_init(struct mtd_info *mtd, | ||
989 | struct nand_ecc_ctrl *ecc, | ||
990 | struct device_node *np) | ||
991 | { | ||
992 | struct nand_ecclayout *layout; | ||
993 | int nsectors; | ||
994 | int i, j; | ||
995 | int ret; | ||
996 | |||
997 | ret = sunxi_nand_hw_common_ecc_ctrl_init(mtd, ecc, np); | ||
998 | if (ret) | ||
999 | return ret; | ||
1000 | |||
1001 | ecc->read_page = sunxi_nfc_hw_ecc_read_page; | ||
1002 | ecc->write_page = sunxi_nfc_hw_ecc_write_page; | ||
1003 | layout = ecc->layout; | ||
1004 | nsectors = mtd->writesize / ecc->size; | ||
1005 | |||
1006 | for (i = 0; i < nsectors; i++) { | ||
1007 | if (i) { | ||
1008 | layout->oobfree[i].offset = | ||
1009 | layout->oobfree[i - 1].offset + | ||
1010 | layout->oobfree[i - 1].length + | ||
1011 | ecc->bytes; | ||
1012 | layout->oobfree[i].length = 4; | ||
1013 | } else { | ||
1014 | /* | ||
1015 | * The first 2 bytes are used for BB markers, hence we | ||
1016 | * only have 2 bytes available in the first user data | ||
1017 | * section. | ||
1018 | */ | ||
1019 | layout->oobfree[i].length = 2; | ||
1020 | layout->oobfree[i].offset = 2; | ||
1021 | } | ||
1022 | |||
1023 | for (j = 0; j < ecc->bytes; j++) | ||
1024 | layout->eccpos[(ecc->bytes * i) + j] = | ||
1025 | layout->oobfree[i].offset + | ||
1026 | layout->oobfree[i].length + j; | ||
1027 | } | ||
1028 | |||
1029 | if (mtd->oobsize > (ecc->bytes + 4) * nsectors) { | ||
1030 | layout->oobfree[nsectors].offset = | ||
1031 | layout->oobfree[nsectors - 1].offset + | ||
1032 | layout->oobfree[nsectors - 1].length + | ||
1033 | ecc->bytes; | ||
1034 | layout->oobfree[nsectors].length = mtd->oobsize - | ||
1035 | ((ecc->bytes + 4) * nsectors); | ||
1036 | } | ||
1037 | |||
1038 | return 0; | ||
1039 | } | ||
1040 | |||
1041 | static int sunxi_nand_hw_syndrome_ecc_ctrl_init(struct mtd_info *mtd, | ||
1042 | struct nand_ecc_ctrl *ecc, | ||
1043 | struct device_node *np) | ||
1044 | { | ||
1045 | struct nand_ecclayout *layout; | ||
1046 | int nsectors; | ||
1047 | int i; | ||
1048 | int ret; | ||
1049 | |||
1050 | ret = sunxi_nand_hw_common_ecc_ctrl_init(mtd, ecc, np); | ||
1051 | if (ret) | ||
1052 | return ret; | ||
1053 | |||
1054 | ecc->prepad = 4; | ||
1055 | ecc->read_page = sunxi_nfc_hw_syndrome_ecc_read_page; | ||
1056 | ecc->write_page = sunxi_nfc_hw_syndrome_ecc_write_page; | ||
1057 | |||
1058 | layout = ecc->layout; | ||
1059 | nsectors = mtd->writesize / ecc->size; | ||
1060 | |||
1061 | for (i = 0; i < (ecc->bytes * nsectors); i++) | ||
1062 | layout->eccpos[i] = i; | ||
1063 | |||
1064 | layout->oobfree[0].length = mtd->oobsize - i; | ||
1065 | layout->oobfree[0].offset = i; | ||
1066 | |||
1067 | return 0; | ||
1068 | } | ||
1069 | |||
1070 | static void sunxi_nand_ecc_cleanup(struct nand_ecc_ctrl *ecc) | ||
1071 | { | ||
1072 | switch (ecc->mode) { | ||
1073 | case NAND_ECC_HW: | ||
1074 | case NAND_ECC_HW_SYNDROME: | ||
1075 | sunxi_nand_hw_common_ecc_ctrl_cleanup(ecc); | ||
1076 | break; | ||
1077 | case NAND_ECC_NONE: | ||
1078 | kfree(ecc->layout); | ||
1079 | default: | ||
1080 | break; | ||
1081 | } | ||
1082 | } | ||
1083 | |||
1084 | static int sunxi_nand_ecc_init(struct mtd_info *mtd, struct nand_ecc_ctrl *ecc, | ||
1085 | struct device_node *np) | ||
1086 | { | ||
1087 | struct nand_chip *nand = mtd->priv; | ||
1088 | int strength; | ||
1089 | int blk_size; | ||
1090 | int ret; | ||
1091 | |||
1092 | blk_size = of_get_nand_ecc_step_size(np); | ||
1093 | strength = of_get_nand_ecc_strength(np); | ||
1094 | if (blk_size > 0 && strength > 0) { | ||
1095 | ecc->size = blk_size; | ||
1096 | ecc->strength = strength; | ||
1097 | } else { | ||
1098 | ecc->size = nand->ecc_step_ds; | ||
1099 | ecc->strength = nand->ecc_strength_ds; | ||
1100 | } | ||
1101 | |||
1102 | if (!ecc->size || !ecc->strength) | ||
1103 | return -EINVAL; | ||
1104 | |||
1105 | ecc->mode = NAND_ECC_HW; | ||
1106 | |||
1107 | ret = of_get_nand_ecc_mode(np); | ||
1108 | if (ret >= 0) | ||
1109 | ecc->mode = ret; | ||
1110 | |||
1111 | switch (ecc->mode) { | ||
1112 | case NAND_ECC_SOFT_BCH: | ||
1113 | ecc->bytes = DIV_ROUND_UP(ecc->strength * fls(8 * ecc->size), | ||
1114 | 8); | ||
1115 | break; | ||
1116 | case NAND_ECC_HW: | ||
1117 | ret = sunxi_nand_hw_ecc_ctrl_init(mtd, ecc, np); | ||
1118 | if (ret) | ||
1119 | return ret; | ||
1120 | break; | ||
1121 | case NAND_ECC_HW_SYNDROME: | ||
1122 | ret = sunxi_nand_hw_syndrome_ecc_ctrl_init(mtd, ecc, np); | ||
1123 | if (ret) | ||
1124 | return ret; | ||
1125 | break; | ||
1126 | case NAND_ECC_NONE: | ||
1127 | ecc->layout = kzalloc(sizeof(*ecc->layout), GFP_KERNEL); | ||
1128 | if (!ecc->layout) | ||
1129 | return -ENOMEM; | ||
1130 | ecc->layout->oobfree[0].length = mtd->oobsize; | ||
1131 | case NAND_ECC_SOFT: | ||
1132 | break; | ||
1133 | default: | ||
1134 | return -EINVAL; | ||
1135 | } | ||
1136 | |||
1137 | return 0; | ||
1138 | } | ||
1139 | |||
1140 | static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc, | ||
1141 | struct device_node *np) | ||
1142 | { | ||
1143 | const struct nand_sdr_timings *timings; | ||
1144 | struct sunxi_nand_chip *chip; | ||
1145 | struct mtd_part_parser_data ppdata; | ||
1146 | struct mtd_info *mtd; | ||
1147 | struct nand_chip *nand; | ||
1148 | int nsels; | ||
1149 | int ret; | ||
1150 | int i; | ||
1151 | u32 tmp; | ||
1152 | |||
1153 | if (!of_get_property(np, "reg", &nsels)) | ||
1154 | return -EINVAL; | ||
1155 | |||
1156 | nsels /= sizeof(u32); | ||
1157 | if (!nsels) { | ||
1158 | dev_err(dev, "invalid reg property size\n"); | ||
1159 | return -EINVAL; | ||
1160 | } | ||
1161 | |||
1162 | chip = devm_kzalloc(dev, | ||
1163 | sizeof(*chip) + | ||
1164 | (nsels * sizeof(struct sunxi_nand_chip_sel)), | ||
1165 | GFP_KERNEL); | ||
1166 | if (!chip) { | ||
1167 | dev_err(dev, "could not allocate chip\n"); | ||
1168 | return -ENOMEM; | ||
1169 | } | ||
1170 | |||
1171 | chip->nsels = nsels; | ||
1172 | chip->selected = -1; | ||
1173 | |||
1174 | for (i = 0; i < nsels; i++) { | ||
1175 | ret = of_property_read_u32_index(np, "reg", i, &tmp); | ||
1176 | if (ret) { | ||
1177 | dev_err(dev, "could not retrieve reg property: %d\n", | ||
1178 | ret); | ||
1179 | return ret; | ||
1180 | } | ||
1181 | |||
1182 | if (tmp > NFC_MAX_CS) { | ||
1183 | dev_err(dev, | ||
1184 | "invalid reg value: %u (max CS = 7)\n", | ||
1185 | tmp); | ||
1186 | return -EINVAL; | ||
1187 | } | ||
1188 | |||
1189 | if (test_and_set_bit(tmp, &nfc->assigned_cs)) { | ||
1190 | dev_err(dev, "CS %d already assigned\n", tmp); | ||
1191 | return -EINVAL; | ||
1192 | } | ||
1193 | |||
1194 | chip->sels[i].cs = tmp; | ||
1195 | |||
1196 | if (!of_property_read_u32_index(np, "allwinner,rb", i, &tmp) && | ||
1197 | tmp < 2) { | ||
1198 | chip->sels[i].rb.type = RB_NATIVE; | ||
1199 | chip->sels[i].rb.info.nativeid = tmp; | ||
1200 | } else { | ||
1201 | ret = of_get_named_gpio(np, "rb-gpios", i); | ||
1202 | if (ret >= 0) { | ||
1203 | tmp = ret; | ||
1204 | chip->sels[i].rb.type = RB_GPIO; | ||
1205 | chip->sels[i].rb.info.gpio = tmp; | ||
1206 | ret = devm_gpio_request(dev, tmp, "nand-rb"); | ||
1207 | if (ret) | ||
1208 | return ret; | ||
1209 | |||
1210 | ret = gpio_direction_input(tmp); | ||
1211 | if (ret) | ||
1212 | return ret; | ||
1213 | } else { | ||
1214 | chip->sels[i].rb.type = RB_NONE; | ||
1215 | } | ||
1216 | } | ||
1217 | } | ||
1218 | |||
1219 | timings = onfi_async_timing_mode_to_sdr_timings(0); | ||
1220 | if (IS_ERR(timings)) { | ||
1221 | ret = PTR_ERR(timings); | ||
1222 | dev_err(dev, | ||
1223 | "could not retrieve timings for ONFI mode 0: %d\n", | ||
1224 | ret); | ||
1225 | return ret; | ||
1226 | } | ||
1227 | |||
1228 | ret = sunxi_nand_chip_set_timings(chip, timings); | ||
1229 | if (ret) { | ||
1230 | dev_err(dev, "could not configure chip timings: %d\n", ret); | ||
1231 | return ret; | ||
1232 | } | ||
1233 | |||
1234 | nand = &chip->nand; | ||
1235 | /* Default tR value specified in the ONFI spec (chapter 4.15.1) */ | ||
1236 | nand->chip_delay = 200; | ||
1237 | nand->controller = &nfc->controller; | ||
1238 | nand->select_chip = sunxi_nfc_select_chip; | ||
1239 | nand->cmd_ctrl = sunxi_nfc_cmd_ctrl; | ||
1240 | nand->read_buf = sunxi_nfc_read_buf; | ||
1241 | nand->write_buf = sunxi_nfc_write_buf; | ||
1242 | nand->read_byte = sunxi_nfc_read_byte; | ||
1243 | |||
1244 | if (of_get_nand_on_flash_bbt(np)) | ||
1245 | nand->bbt_options |= NAND_BBT_USE_FLASH | NAND_BBT_NO_OOB; | ||
1246 | |||
1247 | mtd = &chip->mtd; | ||
1248 | mtd->dev.parent = dev; | ||
1249 | mtd->priv = nand; | ||
1250 | mtd->owner = THIS_MODULE; | ||
1251 | |||
1252 | ret = nand_scan_ident(mtd, nsels, NULL); | ||
1253 | if (ret) | ||
1254 | return ret; | ||
1255 | |||
1256 | ret = sunxi_nand_chip_init_timings(chip, np); | ||
1257 | if (ret) { | ||
1258 | dev_err(dev, "could not configure chip timings: %d\n", ret); | ||
1259 | return ret; | ||
1260 | } | ||
1261 | |||
1262 | ret = sunxi_nand_ecc_init(mtd, &nand->ecc, np); | ||
1263 | if (ret) { | ||
1264 | dev_err(dev, "ECC init failed: %d\n", ret); | ||
1265 | return ret; | ||
1266 | } | ||
1267 | |||
1268 | ret = nand_scan_tail(mtd); | ||
1269 | if (ret) { | ||
1270 | dev_err(dev, "nand_scan_tail failed: %d\n", ret); | ||
1271 | return ret; | ||
1272 | } | ||
1273 | |||
1274 | ppdata.of_node = np; | ||
1275 | ret = mtd_device_parse_register(mtd, NULL, &ppdata, NULL, 0); | ||
1276 | if (ret) { | ||
1277 | dev_err(dev, "failed to register mtd device: %d\n", ret); | ||
1278 | nand_release(mtd); | ||
1279 | return ret; | ||
1280 | } | ||
1281 | |||
1282 | list_add_tail(&chip->node, &nfc->chips); | ||
1283 | |||
1284 | return 0; | ||
1285 | } | ||
1286 | |||
1287 | static int sunxi_nand_chips_init(struct device *dev, struct sunxi_nfc *nfc) | ||
1288 | { | ||
1289 | struct device_node *np = dev->of_node; | ||
1290 | struct device_node *nand_np; | ||
1291 | int nchips = of_get_child_count(np); | ||
1292 | int ret; | ||
1293 | |||
1294 | if (nchips > 8) { | ||
1295 | dev_err(dev, "too many NAND chips: %d (max = 8)\n", nchips); | ||
1296 | return -EINVAL; | ||
1297 | } | ||
1298 | |||
1299 | for_each_child_of_node(np, nand_np) { | ||
1300 | ret = sunxi_nand_chip_init(dev, nfc, nand_np); | ||
1301 | if (ret) | ||
1302 | return ret; | ||
1303 | } | ||
1304 | |||
1305 | return 0; | ||
1306 | } | ||
1307 | |||
1308 | static void sunxi_nand_chips_cleanup(struct sunxi_nfc *nfc) | ||
1309 | { | ||
1310 | struct sunxi_nand_chip *chip; | ||
1311 | |||
1312 | while (!list_empty(&nfc->chips)) { | ||
1313 | chip = list_first_entry(&nfc->chips, struct sunxi_nand_chip, | ||
1314 | node); | ||
1315 | nand_release(&chip->mtd); | ||
1316 | sunxi_nand_ecc_cleanup(&chip->nand.ecc); | ||
1317 | } | ||
1318 | } | ||
1319 | |||
1320 | static int sunxi_nfc_probe(struct platform_device *pdev) | ||
1321 | { | ||
1322 | struct device *dev = &pdev->dev; | ||
1323 | struct resource *r; | ||
1324 | struct sunxi_nfc *nfc; | ||
1325 | int irq; | ||
1326 | int ret; | ||
1327 | |||
1328 | nfc = devm_kzalloc(dev, sizeof(*nfc), GFP_KERNEL); | ||
1329 | if (!nfc) | ||
1330 | return -ENOMEM; | ||
1331 | |||
1332 | nfc->dev = dev; | ||
1333 | spin_lock_init(&nfc->controller.lock); | ||
1334 | init_waitqueue_head(&nfc->controller.wq); | ||
1335 | INIT_LIST_HEAD(&nfc->chips); | ||
1336 | |||
1337 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
1338 | nfc->regs = devm_ioremap_resource(dev, r); | ||
1339 | if (IS_ERR(nfc->regs)) | ||
1340 | return PTR_ERR(nfc->regs); | ||
1341 | |||
1342 | irq = platform_get_irq(pdev, 0); | ||
1343 | if (irq < 0) { | ||
1344 | dev_err(dev, "failed to retrieve irq\n"); | ||
1345 | return irq; | ||
1346 | } | ||
1347 | |||
1348 | nfc->ahb_clk = devm_clk_get(dev, "ahb"); | ||
1349 | if (IS_ERR(nfc->ahb_clk)) { | ||
1350 | dev_err(dev, "failed to retrieve ahb clk\n"); | ||
1351 | return PTR_ERR(nfc->ahb_clk); | ||
1352 | } | ||
1353 | |||
1354 | ret = clk_prepare_enable(nfc->ahb_clk); | ||
1355 | if (ret) | ||
1356 | return ret; | ||
1357 | |||
1358 | nfc->mod_clk = devm_clk_get(dev, "mod"); | ||
1359 | if (IS_ERR(nfc->mod_clk)) { | ||
1360 | dev_err(dev, "failed to retrieve mod clk\n"); | ||
1361 | ret = PTR_ERR(nfc->mod_clk); | ||
1362 | goto out_ahb_clk_unprepare; | ||
1363 | } | ||
1364 | |||
1365 | ret = clk_prepare_enable(nfc->mod_clk); | ||
1366 | if (ret) | ||
1367 | goto out_ahb_clk_unprepare; | ||
1368 | |||
1369 | ret = sunxi_nfc_rst(nfc); | ||
1370 | if (ret) | ||
1371 | goto out_mod_clk_unprepare; | ||
1372 | |||
1373 | writel(0, nfc->regs + NFC_REG_INT); | ||
1374 | ret = devm_request_irq(dev, irq, sunxi_nfc_interrupt, | ||
1375 | 0, "sunxi-nand", nfc); | ||
1376 | if (ret) | ||
1377 | goto out_mod_clk_unprepare; | ||
1378 | |||
1379 | platform_set_drvdata(pdev, nfc); | ||
1380 | |||
1381 | /* | ||
1382 | * TODO: replace these magic values with proper flags as soon as we | ||
1383 | * know what they are encoding. | ||
1384 | */ | ||
1385 | writel(0x100, nfc->regs + NFC_REG_TIMING_CTL); | ||
1386 | writel(0x7ff, nfc->regs + NFC_REG_TIMING_CFG); | ||
1387 | |||
1388 | ret = sunxi_nand_chips_init(dev, nfc); | ||
1389 | if (ret) { | ||
1390 | dev_err(dev, "failed to init nand chips\n"); | ||
1391 | goto out_mod_clk_unprepare; | ||
1392 | } | ||
1393 | |||
1394 | return 0; | ||
1395 | |||
1396 | out_mod_clk_unprepare: | ||
1397 | clk_disable_unprepare(nfc->mod_clk); | ||
1398 | out_ahb_clk_unprepare: | ||
1399 | clk_disable_unprepare(nfc->ahb_clk); | ||
1400 | |||
1401 | return ret; | ||
1402 | } | ||
1403 | |||
1404 | static int sunxi_nfc_remove(struct platform_device *pdev) | ||
1405 | { | ||
1406 | struct sunxi_nfc *nfc = platform_get_drvdata(pdev); | ||
1407 | |||
1408 | sunxi_nand_chips_cleanup(nfc); | ||
1409 | |||
1410 | return 0; | ||
1411 | } | ||
1412 | |||
1413 | static const struct of_device_id sunxi_nfc_ids[] = { | ||
1414 | { .compatible = "allwinner,sun4i-a10-nand" }, | ||
1415 | { /* sentinel */ } | ||
1416 | }; | ||
1417 | MODULE_DEVICE_TABLE(of, sunxi_nfc_ids); | ||
1418 | |||
1419 | static struct platform_driver sunxi_nfc_driver = { | ||
1420 | .driver = { | ||
1421 | .name = "sunxi_nand", | ||
1422 | .of_match_table = sunxi_nfc_ids, | ||
1423 | }, | ||
1424 | .probe = sunxi_nfc_probe, | ||
1425 | .remove = sunxi_nfc_remove, | ||
1426 | }; | ||
1427 | module_platform_driver(sunxi_nfc_driver); | ||
1428 | |||
1429 | MODULE_LICENSE("GPL v2"); | ||
1430 | MODULE_AUTHOR("Boris BREZILLON"); | ||
1431 | MODULE_DESCRIPTION("Allwinner NAND Flash Controller driver"); | ||
1432 | MODULE_ALIAS("platform:sunxi_nand"); | ||