OpenWrt – Blame information for rev 3
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | /* |
2 | * Driver for the built-in NAND controller of the Atheros AR934x SoCs |
||
3 | * |
||
4 | * Copyright (C) 2011-2013 Gabor Juhos <juhosg@openwrt.org> |
||
5 | * |
||
6 | * This program is free software; you can redistribute it and/or modify it |
||
7 | * under the terms of the GNU General Public License version 2 as published |
||
8 | * by the Free Software Foundation. |
||
9 | */ |
||
10 | |||
11 | #include <linux/init.h> |
||
12 | #include <linux/interrupt.h> |
||
13 | #include <linux/module.h> |
||
14 | #include <linux/dma-mapping.h> |
||
15 | #include <linux/mtd/mtd.h> |
||
16 | #include <linux/mtd/nand.h> |
||
17 | #include <linux/mtd/partitions.h> |
||
18 | #include <linux/platform_device.h> |
||
19 | #include <linux/delay.h> |
||
20 | #include <linux/slab.h> |
||
3 | office | 21 | #include <linux/version.h> |
1 | office | 22 | |
23 | #include <linux/platform/ar934x_nfc.h> |
||
24 | |||
25 | #define AR934X_NFC_REG_CMD 0x00 |
||
26 | #define AR934X_NFC_REG_CTRL 0x04 |
||
27 | #define AR934X_NFC_REG_STATUS 0x08 |
||
28 | #define AR934X_NFC_REG_INT_MASK 0x0c |
||
29 | #define AR934X_NFC_REG_INT_STATUS 0x10 |
||
30 | #define AR934X_NFC_REG_ECC_CTRL 0x14 |
||
31 | #define AR934X_NFC_REG_ECC_OFFSET 0x18 |
||
32 | #define AR934X_NFC_REG_ADDR0_0 0x1c |
||
33 | #define AR934X_NFC_REG_ADDR0_1 0x24 |
||
34 | #define AR934X_NFC_REG_ADDR1_0 0x20 |
||
35 | #define AR934X_NFC_REG_ADDR1_1 0x28 |
||
36 | #define AR934X_NFC_REG_SPARE_SIZE 0x30 |
||
37 | #define AR934X_NFC_REG_PROTECT 0x38 |
||
38 | #define AR934X_NFC_REG_LOOKUP_EN 0x40 |
||
39 | #define AR934X_NFC_REG_LOOKUP(_x) (0x44 + (_i) * 4) |
||
40 | #define AR934X_NFC_REG_DMA_ADDR 0x64 |
||
41 | #define AR934X_NFC_REG_DMA_COUNT 0x68 |
||
42 | #define AR934X_NFC_REG_DMA_CTRL 0x6c |
||
43 | #define AR934X_NFC_REG_MEM_CTRL 0x80 |
||
44 | #define AR934X_NFC_REG_DATA_SIZE 0x84 |
||
45 | #define AR934X_NFC_REG_READ_STATUS 0x88 |
||
46 | #define AR934X_NFC_REG_TIME_SEQ 0x8c |
||
47 | #define AR934X_NFC_REG_TIMINGS_ASYN 0x90 |
||
48 | #define AR934X_NFC_REG_TIMINGS_SYN 0x94 |
||
49 | #define AR934X_NFC_REG_FIFO_DATA 0x98 |
||
50 | #define AR934X_NFC_REG_TIME_MODE 0x9c |
||
51 | #define AR934X_NFC_REG_DMA_ADDR_OFFS 0xa0 |
||
52 | #define AR934X_NFC_REG_FIFO_INIT 0xb0 |
||
53 | #define AR934X_NFC_REG_GEN_SEQ_CTRL 0xb4 |
||
54 | |||
55 | #define AR934X_NFC_CMD_CMD_SEQ_S 0 |
||
56 | #define AR934X_NFC_CMD_CMD_SEQ_M 0x3f |
||
57 | #define AR934X_NFC_CMD_SEQ_1C 0x00 |
||
58 | #define AR934X_NFC_CMD_SEQ_ERASE 0x0e |
||
59 | #define AR934X_NFC_CMD_SEQ_12 0x0c |
||
60 | #define AR934X_NFC_CMD_SEQ_1C1AXR 0x21 |
||
61 | #define AR934X_NFC_CMD_SEQ_S 0x24 |
||
62 | #define AR934X_NFC_CMD_SEQ_1C3AXR 0x27 |
||
63 | #define AR934X_NFC_CMD_SEQ_1C5A1CXR 0x2a |
||
64 | #define AR934X_NFC_CMD_SEQ_18 0x32 |
||
65 | #define AR934X_NFC_CMD_INPUT_SEL_SIU 0 |
||
66 | #define AR934X_NFC_CMD_INPUT_SEL_DMA BIT(6) |
||
67 | #define AR934X_NFC_CMD_ADDR_SEL_0 0 |
||
68 | #define AR934X_NFC_CMD_ADDR_SEL_1 BIT(7) |
||
69 | #define AR934X_NFC_CMD_CMD0_S 8 |
||
70 | #define AR934X_NFC_CMD_CMD0_M 0xff |
||
71 | #define AR934X_NFC_CMD_CMD1_S 16 |
||
72 | #define AR934X_NFC_CMD_CMD1_M 0xff |
||
73 | #define AR934X_NFC_CMD_CMD2_S 24 |
||
74 | #define AR934X_NFC_CMD_CMD2_M 0xff |
||
75 | |||
76 | #define AR934X_NFC_CTRL_ADDR_CYCLE0_M 0x7 |
||
77 | #define AR934X_NFC_CTRL_ADDR_CYCLE0_S 0 |
||
78 | #define AR934X_NFC_CTRL_SPARE_EN BIT(3) |
||
79 | #define AR934X_NFC_CTRL_INT_EN BIT(4) |
||
80 | #define AR934X_NFC_CTRL_ECC_EN BIT(5) |
||
81 | #define AR934X_NFC_CTRL_BLOCK_SIZE_S 6 |
||
82 | #define AR934X_NFC_CTRL_BLOCK_SIZE_M 0x3 |
||
83 | #define AR934X_NFC_CTRL_BLOCK_SIZE_32 0 |
||
84 | #define AR934X_NFC_CTRL_BLOCK_SIZE_64 1 |
||
85 | #define AR934X_NFC_CTRL_BLOCK_SIZE_128 2 |
||
86 | #define AR934X_NFC_CTRL_BLOCK_SIZE_256 3 |
||
87 | #define AR934X_NFC_CTRL_PAGE_SIZE_S 8 |
||
88 | #define AR934X_NFC_CTRL_PAGE_SIZE_M 0x7 |
||
89 | #define AR934X_NFC_CTRL_PAGE_SIZE_256 0 |
||
90 | #define AR934X_NFC_CTRL_PAGE_SIZE_512 1 |
||
91 | #define AR934X_NFC_CTRL_PAGE_SIZE_1024 2 |
||
92 | #define AR934X_NFC_CTRL_PAGE_SIZE_2048 3 |
||
93 | #define AR934X_NFC_CTRL_PAGE_SIZE_4096 4 |
||
94 | #define AR934X_NFC_CTRL_PAGE_SIZE_8192 5 |
||
95 | #define AR934X_NFC_CTRL_PAGE_SIZE_16384 6 |
||
96 | #define AR934X_NFC_CTRL_CUSTOM_SIZE_EN BIT(11) |
||
97 | #define AR934X_NFC_CTRL_IO_WIDTH_8BITS 0 |
||
98 | #define AR934X_NFC_CTRL_IO_WIDTH_16BITS BIT(12) |
||
99 | #define AR934X_NFC_CTRL_LOOKUP_EN BIT(13) |
||
100 | #define AR934X_NFC_CTRL_PROT_EN BIT(14) |
||
101 | #define AR934X_NFC_CTRL_WORK_MODE_ASYNC 0 |
||
102 | #define AR934X_NFC_CTRL_WORK_MODE_SYNC BIT(15) |
||
103 | #define AR934X_NFC_CTRL_ADDR0_AUTO_INC BIT(16) |
||
104 | #define AR934X_NFC_CTRL_ADDR1_AUTO_INC BIT(17) |
||
105 | #define AR934X_NFC_CTRL_ADDR_CYCLE1_M 0x7 |
||
106 | #define AR934X_NFC_CTRL_ADDR_CYCLE1_S 18 |
||
107 | #define AR934X_NFC_CTRL_SMALL_PAGE BIT(21) |
||
108 | |||
109 | #define AR934X_NFC_DMA_CTRL_DMA_START BIT(7) |
||
110 | #define AR934X_NFC_DMA_CTRL_DMA_DIR_WRITE 0 |
||
111 | #define AR934X_NFC_DMA_CTRL_DMA_DIR_READ BIT(6) |
||
112 | #define AR934X_NFC_DMA_CTRL_DMA_MODE_SG BIT(5) |
||
113 | #define AR934X_NFC_DMA_CTRL_DMA_BURST_S 2 |
||
114 | #define AR934X_NFC_DMA_CTRL_DMA_BURST_0 0 |
||
115 | #define AR934X_NFC_DMA_CTRL_DMA_BURST_1 1 |
||
116 | #define AR934X_NFC_DMA_CTRL_DMA_BURST_2 2 |
||
117 | #define AR934X_NFC_DMA_CTRL_DMA_BURST_3 3 |
||
118 | #define AR934X_NFC_DMA_CTRL_DMA_BURST_4 4 |
||
119 | #define AR934X_NFC_DMA_CTRL_DMA_BURST_5 5 |
||
120 | #define AR934X_NFC_DMA_CTRL_ERR_FLAG BIT(1) |
||
121 | #define AR934X_NFC_DMA_CTRL_DMA_READY BIT(0) |
||
122 | |||
123 | #define AR934X_NFC_INT_DEV_RDY(_x) BIT(4 + (_x)) |
||
124 | #define AR934X_NFC_INT_CMD_END BIT(1) |
||
125 | |||
126 | #define AR934X_NFC_ECC_CTRL_ERR_THRES_S 8 |
||
127 | #define AR934X_NFC_ECC_CTRL_ERR_THRES_M 0x1f |
||
128 | #define AR934X_NFC_ECC_CTRL_ECC_CAP_S 5 |
||
129 | #define AR934X_NFC_ECC_CTRL_ECC_CAP_M 0x7 |
||
130 | #define AR934X_NFC_ECC_CTRL_ECC_CAP_2 0 |
||
131 | #define AR934X_NFC_ECC_CTRL_ECC_CAP_4 1 |
||
132 | #define AR934X_NFC_ECC_CTRL_ECC_CAP_6 2 |
||
133 | #define AR934X_NFC_ECC_CTRL_ECC_CAP_8 3 |
||
134 | #define AR934X_NFC_ECC_CTRL_ECC_CAP_10 4 |
||
135 | #define AR934X_NFC_ECC_CTRL_ECC_CAP_12 5 |
||
136 | #define AR934X_NFC_ECC_CTRL_ECC_CAP_14 6 |
||
137 | #define AR934X_NFC_ECC_CTRL_ECC_CAP_16 7 |
||
138 | #define AR934X_NFC_ECC_CTRL_ERR_OVER BIT(2) |
||
139 | #define AR934X_NFC_ECC_CTRL_ERR_UNCORRECT BIT(1) |
||
140 | #define AR934X_NFC_ECC_CTRL_ERR_CORRECT BIT(0) |
||
141 | |||
142 | #define AR934X_NFC_ECC_OFFS_OFSET_M 0xffff |
||
143 | |||
144 | /* default timing values */ |
||
145 | #define AR934X_NFC_TIME_SEQ_DEFAULT 0x7fff |
||
146 | #define AR934X_NFC_TIMINGS_ASYN_DEFAULT 0x22 |
||
147 | #define AR934X_NFC_TIMINGS_SYN_DEFAULT 0xf |
||
148 | |||
149 | #define AR934X_NFC_ID_BUF_SIZE 8 |
||
150 | #define AR934X_NFC_DEV_READY_TIMEOUT 25 /* msecs */ |
||
151 | #define AR934X_NFC_DMA_READY_TIMEOUT 25 /* msecs */ |
||
152 | #define AR934X_NFC_DONE_TIMEOUT 1000 |
||
153 | #define AR934X_NFC_DMA_RETRIES 20 |
||
154 | |||
155 | #define AR934X_NFC_USE_IRQ true |
||
156 | #define AR934X_NFC_IRQ_MASK AR934X_NFC_INT_DEV_RDY(0) |
||
157 | |||
158 | #define AR934X_NFC_GENSEQ_SMALL_PAGE_READ 0x30043 |
||
159 | |||
160 | #undef AR934X_NFC_DEBUG_DATA |
||
161 | #undef AR934X_NFC_DEBUG |
||
162 | |||
163 | struct ar934x_nfc; |
||
164 | |||
165 | static inline __attribute__ ((format (printf, 2, 3))) |
||
166 | void _nfc_dbg(struct ar934x_nfc *nfc, const char *fmt, ...) |
||
167 | { |
||
168 | } |
||
169 | |||
170 | #ifdef AR934X_NFC_DEBUG |
||
171 | #define nfc_dbg(_nfc, fmt, ...) \ |
||
172 | dev_info((_nfc)->parent, fmt, ##__VA_ARGS__) |
||
173 | #else |
||
174 | #define nfc_dbg(_nfc, fmt, ...) \ |
||
175 | _nfc_dbg((_nfc), fmt, ##__VA_ARGS__) |
||
176 | #endif /* AR934X_NFC_DEBUG */ |
||
177 | |||
178 | #ifdef AR934X_NFC_DEBUG_DATA |
||
179 | static void |
||
180 | nfc_debug_data(const char *label, void *data, int len) |
||
181 | { |
||
182 | print_hex_dump(KERN_WARNING, label, DUMP_PREFIX_OFFSET, 16, 1, |
||
183 | data, len, 0); |
||
184 | } |
||
185 | #else |
||
186 | static inline void |
||
187 | nfc_debug_data(const char *label, void *data, int len) {} |
||
188 | #endif /* AR934X_NFC_DEBUG_DATA */ |
||
189 | |||
190 | struct ar934x_nfc { |
||
191 | #if LINUX_VERSION_CODE < KERNEL_VERSION(4,6,0) |
||
192 | struct mtd_info mtd; |
||
193 | #endif |
||
194 | struct nand_chip nand_chip; |
||
195 | struct device *parent; |
||
196 | void __iomem *base; |
||
197 | void (*select_chip)(int chip_no); |
||
198 | bool swap_dma; |
||
199 | int irq; |
||
200 | wait_queue_head_t irq_waitq; |
||
201 | |||
202 | bool spurious_irq_expected; |
||
203 | u32 irq_status; |
||
204 | |||
205 | u32 ctrl_reg; |
||
206 | u32 ecc_ctrl_reg; |
||
207 | u32 ecc_offset_reg; |
||
208 | u32 ecc_thres; |
||
209 | u32 ecc_oob_pos; |
||
210 | |||
211 | bool small_page; |
||
212 | unsigned int addr_count0; |
||
213 | unsigned int addr_count1; |
||
214 | |||
215 | u8 *buf; |
||
216 | dma_addr_t buf_dma; |
||
217 | unsigned int buf_size; |
||
218 | int buf_index; |
||
219 | |||
220 | bool read_id; |
||
221 | |||
222 | int erase1_page_addr; |
||
223 | |||
224 | int rndout_page_addr; |
||
225 | int rndout_read_cmd; |
||
226 | |||
227 | int seqin_page_addr; |
||
228 | int seqin_column; |
||
229 | int seqin_read_cmd; |
||
230 | }; |
||
231 | |||
232 | static void ar934x_nfc_restart(struct ar934x_nfc *nfc); |
||
233 | |||
234 | static inline bool |
||
235 | is_all_ff(u8 *buf, int len) |
||
236 | { |
||
237 | while (len--) |
||
238 | if (buf[len] != 0xff) |
||
239 | return false; |
||
240 | |||
241 | return true; |
||
242 | } |
||
243 | |||
244 | static inline void |
||
245 | ar934x_nfc_wr(struct ar934x_nfc *nfc, unsigned reg, u32 val) |
||
246 | { |
||
247 | __raw_writel(val, nfc->base + reg); |
||
248 | } |
||
249 | |||
250 | static inline u32 |
||
251 | ar934x_nfc_rr(struct ar934x_nfc *nfc, unsigned reg) |
||
252 | { |
||
253 | return __raw_readl(nfc->base + reg); |
||
254 | } |
||
255 | |||
256 | static inline struct ar934x_nfc_platform_data * |
||
257 | ar934x_nfc_get_platform_data(struct ar934x_nfc *nfc) |
||
258 | { |
||
259 | return nfc->parent->platform_data; |
||
260 | } |
||
261 | |||
262 | static inline struct |
||
263 | ar934x_nfc *mtd_to_ar934x_nfc(struct mtd_info *mtd) |
||
264 | { |
||
265 | #if LINUX_VERSION_CODE < KERNEL_VERSION(4,6,0) |
||
266 | return container_of(mtd, struct ar934x_nfc, mtd); |
||
267 | #else |
||
268 | struct nand_chip *chip = mtd_to_nand(mtd); |
||
269 | |||
270 | return container_of(chip, struct ar934x_nfc, nand_chip); |
||
271 | #endif |
||
272 | } |
||
273 | |||
274 | static struct mtd_info *ar934x_nfc_to_mtd(struct ar934x_nfc *nfc) |
||
275 | { |
||
276 | #if LINUX_VERSION_CODE < KERNEL_VERSION(4,6,0) |
||
277 | return &nfc->mtd; |
||
278 | #else |
||
279 | return nand_to_mtd(&nfc->nand_chip); |
||
280 | #endif |
||
281 | } |
||
282 | |||
283 | static inline bool ar934x_nfc_use_irq(struct ar934x_nfc *nfc) |
||
284 | { |
||
285 | return AR934X_NFC_USE_IRQ; |
||
286 | } |
||
287 | |||
288 | static inline void ar934x_nfc_write_cmd_reg(struct ar934x_nfc *nfc, u32 cmd_reg) |
||
289 | { |
||
290 | wmb(); |
||
291 | |||
292 | ar934x_nfc_wr(nfc, AR934X_NFC_REG_CMD, cmd_reg); |
||
293 | /* flush write */ |
||
294 | ar934x_nfc_rr(nfc, AR934X_NFC_REG_CMD); |
||
295 | } |
||
296 | |||
297 | static bool |
||
298 | __ar934x_nfc_dev_ready(struct ar934x_nfc *nfc) |
||
299 | { |
||
300 | u32 status; |
||
301 | |||
302 | status = ar934x_nfc_rr(nfc, AR934X_NFC_REG_STATUS); |
||
303 | return (status & 0xff) == 0xff; |
||
304 | } |
||
305 | |||
306 | static inline bool |
||
307 | __ar934x_nfc_is_dma_ready(struct ar934x_nfc *nfc) |
||
308 | { |
||
309 | u32 status; |
||
310 | |||
311 | status = ar934x_nfc_rr(nfc, AR934X_NFC_REG_DMA_CTRL); |
||
312 | return (status & AR934X_NFC_DMA_CTRL_DMA_READY) != 0; |
||
313 | } |
||
314 | |||
315 | static int |
||
316 | ar934x_nfc_wait_dev_ready(struct ar934x_nfc *nfc) |
||
317 | { |
||
318 | unsigned long timeout; |
||
319 | |||
320 | timeout = jiffies + msecs_to_jiffies(AR934X_NFC_DEV_READY_TIMEOUT); |
||
321 | do { |
||
322 | if (__ar934x_nfc_dev_ready(nfc)) |
||
323 | return 0; |
||
324 | } while time_before(jiffies, timeout); |
||
325 | |||
326 | nfc_dbg(nfc, "timeout waiting for device ready, status:%08x int:%08x\n", |
||
327 | ar934x_nfc_rr(nfc, AR934X_NFC_REG_STATUS), |
||
328 | ar934x_nfc_rr(nfc, AR934X_NFC_REG_INT_STATUS)); |
||
329 | return -ETIMEDOUT; |
||
330 | } |
||
331 | |||
332 | static int |
||
333 | ar934x_nfc_wait_dma_ready(struct ar934x_nfc *nfc) |
||
334 | { |
||
335 | unsigned long timeout; |
||
336 | |||
337 | timeout = jiffies + msecs_to_jiffies(AR934X_NFC_DMA_READY_TIMEOUT); |
||
338 | do { |
||
339 | if (__ar934x_nfc_is_dma_ready(nfc)) |
||
340 | return 0; |
||
341 | } while time_before(jiffies, timeout); |
||
342 | |||
343 | nfc_dbg(nfc, "timeout waiting for DMA ready, dma_ctrl:%08x\n", |
||
344 | ar934x_nfc_rr(nfc, AR934X_NFC_REG_DMA_CTRL)); |
||
345 | return -ETIMEDOUT; |
||
346 | } |
||
347 | |||
348 | static int |
||
349 | ar934x_nfc_wait_irq(struct ar934x_nfc *nfc) |
||
350 | { |
||
351 | long timeout; |
||
352 | int ret; |
||
353 | |||
354 | timeout = wait_event_timeout(nfc->irq_waitq, |
||
355 | (nfc->irq_status & AR934X_NFC_IRQ_MASK) != 0, |
||
356 | msecs_to_jiffies(AR934X_NFC_DEV_READY_TIMEOUT)); |
||
357 | |||
358 | ret = 0; |
||
359 | if (!timeout) { |
||
360 | ar934x_nfc_wr(nfc, AR934X_NFC_REG_INT_MASK, 0); |
||
361 | ar934x_nfc_wr(nfc, AR934X_NFC_REG_INT_STATUS, 0); |
||
362 | /* flush write */ |
||
363 | ar934x_nfc_rr(nfc, AR934X_NFC_REG_INT_STATUS); |
||
364 | |||
365 | nfc_dbg(nfc, |
||
366 | "timeout waiting for interrupt, status:%08x\n", |
||
367 | nfc->irq_status); |
||
368 | ret = -ETIMEDOUT; |
||
369 | } |
||
370 | |||
371 | nfc->irq_status = 0; |
||
372 | return ret; |
||
373 | } |
||
374 | |||
375 | static int |
||
376 | ar934x_nfc_wait_done(struct ar934x_nfc *nfc) |
||
377 | { |
||
378 | int ret; |
||
379 | |||
380 | if (ar934x_nfc_use_irq(nfc)) |
||
381 | ret = ar934x_nfc_wait_irq(nfc); |
||
382 | else |
||
383 | ret = ar934x_nfc_wait_dev_ready(nfc); |
||
384 | |||
385 | if (ret) |
||
386 | return ret; |
||
387 | |||
388 | return ar934x_nfc_wait_dma_ready(nfc); |
||
389 | } |
||
390 | |||
391 | static int |
||
392 | ar934x_nfc_alloc_buf(struct ar934x_nfc *nfc, unsigned size) |
||
393 | { |
||
394 | nfc->buf = dma_alloc_coherent(nfc->parent, size, |
||
395 | &nfc->buf_dma, GFP_KERNEL); |
||
396 | if (nfc->buf == NULL) { |
||
397 | dev_err(nfc->parent, "no memory for DMA buffer\n"); |
||
398 | return -ENOMEM; |
||
399 | } |
||
400 | |||
401 | nfc->buf_size = size; |
||
402 | nfc_dbg(nfc, "buf:%p size:%u\n", nfc->buf, nfc->buf_size); |
||
403 | |||
404 | return 0; |
||
405 | } |
||
406 | |||
407 | static void |
||
408 | ar934x_nfc_free_buf(struct ar934x_nfc *nfc) |
||
409 | { |
||
410 | dma_free_coherent(nfc->parent, nfc->buf_size, nfc->buf, nfc->buf_dma); |
||
411 | } |
||
412 | |||
413 | static void |
||
414 | ar934x_nfc_get_addr(struct ar934x_nfc *nfc, int column, int page_addr, |
||
415 | u32 *addr0, u32 *addr1) |
||
416 | { |
||
417 | u32 a0, a1; |
||
418 | |||
419 | a0 = 0; |
||
420 | a1 = 0; |
||
421 | |||
422 | if (column == -1) { |
||
423 | /* ERASE1 */ |
||
424 | a0 = (page_addr & 0xffff) << 16; |
||
425 | a1 = (page_addr >> 16) & 0xf; |
||
426 | } else if (page_addr != -1) { |
||
427 | /* SEQIN, READ0, etc.. */ |
||
428 | |||
429 | /* TODO: handle 16bit bus width */ |
||
430 | if (nfc->small_page) { |
||
431 | a0 = column & 0xff; |
||
432 | a0 |= (page_addr & 0xff) << 8; |
||
433 | a0 |= ((page_addr >> 8) & 0xff) << 16; |
||
434 | a0 |= ((page_addr >> 16) & 0xff) << 24; |
||
435 | } else { |
||
436 | a0 = column & 0x0FFF; |
||
437 | a0 |= (page_addr & 0xffff) << 16; |
||
438 | |||
439 | if (nfc->addr_count0 > 4) |
||
440 | a1 = (page_addr >> 16) & 0xf; |
||
441 | } |
||
442 | } |
||
443 | |||
444 | *addr0 = a0; |
||
445 | *addr1 = a1; |
||
446 | } |
||
447 | |||
448 | static void |
||
449 | ar934x_nfc_send_cmd(struct ar934x_nfc *nfc, unsigned command) |
||
450 | { |
||
451 | u32 cmd_reg; |
||
452 | |||
453 | cmd_reg = AR934X_NFC_CMD_INPUT_SEL_SIU | AR934X_NFC_CMD_ADDR_SEL_0 | |
||
454 | AR934X_NFC_CMD_SEQ_1C; |
||
455 | cmd_reg |= (command & AR934X_NFC_CMD_CMD0_M) << AR934X_NFC_CMD_CMD0_S; |
||
456 | |||
457 | ar934x_nfc_wr(nfc, AR934X_NFC_REG_INT_STATUS, 0); |
||
458 | ar934x_nfc_wr(nfc, AR934X_NFC_REG_CTRL, nfc->ctrl_reg); |
||
459 | |||
460 | ar934x_nfc_write_cmd_reg(nfc, cmd_reg); |
||
461 | ar934x_nfc_wait_dev_ready(nfc); |
||
462 | } |
||
463 | |||
464 | static int |
||
465 | ar934x_nfc_do_rw_command(struct ar934x_nfc *nfc, int column, int page_addr, |
||
466 | int len, u32 cmd_reg, u32 ctrl_reg, bool write) |
||
467 | { |
||
468 | u32 addr0, addr1; |
||
469 | u32 dma_ctrl; |
||
470 | int dir; |
||
471 | int err; |
||
472 | int retries = 0; |
||
473 | |||
474 | WARN_ON(len & 3); |
||
475 | |||
476 | if (WARN_ON(len > nfc->buf_size)) |
||
477 | dev_err(nfc->parent, "len=%d > buf_size=%d", len, nfc->buf_size); |
||
478 | |||
479 | if (write) { |
||
480 | dma_ctrl = AR934X_NFC_DMA_CTRL_DMA_DIR_WRITE; |
||
481 | dir = DMA_TO_DEVICE; |
||
482 | } else { |
||
483 | dma_ctrl = AR934X_NFC_DMA_CTRL_DMA_DIR_READ; |
||
484 | dir = DMA_FROM_DEVICE; |
||
485 | } |
||
486 | |||
487 | ar934x_nfc_get_addr(nfc, column, page_addr, &addr0, &addr1); |
||
488 | |||
489 | dma_ctrl |= AR934X_NFC_DMA_CTRL_DMA_START | |
||
490 | (AR934X_NFC_DMA_CTRL_DMA_BURST_3 << |
||
491 | AR934X_NFC_DMA_CTRL_DMA_BURST_S); |
||
492 | |||
493 | cmd_reg |= AR934X_NFC_CMD_INPUT_SEL_DMA | AR934X_NFC_CMD_ADDR_SEL_0; |
||
494 | ctrl_reg |= AR934X_NFC_CTRL_INT_EN; |
||
495 | |||
496 | nfc_dbg(nfc, "%s a0:%08x a1:%08x len:%x cmd:%08x dma:%08x ctrl:%08x\n", |
||
497 | (write) ? "write" : "read", |
||
498 | addr0, addr1, len, cmd_reg, dma_ctrl, ctrl_reg); |
||
499 | |||
500 | retry: |
||
501 | ar934x_nfc_wr(nfc, AR934X_NFC_REG_INT_STATUS, 0); |
||
502 | ar934x_nfc_wr(nfc, AR934X_NFC_REG_ADDR0_0, addr0); |
||
503 | ar934x_nfc_wr(nfc, AR934X_NFC_REG_ADDR0_1, addr1); |
||
504 | ar934x_nfc_wr(nfc, AR934X_NFC_REG_DMA_ADDR, nfc->buf_dma); |
||
505 | ar934x_nfc_wr(nfc, AR934X_NFC_REG_DMA_COUNT, len); |
||
506 | ar934x_nfc_wr(nfc, AR934X_NFC_REG_DATA_SIZE, len); |
||
507 | ar934x_nfc_wr(nfc, AR934X_NFC_REG_CTRL, ctrl_reg); |
||
508 | ar934x_nfc_wr(nfc, AR934X_NFC_REG_DMA_CTRL, dma_ctrl); |
||
509 | ar934x_nfc_wr(nfc, AR934X_NFC_REG_ECC_CTRL, nfc->ecc_ctrl_reg); |
||
510 | ar934x_nfc_wr(nfc, AR934X_NFC_REG_ECC_OFFSET, nfc->ecc_offset_reg); |
||
511 | |||
512 | if (ar934x_nfc_use_irq(nfc)) { |
||
513 | ar934x_nfc_wr(nfc, AR934X_NFC_REG_INT_MASK, AR934X_NFC_IRQ_MASK); |
||
514 | /* flush write */ |
||
515 | ar934x_nfc_rr(nfc, AR934X_NFC_REG_INT_MASK); |
||
516 | } |
||
517 | |||
518 | ar934x_nfc_write_cmd_reg(nfc, cmd_reg); |
||
519 | err = ar934x_nfc_wait_done(nfc); |
||
520 | if (err) { |
||
521 | dev_dbg(nfc->parent, "%s operation stuck at page %d\n", |
||
522 | (write) ? "write" : "read", page_addr); |
||
523 | |||
524 | ar934x_nfc_restart(nfc); |
||
525 | if (retries++ < AR934X_NFC_DMA_RETRIES) |
||
526 | goto retry; |
||
527 | |||
528 | dev_err(nfc->parent, "%s operation failed on page %d\n", |
||
529 | (write) ? "write" : "read", page_addr); |
||
530 | } |
||
531 | |||
532 | return err; |
||
533 | } |
||
534 | |||
535 | static int |
||
536 | ar934x_nfc_send_readid(struct ar934x_nfc *nfc, unsigned command) |
||
537 | { |
||
538 | u32 cmd_reg; |
||
539 | int err; |
||
540 | |||
541 | nfc_dbg(nfc, "readid, cmd:%02x\n", command); |
||
542 | |||
543 | cmd_reg = AR934X_NFC_CMD_SEQ_1C1AXR; |
||
544 | cmd_reg |= (command & AR934X_NFC_CMD_CMD0_M) << AR934X_NFC_CMD_CMD0_S; |
||
545 | |||
546 | err = ar934x_nfc_do_rw_command(nfc, -1, -1, AR934X_NFC_ID_BUF_SIZE, |
||
547 | cmd_reg, nfc->ctrl_reg, false); |
||
548 | |||
549 | nfc_debug_data("[id] ", nfc->buf, AR934X_NFC_ID_BUF_SIZE); |
||
550 | |||
551 | return err; |
||
552 | } |
||
553 | |||
554 | static int |
||
555 | ar934x_nfc_send_read(struct ar934x_nfc *nfc, unsigned command, int column, |
||
556 | int page_addr, int len) |
||
557 | { |
||
558 | u32 cmd_reg; |
||
559 | int err; |
||
560 | |||
561 | nfc_dbg(nfc, "read, column=%d page=%d len=%d\n", |
||
562 | column, page_addr, len); |
||
563 | |||
564 | cmd_reg = (command & AR934X_NFC_CMD_CMD0_M) << AR934X_NFC_CMD_CMD0_S; |
||
565 | |||
566 | if (nfc->small_page) { |
||
567 | cmd_reg |= AR934X_NFC_CMD_SEQ_18; |
||
568 | } else { |
||
569 | cmd_reg |= NAND_CMD_READSTART << AR934X_NFC_CMD_CMD1_S; |
||
570 | cmd_reg |= AR934X_NFC_CMD_SEQ_1C5A1CXR; |
||
571 | } |
||
572 | |||
573 | err = ar934x_nfc_do_rw_command(nfc, column, page_addr, len, |
||
574 | cmd_reg, nfc->ctrl_reg, false); |
||
575 | |||
576 | nfc_debug_data("[data] ", nfc->buf, len); |
||
577 | |||
578 | return err; |
||
579 | } |
||
580 | |||
581 | static void |
||
582 | ar934x_nfc_send_erase(struct ar934x_nfc *nfc, unsigned command, int column, |
||
583 | int page_addr) |
||
584 | { |
||
585 | u32 addr0, addr1; |
||
586 | u32 ctrl_reg; |
||
587 | u32 cmd_reg; |
||
588 | |||
589 | ar934x_nfc_get_addr(nfc, column, page_addr, &addr0, &addr1); |
||
590 | |||
591 | ctrl_reg = nfc->ctrl_reg; |
||
592 | if (nfc->small_page) { |
||
593 | /* override number of address cycles for the erase command */ |
||
594 | ctrl_reg &= ~(AR934X_NFC_CTRL_ADDR_CYCLE0_M << |
||
595 | AR934X_NFC_CTRL_ADDR_CYCLE0_S); |
||
596 | ctrl_reg &= ~(AR934X_NFC_CTRL_ADDR_CYCLE1_M << |
||
597 | AR934X_NFC_CTRL_ADDR_CYCLE1_S); |
||
598 | ctrl_reg &= ~(AR934X_NFC_CTRL_SMALL_PAGE); |
||
599 | ctrl_reg |= (nfc->addr_count0 + 1) << |
||
600 | AR934X_NFC_CTRL_ADDR_CYCLE0_S; |
||
601 | } |
||
602 | |||
603 | cmd_reg = NAND_CMD_ERASE1 << AR934X_NFC_CMD_CMD0_S; |
||
604 | cmd_reg |= command << AR934X_NFC_CMD_CMD1_S; |
||
605 | cmd_reg |= AR934X_NFC_CMD_SEQ_ERASE; |
||
606 | |||
607 | nfc_dbg(nfc, "erase page %d, a0:%08x a1:%08x cmd:%08x ctrl:%08x\n", |
||
608 | page_addr, addr0, addr1, cmd_reg, ctrl_reg); |
||
609 | |||
610 | ar934x_nfc_wr(nfc, AR934X_NFC_REG_INT_STATUS, 0); |
||
611 | ar934x_nfc_wr(nfc, AR934X_NFC_REG_CTRL, ctrl_reg); |
||
612 | ar934x_nfc_wr(nfc, AR934X_NFC_REG_ADDR0_0, addr0); |
||
613 | ar934x_nfc_wr(nfc, AR934X_NFC_REG_ADDR0_1, addr1); |
||
614 | |||
615 | ar934x_nfc_write_cmd_reg(nfc, cmd_reg); |
||
616 | ar934x_nfc_wait_dev_ready(nfc); |
||
617 | } |
||
618 | |||
619 | static int |
||
620 | ar934x_nfc_send_write(struct ar934x_nfc *nfc, unsigned command, int column, |
||
621 | int page_addr, int len) |
||
622 | { |
||
623 | u32 cmd_reg; |
||
624 | |||
625 | nfc_dbg(nfc, "write, column=%d page=%d len=%d\n", |
||
626 | column, page_addr, len); |
||
627 | |||
628 | nfc_debug_data("[data] ", nfc->buf, len); |
||
629 | |||
630 | cmd_reg = NAND_CMD_SEQIN << AR934X_NFC_CMD_CMD0_S; |
||
631 | cmd_reg |= command << AR934X_NFC_CMD_CMD1_S; |
||
632 | cmd_reg |= AR934X_NFC_CMD_SEQ_12; |
||
633 | |||
634 | return ar934x_nfc_do_rw_command(nfc, column, page_addr, len, |
||
635 | cmd_reg, nfc->ctrl_reg, true); |
||
636 | } |
||
637 | |||
638 | static void |
||
639 | ar934x_nfc_read_status(struct ar934x_nfc *nfc) |
||
640 | { |
||
641 | u32 cmd_reg; |
||
642 | u32 status; |
||
643 | |||
644 | cmd_reg = NAND_CMD_STATUS << AR934X_NFC_CMD_CMD0_S; |
||
645 | cmd_reg |= AR934X_NFC_CMD_SEQ_S; |
||
646 | |||
647 | ar934x_nfc_wr(nfc, AR934X_NFC_REG_INT_STATUS, 0); |
||
648 | ar934x_nfc_wr(nfc, AR934X_NFC_REG_CTRL, nfc->ctrl_reg); |
||
649 | |||
650 | ar934x_nfc_write_cmd_reg(nfc, cmd_reg); |
||
651 | ar934x_nfc_wait_dev_ready(nfc); |
||
652 | |||
653 | status = ar934x_nfc_rr(nfc, AR934X_NFC_REG_READ_STATUS); |
||
654 | |||
655 | nfc_dbg(nfc, "read status, cmd:%08x status:%02x\n", |
||
656 | cmd_reg, (status & 0xff)); |
||
657 | |||
658 | if (nfc->swap_dma) |
||
659 | nfc->buf[0 ^ 3] = status; |
||
660 | else |
||
661 | nfc->buf[0] = status; |
||
662 | } |
||
663 | |||
664 | static void |
||
665 | ar934x_nfc_cmdfunc(struct mtd_info *mtd, unsigned int command, int column, |
||
666 | int page_addr) |
||
667 | { |
||
668 | struct ar934x_nfc *nfc = mtd_to_ar934x_nfc(mtd); |
||
669 | struct nand_chip *nand = &nfc->nand_chip; |
||
670 | |||
671 | nfc->read_id = false; |
||
672 | if (command != NAND_CMD_PAGEPROG) |
||
673 | nfc->buf_index = 0; |
||
674 | |||
675 | switch (command) { |
||
676 | case NAND_CMD_RESET: |
||
677 | ar934x_nfc_send_cmd(nfc, command); |
||
678 | break; |
||
679 | |||
680 | case NAND_CMD_READID: |
||
681 | nfc->read_id = true; |
||
682 | ar934x_nfc_send_readid(nfc, command); |
||
683 | break; |
||
684 | |||
685 | case NAND_CMD_READ0: |
||
686 | case NAND_CMD_READ1: |
||
687 | if (nfc->small_page) { |
||
688 | ar934x_nfc_send_read(nfc, command, column, page_addr, |
||
689 | mtd->writesize + mtd->oobsize); |
||
690 | } else { |
||
691 | ar934x_nfc_send_read(nfc, command, 0, page_addr, |
||
692 | mtd->writesize + mtd->oobsize); |
||
693 | nfc->buf_index = column; |
||
694 | nfc->rndout_page_addr = page_addr; |
||
695 | nfc->rndout_read_cmd = command; |
||
696 | } |
||
697 | break; |
||
698 | |||
699 | case NAND_CMD_READOOB: |
||
700 | if (nfc->small_page) |
||
701 | ar934x_nfc_send_read(nfc, NAND_CMD_READOOB, |
||
702 | column, page_addr, |
||
703 | mtd->oobsize); |
||
704 | else |
||
705 | ar934x_nfc_send_read(nfc, NAND_CMD_READ0, |
||
706 | mtd->writesize, page_addr, |
||
707 | mtd->oobsize); |
||
708 | break; |
||
709 | |||
710 | case NAND_CMD_RNDOUT: |
||
711 | if (WARN_ON(nfc->small_page)) |
||
712 | break; |
||
713 | |||
714 | /* emulate subpage read */ |
||
715 | ar934x_nfc_send_read(nfc, nfc->rndout_read_cmd, 0, |
||
716 | nfc->rndout_page_addr, |
||
717 | mtd->writesize + mtd->oobsize); |
||
718 | nfc->buf_index = column; |
||
719 | break; |
||
720 | |||
721 | case NAND_CMD_ERASE1: |
||
722 | nfc->erase1_page_addr = page_addr; |
||
723 | break; |
||
724 | |||
725 | case NAND_CMD_ERASE2: |
||
726 | ar934x_nfc_send_erase(nfc, command, -1, nfc->erase1_page_addr); |
||
727 | break; |
||
728 | |||
729 | case NAND_CMD_STATUS: |
||
730 | ar934x_nfc_read_status(nfc); |
||
731 | break; |
||
732 | |||
733 | case NAND_CMD_SEQIN: |
||
734 | if (nfc->small_page) { |
||
735 | /* output read command */ |
||
736 | if (column >= mtd->writesize) { |
||
737 | column -= mtd->writesize; |
||
738 | nfc->seqin_read_cmd = NAND_CMD_READOOB; |
||
739 | } else if (column < 256) { |
||
740 | nfc->seqin_read_cmd = NAND_CMD_READ0; |
||
741 | } else { |
||
742 | column -= 256; |
||
743 | nfc->seqin_read_cmd = NAND_CMD_READ1; |
||
744 | } |
||
745 | } else { |
||
746 | nfc->seqin_read_cmd = NAND_CMD_READ0; |
||
747 | } |
||
748 | nfc->seqin_column = column; |
||
749 | nfc->seqin_page_addr = page_addr; |
||
750 | break; |
||
751 | |||
752 | case NAND_CMD_PAGEPROG: |
||
753 | if (nand->ecc.mode == NAND_ECC_HW) { |
||
754 | /* the data is already written */ |
||
755 | break; |
||
756 | } |
||
757 | |||
758 | if (nfc->small_page) |
||
759 | ar934x_nfc_send_cmd(nfc, nfc->seqin_read_cmd); |
||
760 | |||
761 | ar934x_nfc_send_write(nfc, command, nfc->seqin_column, |
||
762 | nfc->seqin_page_addr, |
||
763 | nfc->buf_index); |
||
764 | break; |
||
765 | |||
766 | default: |
||
767 | dev_err(nfc->parent, |
||
768 | "unsupported command: %x, column:%d page_addr=%d\n", |
||
769 | command, column, page_addr); |
||
770 | break; |
||
771 | } |
||
772 | } |
||
773 | |||
774 | static int |
||
775 | ar934x_nfc_dev_ready(struct mtd_info *mtd) |
||
776 | { |
||
777 | struct ar934x_nfc *nfc = mtd_to_ar934x_nfc(mtd); |
||
778 | |||
779 | return __ar934x_nfc_dev_ready(nfc); |
||
780 | } |
||
781 | |||
782 | static void |
||
783 | ar934x_nfc_select_chip(struct mtd_info *mtd, int chip_no) |
||
784 | { |
||
785 | struct ar934x_nfc *nfc = mtd_to_ar934x_nfc(mtd); |
||
786 | |||
787 | if (nfc->select_chip) |
||
788 | nfc->select_chip(chip_no); |
||
789 | } |
||
790 | |||
791 | static u8 |
||
792 | ar934x_nfc_read_byte(struct mtd_info *mtd) |
||
793 | { |
||
794 | struct ar934x_nfc *nfc = mtd_to_ar934x_nfc(mtd); |
||
795 | u8 data; |
||
796 | |||
797 | WARN_ON(nfc->buf_index >= nfc->buf_size); |
||
798 | |||
799 | if (nfc->swap_dma || nfc->read_id) |
||
800 | data = nfc->buf[nfc->buf_index ^ 3]; |
||
801 | else |
||
802 | data = nfc->buf[nfc->buf_index]; |
||
803 | |||
804 | nfc->buf_index++; |
||
805 | |||
806 | return data; |
||
807 | } |
||
808 | |||
809 | static void |
||
810 | ar934x_nfc_write_buf(struct mtd_info *mtd, const u8 *buf, int len) |
||
811 | { |
||
812 | struct ar934x_nfc *nfc = mtd_to_ar934x_nfc(mtd); |
||
813 | int i; |
||
814 | |||
815 | WARN_ON(nfc->buf_index + len > nfc->buf_size); |
||
816 | |||
817 | if (nfc->swap_dma) { |
||
818 | for (i = 0; i < len; i++) { |
||
819 | nfc->buf[nfc->buf_index ^ 3] = buf[i]; |
||
820 | nfc->buf_index++; |
||
821 | } |
||
822 | } else { |
||
823 | for (i = 0; i < len; i++) { |
||
824 | nfc->buf[nfc->buf_index] = buf[i]; |
||
825 | nfc->buf_index++; |
||
826 | } |
||
827 | } |
||
828 | } |
||
829 | |||
830 | static void |
||
831 | ar934x_nfc_read_buf(struct mtd_info *mtd, u8 *buf, int len) |
||
832 | { |
||
833 | struct ar934x_nfc *nfc = mtd_to_ar934x_nfc(mtd); |
||
834 | int buf_index; |
||
835 | int i; |
||
836 | |||
837 | WARN_ON(nfc->buf_index + len > nfc->buf_size); |
||
838 | |||
839 | buf_index = nfc->buf_index; |
||
840 | |||
841 | if (nfc->swap_dma || nfc->read_id) { |
||
842 | for (i = 0; i < len; i++) { |
||
843 | buf[i] = nfc->buf[buf_index ^ 3]; |
||
844 | buf_index++; |
||
845 | } |
||
846 | } else { |
||
847 | for (i = 0; i < len; i++) { |
||
848 | buf[i] = nfc->buf[buf_index]; |
||
849 | buf_index++; |
||
850 | } |
||
851 | } |
||
852 | |||
853 | nfc->buf_index = buf_index; |
||
854 | } |
||
855 | |||
856 | static inline void |
||
857 | ar934x_nfc_enable_hwecc(struct ar934x_nfc *nfc) |
||
858 | { |
||
859 | nfc->ctrl_reg |= AR934X_NFC_CTRL_ECC_EN; |
||
860 | nfc->ctrl_reg &= ~AR934X_NFC_CTRL_CUSTOM_SIZE_EN; |
||
861 | } |
||
862 | |||
863 | static inline void |
||
864 | ar934x_nfc_disable_hwecc(struct ar934x_nfc *nfc) |
||
865 | { |
||
866 | nfc->ctrl_reg &= ~AR934X_NFC_CTRL_ECC_EN; |
||
867 | nfc->ctrl_reg |= AR934X_NFC_CTRL_CUSTOM_SIZE_EN; |
||
868 | } |
||
869 | |||
870 | static int |
||
871 | ar934x_nfc_read_oob(struct mtd_info *mtd, struct nand_chip *chip, |
||
872 | int page) |
||
873 | { |
||
874 | struct ar934x_nfc *nfc = mtd_to_ar934x_nfc(mtd); |
||
875 | int err; |
||
876 | |||
877 | nfc_dbg(nfc, "read_oob: page:%d\n", page); |
||
878 | |||
879 | err = ar934x_nfc_send_read(nfc, NAND_CMD_READ0, mtd->writesize, page, |
||
880 | mtd->oobsize); |
||
881 | if (err) |
||
882 | return err; |
||
883 | |||
884 | memcpy(chip->oob_poi, nfc->buf, mtd->oobsize); |
||
885 | |||
886 | return 0; |
||
887 | } |
||
888 | |||
889 | static int |
||
890 | ar934x_nfc_write_oob(struct mtd_info *mtd, struct nand_chip *chip, |
||
891 | int page) |
||
892 | { |
||
893 | struct ar934x_nfc *nfc = mtd_to_ar934x_nfc(mtd); |
||
894 | |||
895 | nfc_dbg(nfc, "write_oob: page:%d\n", page); |
||
896 | |||
897 | memcpy(nfc->buf, chip->oob_poi, mtd->oobsize); |
||
898 | |||
899 | return ar934x_nfc_send_write(nfc, NAND_CMD_PAGEPROG, mtd->writesize, |
||
900 | page, mtd->oobsize); |
||
901 | } |
||
902 | |||
903 | static int |
||
904 | ar934x_nfc_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, |
||
905 | u8 *buf, int oob_required, int page) |
||
906 | { |
||
907 | struct ar934x_nfc *nfc = mtd_to_ar934x_nfc(mtd); |
||
908 | int len; |
||
909 | int err; |
||
910 | |||
911 | nfc_dbg(nfc, "read_page_raw: page:%d oob:%d\n", page, oob_required); |
||
912 | |||
913 | len = mtd->writesize; |
||
914 | if (oob_required) |
||
915 | len += mtd->oobsize; |
||
916 | |||
917 | err = ar934x_nfc_send_read(nfc, NAND_CMD_READ0, 0, page, len); |
||
918 | if (err) |
||
919 | return err; |
||
920 | |||
921 | memcpy(buf, nfc->buf, mtd->writesize); |
||
922 | |||
923 | if (oob_required) |
||
924 | memcpy(chip->oob_poi, &nfc->buf[mtd->writesize], mtd->oobsize); |
||
925 | |||
926 | return 0; |
||
927 | } |
||
928 | |||
929 | static int |
||
930 | ar934x_nfc_read_page(struct mtd_info *mtd, struct nand_chip *chip, |
||
931 | u8 *buf, int oob_required, int page) |
||
932 | { |
||
933 | struct ar934x_nfc *nfc = mtd_to_ar934x_nfc(mtd); |
||
934 | u32 ecc_ctrl; |
||
935 | int max_bitflips = 0; |
||
936 | bool ecc_failed; |
||
937 | bool ecc_corrected; |
||
938 | int err; |
||
939 | |||
940 | nfc_dbg(nfc, "read_page: page:%d oob:%d\n", page, oob_required); |
||
941 | |||
942 | ar934x_nfc_enable_hwecc(nfc); |
||
943 | err = ar934x_nfc_send_read(nfc, NAND_CMD_READ0, 0, page, |
||
944 | mtd->writesize); |
||
945 | ar934x_nfc_disable_hwecc(nfc); |
||
946 | |||
947 | if (err) |
||
948 | return err; |
||
949 | |||
950 | /* TODO: optimize to avoid memcpy */ |
||
951 | memcpy(buf, nfc->buf, mtd->writesize); |
||
952 | |||
953 | /* read the ECC status */ |
||
954 | ecc_ctrl = ar934x_nfc_rr(nfc, AR934X_NFC_REG_ECC_CTRL); |
||
955 | ecc_failed = ecc_ctrl & AR934X_NFC_ECC_CTRL_ERR_UNCORRECT; |
||
956 | ecc_corrected = ecc_ctrl & AR934X_NFC_ECC_CTRL_ERR_CORRECT; |
||
957 | |||
958 | if (oob_required || ecc_failed) { |
||
959 | err = ar934x_nfc_send_read(nfc, NAND_CMD_READ0, mtd->writesize, |
||
960 | page, mtd->oobsize); |
||
961 | if (err) |
||
962 | return err; |
||
963 | |||
964 | if (oob_required) |
||
965 | memcpy(chip->oob_poi, nfc->buf, mtd->oobsize); |
||
966 | } |
||
967 | |||
968 | if (ecc_failed) { |
||
969 | /* |
||
970 | * The hardware ECC engine reports uncorrectable errors |
||
971 | * on empty pages. Check the ECC bytes and the data. If |
||
972 | * both contains 0xff bytes only, dont report a failure. |
||
973 | * |
||
974 | * TODO: prebuild a buffer with 0xff bytes and use memcmp |
||
975 | * for better performance? |
||
976 | */ |
||
977 | if (!is_all_ff(&nfc->buf[nfc->ecc_oob_pos], chip->ecc.total) || |
||
978 | !is_all_ff(buf, mtd->writesize)) |
||
979 | mtd->ecc_stats.failed++; |
||
980 | } else if (ecc_corrected) { |
||
981 | /* |
||
982 | * The hardware does not report the exact count of the |
||
983 | * corrected bitflips, use assumptions based on the |
||
984 | * threshold. |
||
985 | */ |
||
986 | if (ecc_ctrl & AR934X_NFC_ECC_CTRL_ERR_OVER) { |
||
987 | /* |
||
988 | * The number of corrected bitflips exceeds the |
||
989 | * threshold. Assume the maximum. |
||
990 | */ |
||
991 | max_bitflips = chip->ecc.strength * chip->ecc.steps; |
||
992 | } else { |
||
993 | max_bitflips = nfc->ecc_thres * chip->ecc.steps; |
||
994 | } |
||
995 | |||
996 | mtd->ecc_stats.corrected += max_bitflips; |
||
997 | } |
||
998 | |||
999 | return max_bitflips; |
||
1000 | } |
||
1001 | |||
1002 | static int |
||
1003 | ar934x_nfc_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, |
||
1004 | const u8 *buf, int oob_required, int page) |
||
1005 | { |
||
1006 | struct ar934x_nfc *nfc = mtd_to_ar934x_nfc(mtd); |
||
1007 | int len; |
||
1008 | |||
1009 | nfc_dbg(nfc, "write_page_raw: page:%d oob:%d\n", page, oob_required); |
||
1010 | |||
1011 | memcpy(nfc->buf, buf, mtd->writesize); |
||
1012 | len = mtd->writesize; |
||
1013 | |||
1014 | if (oob_required) { |
||
1015 | memcpy(&nfc->buf[mtd->writesize], chip->oob_poi, mtd->oobsize); |
||
1016 | len += mtd->oobsize; |
||
1017 | } |
||
1018 | |||
1019 | return ar934x_nfc_send_write(nfc, NAND_CMD_PAGEPROG, 0, page, len); |
||
1020 | } |
||
1021 | |||
1022 | static int |
||
1023 | ar934x_nfc_write_page(struct mtd_info *mtd, struct nand_chip *chip, |
||
1024 | const u8 *buf, int oob_required, int page) |
||
1025 | { |
||
1026 | struct ar934x_nfc *nfc = mtd_to_ar934x_nfc(mtd); |
||
1027 | int err; |
||
1028 | |||
1029 | nfc_dbg(nfc, "write_page: page:%d oob:%d\n", page, oob_required); |
||
1030 | |||
1031 | /* write OOB first */ |
||
1032 | if (oob_required && |
||
1033 | !is_all_ff(chip->oob_poi, mtd->oobsize)) { |
||
1034 | err = ar934x_nfc_write_oob(mtd, chip, page); |
||
1035 | if (err) |
||
1036 | return err; |
||
1037 | } |
||
1038 | |||
1039 | /* TODO: optimize to avoid memcopy */ |
||
1040 | memcpy(nfc->buf, buf, mtd->writesize); |
||
1041 | |||
1042 | ar934x_nfc_enable_hwecc(nfc); |
||
1043 | err = ar934x_nfc_send_write(nfc, NAND_CMD_PAGEPROG, 0, page, |
||
1044 | mtd->writesize); |
||
1045 | ar934x_nfc_disable_hwecc(nfc); |
||
1046 | |||
1047 | return err; |
||
1048 | } |
||
1049 | |||
1050 | static void |
||
1051 | ar934x_nfc_hw_init(struct ar934x_nfc *nfc) |
||
1052 | { |
||
1053 | struct ar934x_nfc_platform_data *pdata; |
||
1054 | |||
1055 | pdata = ar934x_nfc_get_platform_data(nfc); |
||
1056 | if (pdata->hw_reset) { |
||
1057 | pdata->hw_reset(true); |
||
1058 | pdata->hw_reset(false); |
||
1059 | } |
||
1060 | |||
1061 | /* |
||
1062 | * setup timings |
||
1063 | * TODO: make it configurable via platform data |
||
1064 | */ |
||
1065 | ar934x_nfc_wr(nfc, AR934X_NFC_REG_TIME_SEQ, |
||
1066 | AR934X_NFC_TIME_SEQ_DEFAULT); |
||
1067 | ar934x_nfc_wr(nfc, AR934X_NFC_REG_TIMINGS_ASYN, |
||
1068 | AR934X_NFC_TIMINGS_ASYN_DEFAULT); |
||
1069 | ar934x_nfc_wr(nfc, AR934X_NFC_REG_TIMINGS_SYN, |
||
1070 | AR934X_NFC_TIMINGS_SYN_DEFAULT); |
||
1071 | |||
1072 | /* disable WP on all chips, and select chip 0 */ |
||
1073 | ar934x_nfc_wr(nfc, AR934X_NFC_REG_MEM_CTRL, 0xff00); |
||
1074 | |||
1075 | ar934x_nfc_wr(nfc, AR934X_NFC_REG_DMA_ADDR_OFFS, 0); |
||
1076 | |||
1077 | /* initialize Control register */ |
||
1078 | nfc->ctrl_reg = AR934X_NFC_CTRL_CUSTOM_SIZE_EN; |
||
1079 | ar934x_nfc_wr(nfc, AR934X_NFC_REG_CTRL, nfc->ctrl_reg); |
||
1080 | |||
1081 | if (nfc->small_page) { |
||
1082 | /* Setup generic sequence register for small page reads. */ |
||
1083 | ar934x_nfc_wr(nfc, AR934X_NFC_REG_GEN_SEQ_CTRL, |
||
1084 | AR934X_NFC_GENSEQ_SMALL_PAGE_READ); |
||
1085 | } |
||
1086 | } |
||
1087 | |||
1088 | static void |
||
1089 | ar934x_nfc_restart(struct ar934x_nfc *nfc) |
||
1090 | { |
||
1091 | u32 ctrl_reg; |
||
1092 | |||
1093 | if (nfc->select_chip) |
||
1094 | nfc->select_chip(-1); |
||
1095 | |||
1096 | ctrl_reg = nfc->ctrl_reg; |
||
1097 | ar934x_nfc_hw_init(nfc); |
||
1098 | nfc->ctrl_reg = ctrl_reg; |
||
1099 | |||
1100 | if (nfc->select_chip) |
||
1101 | nfc->select_chip(0); |
||
1102 | |||
1103 | ar934x_nfc_send_cmd(nfc, NAND_CMD_RESET); |
||
1104 | } |
||
1105 | |||
1106 | static irqreturn_t |
||
1107 | ar934x_nfc_irq_handler(int irq, void *data) |
||
1108 | { |
||
1109 | struct ar934x_nfc *nfc = data; |
||
1110 | u32 status; |
||
1111 | |||
1112 | status = ar934x_nfc_rr(nfc, AR934X_NFC_REG_INT_STATUS); |
||
1113 | |||
1114 | ar934x_nfc_wr(nfc, AR934X_NFC_REG_INT_STATUS, 0); |
||
1115 | /* flush write */ |
||
1116 | ar934x_nfc_rr(nfc, AR934X_NFC_REG_INT_STATUS); |
||
1117 | |||
1118 | status &= ar934x_nfc_rr(nfc, AR934X_NFC_REG_INT_MASK); |
||
1119 | if (status) { |
||
1120 | nfc_dbg(nfc, "got IRQ, status:%08x\n", status); |
||
1121 | |||
1122 | nfc->irq_status = status; |
||
1123 | nfc->spurious_irq_expected = true; |
||
1124 | wake_up(&nfc->irq_waitq); |
||
1125 | } else { |
||
1126 | if (nfc->spurious_irq_expected) { |
||
1127 | nfc->spurious_irq_expected = false; |
||
1128 | } else { |
||
1129 | dev_warn(nfc->parent, "spurious interrupt\n"); |
||
1130 | } |
||
1131 | } |
||
1132 | |||
1133 | return IRQ_HANDLED; |
||
1134 | } |
||
1135 | |||
1136 | static int |
||
1137 | ar934x_nfc_init_tail(struct mtd_info *mtd) |
||
1138 | { |
||
1139 | struct ar934x_nfc *nfc = mtd_to_ar934x_nfc(mtd); |
||
1140 | struct nand_chip *chip = &nfc->nand_chip; |
||
1141 | u32 ctrl; |
||
1142 | u32 t; |
||
1143 | int err; |
||
1144 | |||
1145 | switch (mtd->oobsize) { |
||
1146 | case 16: |
||
1147 | case 64: |
||
1148 | case 128: |
||
1149 | ar934x_nfc_wr(nfc, AR934X_NFC_REG_SPARE_SIZE, mtd->oobsize); |
||
1150 | break; |
||
1151 | |||
1152 | default: |
||
1153 | dev_err(nfc->parent, "unsupported OOB size: %d bytes\n", |
||
1154 | mtd->oobsize); |
||
1155 | return -ENXIO; |
||
1156 | } |
||
1157 | |||
1158 | ctrl = AR934X_NFC_CTRL_CUSTOM_SIZE_EN; |
||
1159 | |||
1160 | switch (mtd->erasesize / mtd->writesize) { |
||
1161 | case 32: |
||
1162 | t = AR934X_NFC_CTRL_BLOCK_SIZE_32; |
||
1163 | break; |
||
1164 | |||
1165 | case 64: |
||
1166 | t = AR934X_NFC_CTRL_BLOCK_SIZE_64; |
||
1167 | break; |
||
1168 | |||
1169 | case 128: |
||
1170 | t = AR934X_NFC_CTRL_BLOCK_SIZE_128; |
||
1171 | break; |
||
1172 | |||
1173 | case 256: |
||
1174 | t = AR934X_NFC_CTRL_BLOCK_SIZE_256; |
||
1175 | break; |
||
1176 | |||
1177 | default: |
||
1178 | dev_err(nfc->parent, "unsupported block size: %u\n", |
||
1179 | mtd->erasesize / mtd->writesize); |
||
1180 | return -ENXIO; |
||
1181 | } |
||
1182 | |||
1183 | ctrl |= t << AR934X_NFC_CTRL_BLOCK_SIZE_S; |
||
1184 | |||
1185 | switch (mtd->writesize) { |
||
1186 | case 256: |
||
1187 | nfc->small_page = 1; |
||
1188 | t = AR934X_NFC_CTRL_PAGE_SIZE_256; |
||
1189 | break; |
||
1190 | |||
1191 | case 512: |
||
1192 | nfc->small_page = 1; |
||
1193 | t = AR934X_NFC_CTRL_PAGE_SIZE_512; |
||
1194 | break; |
||
1195 | |||
1196 | case 1024: |
||
1197 | t = AR934X_NFC_CTRL_PAGE_SIZE_1024; |
||
1198 | break; |
||
1199 | |||
1200 | case 2048: |
||
1201 | t = AR934X_NFC_CTRL_PAGE_SIZE_2048; |
||
1202 | break; |
||
1203 | |||
1204 | case 4096: |
||
1205 | t = AR934X_NFC_CTRL_PAGE_SIZE_4096; |
||
1206 | break; |
||
1207 | |||
1208 | case 8192: |
||
1209 | t = AR934X_NFC_CTRL_PAGE_SIZE_8192; |
||
1210 | break; |
||
1211 | |||
1212 | case 16384: |
||
1213 | t = AR934X_NFC_CTRL_PAGE_SIZE_16384; |
||
1214 | break; |
||
1215 | |||
1216 | default: |
||
1217 | dev_err(nfc->parent, "unsupported write size: %d bytes\n", |
||
1218 | mtd->writesize); |
||
1219 | return -ENXIO; |
||
1220 | } |
||
1221 | |||
1222 | ctrl |= t << AR934X_NFC_CTRL_PAGE_SIZE_S; |
||
1223 | |||
1224 | if (nfc->small_page) { |
||
1225 | ctrl |= AR934X_NFC_CTRL_SMALL_PAGE; |
||
1226 | |||
1227 | if (chip->chipsize > (32 << 20)) { |
||
1228 | nfc->addr_count0 = 4; |
||
1229 | nfc->addr_count1 = 3; |
||
1230 | } else if (chip->chipsize > (2 << 16)) { |
||
1231 | nfc->addr_count0 = 3; |
||
1232 | nfc->addr_count1 = 2; |
||
1233 | } else { |
||
1234 | nfc->addr_count0 = 2; |
||
1235 | nfc->addr_count1 = 1; |
||
1236 | } |
||
1237 | } else { |
||
1238 | if (chip->chipsize > (128 << 20)) { |
||
1239 | nfc->addr_count0 = 5; |
||
1240 | nfc->addr_count1 = 3; |
||
1241 | } else if (chip->chipsize > (8 << 16)) { |
||
1242 | nfc->addr_count0 = 4; |
||
1243 | nfc->addr_count1 = 2; |
||
1244 | } else { |
||
1245 | nfc->addr_count0 = 3; |
||
1246 | nfc->addr_count1 = 1; |
||
1247 | } |
||
1248 | } |
||
1249 | |||
1250 | ctrl |= nfc->addr_count0 << AR934X_NFC_CTRL_ADDR_CYCLE0_S; |
||
1251 | ctrl |= nfc->addr_count1 << AR934X_NFC_CTRL_ADDR_CYCLE1_S; |
||
1252 | |||
1253 | nfc->ctrl_reg = ctrl; |
||
1254 | ar934x_nfc_wr(nfc, AR934X_NFC_REG_CTRL, nfc->ctrl_reg); |
||
1255 | |||
1256 | ar934x_nfc_free_buf(nfc); |
||
1257 | err = ar934x_nfc_alloc_buf(nfc, mtd->writesize + mtd->oobsize); |
||
1258 | |||
1259 | return err; |
||
1260 | } |
||
1261 | |||
1262 | #if LINUX_VERSION_CODE < KERNEL_VERSION(4,6,0) |
||
1263 | static struct nand_ecclayout ar934x_nfc_oob_64_hwecc = { |
||
1264 | .eccbytes = 28, |
||
1265 | .eccpos = { |
||
1266 | 20, 21, 22, 23, 24, 25, 26, |
||
1267 | 27, 28, 29, 30, 31, 32, 33, |
||
1268 | 34, 35, 36, 37, 38, 39, 40, |
||
1269 | 41, 42, 43, 44, 45, 46, 47, |
||
1270 | }, |
||
1271 | .oobfree = { |
||
1272 | { |
||
1273 | .offset = 4, |
||
1274 | .length = 16, |
||
1275 | }, |
||
1276 | { |
||
1277 | .offset = 48, |
||
1278 | .length = 16, |
||
1279 | }, |
||
1280 | }, |
||
1281 | }; |
||
1282 | |||
1283 | #else |
||
1284 | |||
1285 | static int ar934x_nfc_ooblayout_ecc(struct mtd_info *mtd, int section, |
||
1286 | struct mtd_oob_region *oobregion) |
||
1287 | { |
||
1288 | if (section) |
||
1289 | return -ERANGE; |
||
1290 | |||
1291 | oobregion->offset = 20; |
||
1292 | oobregion->length = 28; |
||
1293 | |||
1294 | return 0; |
||
1295 | } |
||
1296 | |||
1297 | static int ar934x_nfc_ooblayout_free(struct mtd_info *mtd, int section, |
||
1298 | struct mtd_oob_region *oobregion) |
||
1299 | { |
||
1300 | switch (section) { |
||
1301 | case 0: |
||
1302 | oobregion->offset = 4; |
||
1303 | oobregion->length = 16; |
||
1304 | return 0; |
||
1305 | case 1: |
||
1306 | oobregion->offset = 48; |
||
1307 | oobregion->length = 16; |
||
1308 | return 0; |
||
1309 | default: |
||
1310 | return -ERANGE; |
||
1311 | } |
||
1312 | } |
||
1313 | |||
1314 | static const struct mtd_ooblayout_ops ar934x_nfc_ecclayout_ops = { |
||
1315 | .ecc = ar934x_nfc_ooblayout_ecc, |
||
1316 | .free = ar934x_nfc_ooblayout_free, |
||
1317 | }; |
||
1318 | #endif /* < 4.6 */ |
||
1319 | |||
1320 | static int |
||
1321 | ar934x_nfc_setup_hwecc(struct ar934x_nfc *nfc) |
||
1322 | { |
||
1323 | struct nand_chip *nand = &nfc->nand_chip; |
||
1324 | struct mtd_info *mtd = ar934x_nfc_to_mtd(nfc); |
||
1325 | u32 ecc_cap; |
||
1326 | u32 ecc_thres; |
||
1327 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(4,6,0) |
||
1328 | struct mtd_oob_region oobregion; |
||
1329 | #endif |
||
1330 | |||
1331 | if (!IS_ENABLED(CONFIG_MTD_NAND_AR934X_HW_ECC)) { |
||
1332 | dev_err(nfc->parent, "hardware ECC support is disabled\n"); |
||
1333 | return -EINVAL; |
||
1334 | } |
||
1335 | |||
1336 | switch (mtd->writesize) { |
||
1337 | case 2048: |
||
1338 | /* |
||
1339 | * Writing a subpage separately is not supported, because |
||
1340 | * the controller only does ECC on full-page accesses. |
||
1341 | */ |
||
1342 | nand->options = NAND_NO_SUBPAGE_WRITE; |
||
1343 | |||
1344 | nand->ecc.size = 512; |
||
1345 | nand->ecc.bytes = 7; |
||
1346 | nand->ecc.strength = 4; |
||
1347 | #if LINUX_VERSION_CODE < KERNEL_VERSION(4,6,0) |
||
1348 | nand->ecc.layout = &ar934x_nfc_oob_64_hwecc; |
||
1349 | #else |
||
1350 | mtd_set_ooblayout(mtd, &ar934x_nfc_ecclayout_ops); |
||
1351 | #endif |
||
1352 | break; |
||
1353 | |||
1354 | default: |
||
1355 | dev_err(nfc->parent, |
||
1356 | "hardware ECC is not available for %d byte pages\n", |
||
1357 | mtd->writesize); |
||
1358 | return -EINVAL; |
||
1359 | } |
||
1360 | |||
1361 | #if LINUX_VERSION_CODE < KERNEL_VERSION(4,6,0) |
||
1362 | BUG_ON(!nand->ecc.layout); |
||
1363 | #else |
||
1364 | BUG_ON(!mtd->ooblayout->ecc); |
||
1365 | #endif |
||
1366 | |||
1367 | switch (nand->ecc.strength) { |
||
1368 | case 4: |
||
1369 | ecc_cap = AR934X_NFC_ECC_CTRL_ECC_CAP_4; |
||
1370 | ecc_thres = 4; |
||
1371 | break; |
||
1372 | |||
1373 | default: |
||
1374 | dev_err(nfc->parent, "unsupported ECC strength %u\n", |
||
1375 | nand->ecc.strength); |
||
1376 | return -EINVAL; |
||
1377 | } |
||
1378 | |||
1379 | nfc->ecc_thres = ecc_thres; |
||
1380 | #if LINUX_VERSION_CODE < KERNEL_VERSION(4,6,0) |
||
1381 | nfc->ecc_oob_pos = nand->ecc.layout->eccpos[0]; |
||
1382 | #else |
||
1383 | mtd->ooblayout->ecc(mtd, 0, &oobregion); |
||
1384 | nfc->ecc_oob_pos = oobregion.offset; |
||
1385 | #endif |
||
1386 | |||
1387 | nfc->ecc_ctrl_reg = ecc_cap << AR934X_NFC_ECC_CTRL_ECC_CAP_S; |
||
1388 | nfc->ecc_ctrl_reg |= ecc_thres << AR934X_NFC_ECC_CTRL_ERR_THRES_S; |
||
1389 | |||
1390 | nfc->ecc_offset_reg = mtd->writesize + nfc->ecc_oob_pos; |
||
1391 | |||
1392 | nand->ecc.mode = NAND_ECC_HW; |
||
1393 | nand->ecc.read_page = ar934x_nfc_read_page; |
||
1394 | nand->ecc.read_page_raw = ar934x_nfc_read_page_raw; |
||
1395 | nand->ecc.write_page = ar934x_nfc_write_page; |
||
1396 | nand->ecc.write_page_raw = ar934x_nfc_write_page_raw; |
||
1397 | nand->ecc.read_oob = ar934x_nfc_read_oob; |
||
1398 | nand->ecc.write_oob = ar934x_nfc_write_oob; |
||
1399 | |||
1400 | return 0; |
||
1401 | } |
||
1402 | |||
1403 | static int |
||
1404 | ar934x_nfc_probe(struct platform_device *pdev) |
||
1405 | { |
||
1406 | static const char *part_probes[] = { "cmdlinepart", NULL, }; |
||
1407 | struct ar934x_nfc_platform_data *pdata; |
||
1408 | struct ar934x_nfc *nfc; |
||
1409 | struct resource *res; |
||
1410 | struct mtd_info *mtd; |
||
1411 | struct nand_chip *nand; |
||
1412 | struct mtd_part_parser_data ppdata; |
||
1413 | int ret; |
||
1414 | |||
1415 | pdata = pdev->dev.platform_data; |
||
1416 | if (pdata == NULL) { |
||
1417 | dev_err(&pdev->dev, "no platform data defined\n"); |
||
1418 | return -EINVAL; |
||
1419 | } |
||
1420 | |||
1421 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
||
1422 | if (!res) { |
||
1423 | dev_err(&pdev->dev, "failed to get I/O memory\n"); |
||
1424 | return -EINVAL; |
||
1425 | } |
||
1426 | |||
1427 | nfc = devm_kzalloc(&pdev->dev, sizeof(struct ar934x_nfc), GFP_KERNEL); |
||
1428 | if (!nfc) { |
||
1429 | dev_err(&pdev->dev, "failed to allocate driver data\n"); |
||
1430 | return -ENOMEM; |
||
1431 | } |
||
1432 | |||
1433 | nfc->base = devm_ioremap_resource(&pdev->dev, res); |
||
1434 | if (IS_ERR(nfc->base)) { |
||
1435 | dev_err(&pdev->dev, "failed to remap I/O memory\n"); |
||
1436 | return PTR_ERR(nfc->base); |
||
1437 | } |
||
1438 | |||
1439 | nfc->irq = platform_get_irq(pdev, 0); |
||
1440 | if (nfc->irq < 0) { |
||
1441 | dev_err(&pdev->dev, "no IRQ resource specified\n"); |
||
1442 | return -EINVAL; |
||
1443 | } |
||
1444 | |||
1445 | init_waitqueue_head(&nfc->irq_waitq); |
||
1446 | ret = request_irq(nfc->irq, ar934x_nfc_irq_handler, 0, |
||
1447 | dev_name(&pdev->dev), nfc); |
||
1448 | if (ret) { |
||
1449 | dev_err(&pdev->dev, "requast_irq failed, err:%d\n", ret); |
||
1450 | return ret; |
||
1451 | } |
||
1452 | |||
1453 | nfc->parent = &pdev->dev; |
||
1454 | nfc->select_chip = pdata->select_chip; |
||
1455 | nfc->swap_dma = pdata->swap_dma; |
||
1456 | |||
1457 | nand = &nfc->nand_chip; |
||
1458 | mtd = ar934x_nfc_to_mtd(nfc); |
||
1459 | |||
1460 | #if LINUX_VERSION_CODE < KERNEL_VERSION(4,6,0) |
||
1461 | mtd->priv = nand; |
||
1462 | #endif |
||
1463 | mtd->owner = THIS_MODULE; |
||
1464 | if (pdata->name) |
||
1465 | mtd->name = pdata->name; |
||
1466 | else |
||
1467 | mtd->name = dev_name(&pdev->dev); |
||
1468 | |||
1469 | nand->chip_delay = 25; |
||
1470 | |||
1471 | nand->dev_ready = ar934x_nfc_dev_ready; |
||
1472 | nand->cmdfunc = ar934x_nfc_cmdfunc; |
||
1473 | nand->read_byte = ar934x_nfc_read_byte; |
||
1474 | nand->write_buf = ar934x_nfc_write_buf; |
||
1475 | nand->read_buf = ar934x_nfc_read_buf; |
||
1476 | nand->select_chip = ar934x_nfc_select_chip; |
||
1477 | |||
1478 | ret = ar934x_nfc_alloc_buf(nfc, AR934X_NFC_ID_BUF_SIZE); |
||
1479 | if (ret) |
||
1480 | goto err_free_irq; |
||
1481 | |||
1482 | platform_set_drvdata(pdev, nfc); |
||
1483 | |||
1484 | ar934x_nfc_hw_init(nfc); |
||
1485 | |||
1486 | ret = nand_scan_ident(mtd, 1, NULL); |
||
1487 | if (ret) { |
||
1488 | dev_err(&pdev->dev, "nand_scan_ident failed, err:%d\n", ret); |
||
1489 | goto err_free_buf; |
||
1490 | } |
||
1491 | |||
1492 | ret = ar934x_nfc_init_tail(mtd); |
||
1493 | if (ret) { |
||
1494 | dev_err(&pdev->dev, "init tail failed, err:%d\n", ret); |
||
1495 | goto err_free_buf; |
||
1496 | } |
||
1497 | |||
1498 | if (pdata->scan_fixup) { |
||
1499 | ret = pdata->scan_fixup(mtd); |
||
1500 | if (ret) |
||
1501 | goto err_free_buf; |
||
1502 | } |
||
1503 | |||
1504 | switch (pdata->ecc_mode) { |
||
1505 | case AR934X_NFC_ECC_SOFT: |
||
1506 | nand->ecc.mode = NAND_ECC_SOFT; |
||
1507 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(4,6,0) |
||
1508 | nand->ecc.algo = NAND_ECC_HAMMING; |
||
1509 | #endif |
||
1510 | break; |
||
1511 | |||
1512 | case AR934X_NFC_ECC_SOFT_BCH: |
||
1513 | #if LINUX_VERSION_CODE < KERNEL_VERSION(4,6,0) |
||
1514 | nand->ecc.mode = NAND_ECC_SOFT_BCH; |
||
1515 | #else |
||
1516 | nand->ecc.mode = NAND_ECC_SOFT; |
||
1517 | nand->ecc.algo = NAND_ECC_BCH; |
||
1518 | #endif |
||
1519 | break; |
||
1520 | |||
1521 | case AR934X_NFC_ECC_HW: |
||
1522 | ret = ar934x_nfc_setup_hwecc(nfc); |
||
1523 | if (ret) |
||
1524 | goto err_free_buf; |
||
1525 | |||
1526 | break; |
||
1527 | |||
1528 | default: |
||
1529 | dev_err(nfc->parent, "unknown ECC mode %d\n", pdata->ecc_mode); |
||
1530 | return -EINVAL; |
||
1531 | } |
||
1532 | |||
1533 | ret = nand_scan_tail(mtd); |
||
1534 | if (ret) { |
||
1535 | dev_err(&pdev->dev, "scan tail failed, err:%d\n", ret); |
||
1536 | goto err_free_buf; |
||
1537 | } |
||
1538 | |||
1539 | memset(&ppdata, '\0', sizeof(ppdata)); |
||
1540 | ret = mtd_device_parse_register(mtd, part_probes, &ppdata, |
||
1541 | pdata->parts, pdata->nr_parts); |
||
1542 | if (ret) { |
||
1543 | dev_err(&pdev->dev, "unable to register mtd, err:%d\n", ret); |
||
1544 | goto err_free_buf; |
||
1545 | } |
||
1546 | |||
1547 | return 0; |
||
1548 | |||
1549 | err_free_buf: |
||
1550 | ar934x_nfc_free_buf(nfc); |
||
1551 | err_free_irq: |
||
1552 | free_irq(nfc->irq, nfc); |
||
1553 | return ret; |
||
1554 | } |
||
1555 | |||
1556 | static int |
||
1557 | ar934x_nfc_remove(struct platform_device *pdev) |
||
1558 | { |
||
1559 | struct ar934x_nfc *nfc; |
||
1560 | struct mtd_info *mtd; |
||
1561 | |||
1562 | nfc = platform_get_drvdata(pdev); |
||
1563 | if (nfc) { |
||
1564 | mtd = ar934x_nfc_to_mtd(nfc); |
||
1565 | nand_release(mtd); |
||
1566 | ar934x_nfc_free_buf(nfc); |
||
1567 | free_irq(nfc->irq, nfc); |
||
1568 | } |
||
1569 | |||
1570 | return 0; |
||
1571 | } |
||
1572 | |||
1573 | static struct platform_driver ar934x_nfc_driver = { |
||
1574 | .probe = ar934x_nfc_probe, |
||
1575 | .remove = ar934x_nfc_remove, |
||
1576 | .driver = { |
||
1577 | .name = AR934X_NFC_DRIVER_NAME, |
||
1578 | .owner = THIS_MODULE, |
||
1579 | }, |
||
1580 | }; |
||
1581 | |||
1582 | module_platform_driver(ar934x_nfc_driver); |
||
1583 | |||
1584 | MODULE_LICENSE("GPL v2"); |
||
1585 | MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>"); |
||
1586 | MODULE_DESCRIPTION("Atheros AR934x NAND Flash Controller driver"); |
||
1587 | MODULE_ALIAS("platform:" AR934X_NFC_DRIVER_NAME); |