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