1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27#include <common.h>
28#include <asm/arch/hardware.h>
29#include <asm/arch/gpio.h>
30#include <asm/arch/at91_pio.h>
31
32#include <nand.h>
33
34#ifdef CONFIG_ATMEL_NAND_HWECC
35
36
37#define ecc_readl(add, reg) \
38 readl(AT91_BASE_SYS + add + ATMEL_ECC_##reg)
39#define ecc_writel(add, reg, value) \
40 writel((value), AT91_BASE_SYS + add + ATMEL_ECC_##reg)
41
42#include "atmel_nand_ecc.h"
43
44
45
46
47
48
49static struct nand_ecclayout atmel_oobinfo_large = {
50 .eccbytes = 4,
51 .eccpos = {60, 61, 62, 63},
52 .oobfree = {
53 {2, 58}
54 },
55};
56
57
58
59
60
61
62static struct nand_ecclayout atmel_oobinfo_small = {
63 .eccbytes = 4,
64 .eccpos = {0, 1, 2, 3},
65 .oobfree = {
66 {6, 10}
67 },
68};
69
70
71
72
73
74
75
76
77
78
79static int atmel_nand_calculate(struct mtd_info *mtd,
80 const u_char *dat, unsigned char *ecc_code)
81{
82 struct nand_chip *nand_chip = mtd->priv;
83 unsigned int ecc_value;
84
85
86 ecc_value = ecc_readl(CONFIG_SYS_NAND_ECC_BASE, PR);
87
88 ecc_code[0] = ecc_value & 0xFF;
89 ecc_code[1] = (ecc_value >> 8) & 0xFF;
90
91
92 ecc_value = ecc_readl(CONFIG_SYS_NAND_ECC_BASE, NPR) & ATMEL_ECC_NPARITY;
93
94 ecc_code[2] = ecc_value & 0xFF;
95 ecc_code[3] = (ecc_value >> 8) & 0xFF;
96
97 return 0;
98}
99
100
101
102
103
104
105
106
107static int atmel_nand_read_page(struct mtd_info *mtd,
108 struct nand_chip *chip, uint8_t *buf, int page)
109{
110 int eccsize = chip->ecc.size;
111 int eccbytes = chip->ecc.bytes;
112 uint32_t *eccpos = chip->ecc.layout->eccpos;
113 uint8_t *p = buf;
114 uint8_t *oob = chip->oob_poi;
115 uint8_t *ecc_pos;
116 int stat;
117
118
119 chip->read_buf(mtd, p, eccsize);
120
121
122 if (eccpos[0] != 0) {
123
124
125
126
127
128
129 chip->cmdfunc(mtd, NAND_CMD_RNDOUT,
130 mtd->writesize + eccpos[0], -1);
131 }
132
133
134 ecc_pos = oob + eccpos[0];
135 chip->read_buf(mtd, ecc_pos, eccbytes);
136
137
138 stat = chip->ecc.correct(mtd, p, oob, NULL);
139
140 if (stat < 0)
141 mtd->ecc_stats.failed++;
142 else
143 mtd->ecc_stats.corrected += stat;
144
145
146 chip->cmdfunc(mtd, NAND_CMD_RNDOUT, mtd->writesize, -1);
147
148
149 chip->read_buf(mtd, oob, mtd->oobsize);
150
151 return 0;
152}
153
154
155
156
157
158
159
160
161
162
163
164
165
166static int atmel_nand_correct(struct mtd_info *mtd, u_char *dat,
167 u_char *read_ecc, u_char *isnull)
168{
169 struct nand_chip *nand_chip = mtd->priv;
170 unsigned int ecc_status, ecc_parity, ecc_mode;
171 unsigned int ecc_word, ecc_bit;
172
173
174 ecc_status = ecc_readl(CONFIG_SYS_NAND_ECC_BASE, SR);
175
176
177 if (likely(!(ecc_status & ATMEL_ECC_RECERR)))
178 return 0;
179
180
181 ecc_bit = ecc_readl(CONFIG_SYS_NAND_ECC_BASE, PR) & ATMEL_ECC_BITADDR;
182
183 ecc_word = ecc_readl(CONFIG_SYS_NAND_ECC_BASE, PR) & ATMEL_ECC_WORDADDR;
184 ecc_word >>= 4;
185
186
187 if (ecc_status & ATMEL_ECC_MULERR) {
188
189
190 if ((ecc_bit == ATMEL_ECC_BITADDR)
191 && (ecc_word == (ATMEL_ECC_WORDADDR >> 4))) {
192
193 return 0;
194 }
195
196
197
198 printk(KERN_WARNING "atmel_nand : multiple errors detected."
199 " Unable to correct.\n");
200 return -EIO;
201 }
202
203
204 if (ecc_status & ATMEL_ECC_ECCERR) {
205
206
207
208 printk(KERN_WARNING "atmel_nand : one bit error on ECC code."
209 " Nothing to correct\n");
210 return 0;
211 }
212
213 printk(KERN_WARNING "atmel_nand : one bit error on data."
214 " (word offset in the page :"
215 " 0x%x bit offset : 0x%x)\n",
216 ecc_word, ecc_bit);
217
218 if (nand_chip->options & NAND_BUSWIDTH_16) {
219
220 ((unsigned short *) dat)[ecc_word] ^= (1 << ecc_bit);
221 } else {
222
223 dat[ecc_word] ^= (1 << ecc_bit);
224 }
225 printk(KERN_WARNING "atmel_nand : error corrected\n");
226 return 1;
227}
228
229
230
231
232static void atmel_nand_hwctl(struct mtd_info *mtd, int mode)
233{
234}
235#endif
236
237static void at91_nand_hwcontrol(struct mtd_info *mtd,
238 int cmd, unsigned int ctrl)
239{
240 struct nand_chip *this = mtd->priv;
241
242 if (ctrl & NAND_CTRL_CHANGE) {
243 ulong IO_ADDR_W = (ulong) this->IO_ADDR_W;
244 IO_ADDR_W &= ~(CONFIG_SYS_NAND_MASK_ALE
245 | CONFIG_SYS_NAND_MASK_CLE);
246
247 if (ctrl & NAND_CLE)
248 IO_ADDR_W |= CONFIG_SYS_NAND_MASK_CLE;
249 if (ctrl & NAND_ALE)
250 IO_ADDR_W |= CONFIG_SYS_NAND_MASK_ALE;
251
252#ifdef CONFIG_SYS_NAND_ENABLE_PIN
253 at91_set_gpio_value(CONFIG_SYS_NAND_ENABLE_PIN,
254 !(ctrl & NAND_NCE));
255#endif
256 this->IO_ADDR_W = (void *) IO_ADDR_W;
257 }
258
259 if (cmd != NAND_CMD_NONE)
260 writeb(cmd, this->IO_ADDR_W);
261}
262
263#ifdef CONFIG_SYS_NAND_READY_PIN
264static int at91_nand_ready(struct mtd_info *mtd)
265{
266 return at91_get_gpio_value(CONFIG_SYS_NAND_READY_PIN);
267}
268#endif
269
270int board_nand_init(struct nand_chip *nand)
271{
272#ifdef CONFIG_ATMEL_NAND_HWECC
273 static int chip_nr = 0;
274 struct mtd_info *mtd;
275#endif
276
277 nand->ecc.mode = NAND_ECC_SOFT;
278#ifdef CONFIG_SYS_NAND_DBW_16
279 nand->options = NAND_BUSWIDTH_16;
280#endif
281 nand->cmd_ctrl = at91_nand_hwcontrol;
282#ifdef CONFIG_SYS_NAND_READY_PIN
283 nand->dev_ready = at91_nand_ready;
284#endif
285 nand->chip_delay = 20;
286
287#ifdef CONFIG_ATMEL_NAND_HWECC
288 nand->ecc.mode = NAND_ECC_HW;
289 nand->ecc.calculate = atmel_nand_calculate;
290 nand->ecc.correct = atmel_nand_correct;
291 nand->ecc.hwctl = atmel_nand_hwctl;
292 nand->ecc.read_page = atmel_nand_read_page;
293 nand->ecc.bytes = 4;
294#endif
295
296#ifdef CONFIG_ATMEL_NAND_HWECC
297 mtd = &nand_info[chip_nr++];
298 mtd->priv = nand;
299
300
301 if (nand_scan_ident(mtd, 1, NULL)) {
302 printk(KERN_WARNING "NAND Flash not found !\n");
303 return -ENXIO;
304 }
305
306 if (nand->ecc.mode == NAND_ECC_HW) {
307
308 nand->ecc.size = mtd->writesize;
309
310
311 switch (mtd->writesize) {
312 case 512:
313 nand->ecc.layout = &atmel_oobinfo_small;
314 ecc_writel(CONFIG_SYS_NAND_ECC_BASE, MR, ATMEL_ECC_PAGESIZE_528);
315 break;
316 case 1024:
317 nand->ecc.layout = &atmel_oobinfo_large;
318 ecc_writel(CONFIG_SYS_NAND_ECC_BASE, MR, ATMEL_ECC_PAGESIZE_1056);
319 break;
320 case 2048:
321 nand->ecc.layout = &atmel_oobinfo_large;
322 ecc_writel(CONFIG_SYS_NAND_ECC_BASE, MR, ATMEL_ECC_PAGESIZE_2112);
323 break;
324 case 4096:
325 nand->ecc.layout = &atmel_oobinfo_large;
326 ecc_writel(CONFIG_SYS_NAND_ECC_BASE, MR, ATMEL_ECC_PAGESIZE_4224);
327 break;
328 default:
329
330
331 nand->ecc.mode = NAND_ECC_SOFT;
332 nand->ecc.calculate = NULL;
333 nand->ecc.correct = NULL;
334 nand->ecc.hwctl = NULL;
335 nand->ecc.read_page = NULL;
336 nand->ecc.postpad = 0;
337 nand->ecc.prepad = 0;
338 nand->ecc.bytes = 0;
339 break;
340 }
341 }
342#endif
343
344 return 0;
345}
346