OpenWrt – Blame information for rev 4
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
4 | office | 1 | From 0e1c4e3c97b83b4e7da65b1c56f0a7d40736ac53 Mon Sep 17 00:00:00 2001 |
2 | From: John Crispin <blogic@openwrt.org> |
||
3 | Date: Sun, 27 Jul 2014 11:05:17 +0100 |
||
4 | Subject: [PATCH 39/53] mtd: add mt7621 nand support |
||
5 | |||
6 | Signed-off-by: John Crispin <blogic@openwrt.org> |
||
7 | --- |
||
8 | drivers/mtd/nand/Kconfig | 6 + |
||
9 | drivers/mtd/nand/Makefile | 1 + |
||
10 | drivers/mtd/nand/bmt.c | 750 ++++++++++++ |
||
11 | drivers/mtd/nand/bmt.h | 80 ++ |
||
12 | drivers/mtd/nand/dev-nand.c | 63 + |
||
13 | drivers/mtd/nand/mt6575_typedefs.h | 340 ++++++ |
||
14 | drivers/mtd/nand/mtk_nand2.c | 2304 +++++++++++++++++++++++++++++++++++ |
||
15 | drivers/mtd/nand/mtk_nand2.h | 452 +++++++ |
||
16 | drivers/mtd/nand/nand_base.c | 6 +- |
||
17 | drivers/mtd/nand/nand_def.h | 123 ++ |
||
18 | drivers/mtd/nand/nand_device_list.h | 55 + |
||
19 | drivers/mtd/nand/partition.h | 115 ++ |
||
20 | 13 files changed, 4311 insertions(+), 3 deletions(-) |
||
21 | create mode 100644 drivers/mtd/nand/bmt.c |
||
22 | create mode 100644 drivers/mtd/nand/bmt.h |
||
23 | create mode 100644 drivers/mtd/nand/dev-nand.c |
||
24 | create mode 100644 drivers/mtd/nand/mt6575_typedefs.h |
||
25 | create mode 100644 drivers/mtd/nand/mtk_nand2.c |
||
26 | create mode 100644 drivers/mtd/nand/mtk_nand2.h |
||
27 | create mode 100644 drivers/mtd/nand/nand_def.h |
||
28 | create mode 100644 drivers/mtd/nand/nand_device_list.h |
||
29 | create mode 100644 drivers/mtd/nand/partition.h |
||
30 | |||
31 | --- a/drivers/mtd/nand/Kconfig |
||
32 | +++ b/drivers/mtd/nand/Kconfig |
||
33 | @@ -563,4 +563,10 @@ config MTD_NAND_MTK |
||
34 | Enables support for NAND controller on MTK SoCs. |
||
35 | This controller is found on mt27xx, mt81xx, mt65xx SoCs. |
||
36 | |||
37 | +config MTK_MTD_NAND |
||
38 | + tristate "Support for MTK SoC NAND controller" |
||
39 | + depends on SOC_MT7621 |
||
40 | + select MTD_NAND_IDS |
||
41 | + select MTD_NAND_ECC |
||
42 | + |
||
43 | endif # MTD_NAND |
||
44 | --- a/drivers/mtd/nand/Makefile |
||
45 | +++ b/drivers/mtd/nand/Makefile |
||
46 | @@ -60,6 +60,7 @@ obj-$(CONFIG_MTD_NAND_HISI504) + |
||
47 | obj-$(CONFIG_MTD_NAND_BRCMNAND) += brcmnand/ |
||
48 | obj-$(CONFIG_MTD_NAND_QCOM) += qcom_nandc.o |
||
49 | obj-$(CONFIG_MTD_NAND_MTK) += mtk_nand.o mtk_ecc.o |
||
50 | +obj-$(CONFIG_MTK_MTD_NAND) += mtk_nand2.o bmt.o |
||
51 | |||
52 | nand-objs := nand_base.o nand_bbt.o nand_timings.o nand_ids.o |
||
53 | nand-objs += nand_amd.o |
||
54 | --- /dev/null |
||
55 | +++ b/drivers/mtd/nand/bmt.c |
||
56 | @@ -0,0 +1,750 @@ |
||
57 | +#include "bmt.h" |
||
58 | + |
||
59 | +typedef struct |
||
60 | +{ |
||
61 | + char signature[3]; |
||
62 | + u8 version; |
||
63 | + u8 bad_count; // bad block count in pool |
||
64 | + u8 mapped_count; // mapped block count in pool |
||
65 | + u8 checksum; |
||
66 | + u8 reseverd[13]; |
||
67 | +} phys_bmt_header; |
||
68 | + |
||
69 | +typedef struct |
||
70 | +{ |
||
71 | + phys_bmt_header header; |
||
72 | + bmt_entry table[MAX_BMT_SIZE]; |
||
73 | +} phys_bmt_struct; |
||
74 | + |
||
75 | +typedef struct |
||
76 | +{ |
||
77 | + char signature[3]; |
||
78 | +} bmt_oob_data; |
||
79 | + |
||
80 | +static char MAIN_SIGNATURE[] = "BMT"; |
||
81 | +static char OOB_SIGNATURE[] = "bmt"; |
||
82 | +#define SIGNATURE_SIZE (3) |
||
83 | + |
||
84 | +#define MAX_DAT_SIZE 0x1000 |
||
85 | +#define MAX_OOB_SIZE 0x80 |
||
86 | + |
||
87 | +static struct mtd_info *mtd_bmt; |
||
88 | +static struct nand_chip *nand_chip_bmt; |
||
89 | +#define BLOCK_SIZE_BMT (1 << nand_chip_bmt->phys_erase_shift) |
||
90 | +#define PAGE_SIZE_BMT (1 << nand_chip_bmt->page_shift) |
||
91 | + |
||
92 | +#define OFFSET(block) ((block) * BLOCK_SIZE_BMT) |
||
93 | +#define PAGE_ADDR(block) ((block) * BLOCK_SIZE_BMT / PAGE_SIZE_BMT) |
||
94 | + |
||
95 | +/********************************************************************* |
||
96 | +* Flash is splited into 2 parts, system part is for normal system * |
||
97 | +* system usage, size is system_block_count, another is replace pool * |
||
98 | +* +-------------------------------------------------+ * |
||
99 | +* | system_block_count | bmt_block_count | * |
||
100 | +* +-------------------------------------------------+ * |
||
101 | +*********************************************************************/ |
||
102 | +static u32 total_block_count; // block number in flash |
||
103 | +static u32 system_block_count; |
||
104 | +static int bmt_block_count; // bmt table size |
||
105 | +// static int bmt_count; // block used in bmt |
||
106 | +static int page_per_block; // page per count |
||
107 | + |
||
108 | +static u32 bmt_block_index; // bmt block index |
||
109 | +static bmt_struct bmt; // dynamic created global bmt table |
||
110 | + |
||
111 | +static u8 dat_buf[MAX_DAT_SIZE]; |
||
112 | +static u8 oob_buf[MAX_OOB_SIZE]; |
||
113 | +static bool pool_erased; |
||
114 | + |
||
115 | +/*************************************************************** |
||
116 | +* |
||
117 | +* Interface adaptor for preloader/uboot/kernel |
||
118 | +* These interfaces operate on physical address, read/write |
||
119 | +* physical data. |
||
120 | +* |
||
121 | +***************************************************************/ |
||
122 | +int nand_read_page_bmt(u32 page, u8 * dat, u8 * oob) |
||
123 | +{ |
||
124 | + return mtk_nand_exec_read_page(mtd_bmt, page, PAGE_SIZE_BMT, dat, oob); |
||
125 | +} |
||
126 | + |
||
127 | +bool nand_block_bad_bmt(u32 offset) |
||
128 | +{ |
||
129 | + return mtk_nand_block_bad_hw(mtd_bmt, offset); |
||
130 | +} |
||
131 | + |
||
132 | +bool nand_erase_bmt(u32 offset) |
||
133 | +{ |
||
134 | + int status; |
||
135 | + if (offset < 0x20000) |
||
136 | + { |
||
137 | + MSG(INIT, "erase offset: 0x%x\n", offset); |
||
138 | + } |
||
139 | + |
||
140 | + status = mtk_nand_erase_hw(mtd_bmt, offset / PAGE_SIZE_BMT); // as nand_chip structure doesn't have a erase function defined |
||
141 | + if (status & NAND_STATUS_FAIL) |
||
142 | + return false; |
||
143 | + else |
||
144 | + return true; |
||
145 | +} |
||
146 | + |
||
147 | +int mark_block_bad_bmt(u32 offset) |
||
148 | +{ |
||
149 | + return mtk_nand_block_markbad_hw(mtd_bmt, offset); //mark_block_bad_hw(offset); |
||
150 | +} |
||
151 | + |
||
152 | +bool nand_write_page_bmt(u32 page, u8 * dat, u8 * oob) |
||
153 | +{ |
||
154 | + if (mtk_nand_exec_write_page(mtd_bmt, page, PAGE_SIZE_BMT, dat, oob)) |
||
155 | + return false; |
||
156 | + else |
||
157 | + return true; |
||
158 | +} |
||
159 | + |
||
160 | +/*************************************************************** |
||
161 | +* * |
||
162 | +* static internal function * |
||
163 | +* * |
||
164 | +***************************************************************/ |
||
165 | +static void dump_bmt_info(bmt_struct * bmt) |
||
166 | +{ |
||
167 | + int i; |
||
168 | + |
||
169 | + MSG(INIT, "BMT v%d. total %d mapping:\n", bmt->version, bmt->mapped_count); |
||
170 | + for (i = 0; i < bmt->mapped_count; i++) |
||
171 | + { |
||
172 | + MSG(INIT, "\t0x%x -> 0x%x\n", bmt->table[i].bad_index, bmt->table[i].mapped_index); |
||
173 | + } |
||
174 | +} |
||
175 | + |
||
176 | +static bool match_bmt_signature(u8 * dat, u8 * oob) |
||
177 | +{ |
||
178 | + |
||
179 | + if (memcmp(dat + MAIN_SIGNATURE_OFFSET, MAIN_SIGNATURE, SIGNATURE_SIZE)) |
||
180 | + { |
||
181 | + return false; |
||
182 | + } |
||
183 | + |
||
184 | + if (memcmp(oob + OOB_SIGNATURE_OFFSET, OOB_SIGNATURE, SIGNATURE_SIZE)) |
||
185 | + { |
||
186 | + MSG(INIT, "main signature match, oob signature doesn't match, but ignore\n"); |
||
187 | + } |
||
188 | + return true; |
||
189 | +} |
||
190 | + |
||
191 | +static u8 cal_bmt_checksum(phys_bmt_struct * phys_table, int bmt_size) |
||
192 | +{ |
||
193 | + int i; |
||
194 | + u8 checksum = 0; |
||
195 | + u8 *dat = (u8 *) phys_table; |
||
196 | + |
||
197 | + checksum += phys_table->header.version; |
||
198 | + checksum += phys_table->header.mapped_count; |
||
199 | + |
||
200 | + dat += sizeof(phys_bmt_header); |
||
201 | + for (i = 0; i < bmt_size * sizeof(bmt_entry); i++) |
||
202 | + { |
||
203 | + checksum += dat[i]; |
||
204 | + } |
||
205 | + |
||
206 | + return checksum; |
||
207 | +} |
||
208 | + |
||
209 | + |
||
210 | +static int is_block_mapped(int index) |
||
211 | +{ |
||
212 | + int i; |
||
213 | + for (i = 0; i < bmt.mapped_count; i++) |
||
214 | + { |
||
215 | + if (index == bmt.table[i].mapped_index) |
||
216 | + return i; |
||
217 | + } |
||
218 | + return -1; |
||
219 | +} |
||
220 | + |
||
221 | +static bool is_page_used(u8 * dat, u8 * oob) |
||
222 | +{ |
||
223 | + return ((oob[OOB_INDEX_OFFSET] != 0xFF) || (oob[OOB_INDEX_OFFSET + 1] != 0xFF)); |
||
224 | +} |
||
225 | + |
||
226 | +static bool valid_bmt_data(phys_bmt_struct * phys_table) |
||
227 | +{ |
||
228 | + int i; |
||
229 | + u8 checksum = cal_bmt_checksum(phys_table, bmt_block_count); |
||
230 | + |
||
231 | + // checksum correct? |
||
232 | + if (phys_table->header.checksum != checksum) |
||
233 | + { |
||
234 | + MSG(INIT, "BMT Data checksum error: %x %x\n", phys_table->header.checksum, checksum); |
||
235 | + return false; |
||
236 | + } |
||
237 | + |
||
238 | + MSG(INIT, "BMT Checksum is: 0x%x\n", phys_table->header.checksum); |
||
239 | + |
||
240 | + // block index correct? |
||
241 | + for (i = 0; i < phys_table->header.mapped_count; i++) |
||
242 | + { |
||
243 | + if (phys_table->table[i].bad_index >= total_block_count || phys_table->table[i].mapped_index >= total_block_count || phys_table->table[i].mapped_index < system_block_count) |
||
244 | + { |
||
245 | + MSG(INIT, "index error: bad_index: %d, mapped_index: %d\n", phys_table->table[i].bad_index, phys_table->table[i].mapped_index); |
||
246 | + return false; |
||
247 | + } |
||
248 | + } |
||
249 | + |
||
250 | + // pass check, valid bmt. |
||
251 | + MSG(INIT, "Valid BMT, version v%d\n", phys_table->header.version); |
||
252 | + return true; |
||
253 | +} |
||
254 | + |
||
255 | +static void fill_nand_bmt_buffer(bmt_struct * bmt, u8 * dat, u8 * oob) |
||
256 | +{ |
||
257 | + phys_bmt_struct phys_bmt; |
||
258 | + |
||
259 | + dump_bmt_info(bmt); |
||
260 | + |
||
261 | + // fill phys_bmt_struct structure with bmt_struct |
||
262 | + memset(&phys_bmt, 0xFF, sizeof(phys_bmt)); |
||
263 | + |
||
264 | + memcpy(phys_bmt.header.signature, MAIN_SIGNATURE, SIGNATURE_SIZE); |
||
265 | + phys_bmt.header.version = BMT_VERSION; |
||
266 | + // phys_bmt.header.bad_count = bmt->bad_count; |
||
267 | + phys_bmt.header.mapped_count = bmt->mapped_count; |
||
268 | + memcpy(phys_bmt.table, bmt->table, sizeof(bmt_entry) * bmt_block_count); |
||
269 | + |
||
270 | + phys_bmt.header.checksum = cal_bmt_checksum(&phys_bmt, bmt_block_count); |
||
271 | + |
||
272 | + memcpy(dat + MAIN_SIGNATURE_OFFSET, &phys_bmt, sizeof(phys_bmt)); |
||
273 | + memcpy(oob + OOB_SIGNATURE_OFFSET, OOB_SIGNATURE, SIGNATURE_SIZE); |
||
274 | +} |
||
275 | + |
||
276 | +// return valid index if found BMT, else return 0 |
||
277 | +static int load_bmt_data(int start, int pool_size) |
||
278 | +{ |
||
279 | + int bmt_index = start + pool_size - 1; // find from the end |
||
280 | + phys_bmt_struct phys_table; |
||
281 | + int i; |
||
282 | + |
||
283 | + MSG(INIT, "[%s]: begin to search BMT from block 0x%x\n", __FUNCTION__, bmt_index); |
||
284 | + |
||
285 | + for (bmt_index = start + pool_size - 1; bmt_index >= start; bmt_index--) |
||
286 | + { |
||
287 | + if (nand_block_bad_bmt(OFFSET(bmt_index))) |
||
288 | + { |
||
289 | + MSG(INIT, "Skip bad block: %d\n", bmt_index); |
||
290 | + continue; |
||
291 | + } |
||
292 | + |
||
293 | + if (!nand_read_page_bmt(PAGE_ADDR(bmt_index), dat_buf, oob_buf)) |
||
294 | + { |
||
295 | + MSG(INIT, "Error found when read block %d\n", bmt_index); |
||
296 | + continue; |
||
297 | + } |
||
298 | + |
||
299 | + if (!match_bmt_signature(dat_buf, oob_buf)) |
||
300 | + { |
||
301 | + continue; |
||
302 | + } |
||
303 | + |
||
304 | + MSG(INIT, "Match bmt signature @ block: 0x%x\n", bmt_index); |
||
305 | + |
||
306 | + memcpy(&phys_table, dat_buf + MAIN_SIGNATURE_OFFSET, sizeof(phys_table)); |
||
307 | + |
||
308 | + if (!valid_bmt_data(&phys_table)) |
||
309 | + { |
||
310 | + MSG(INIT, "BMT data is not correct %d\n", bmt_index); |
||
311 | + continue; |
||
312 | + } else |
||
313 | + { |
||
314 | + bmt.mapped_count = phys_table.header.mapped_count; |
||
315 | + bmt.version = phys_table.header.version; |
||
316 | + // bmt.bad_count = phys_table.header.bad_count; |
||
317 | + memcpy(bmt.table, phys_table.table, bmt.mapped_count * sizeof(bmt_entry)); |
||
318 | + |
||
319 | + MSG(INIT, "bmt found at block: %d, mapped block: %d\n", bmt_index, bmt.mapped_count); |
||
320 | + |
||
321 | + for (i = 0; i < bmt.mapped_count; i++) |
||
322 | + { |
||
323 | + if (!nand_block_bad_bmt(OFFSET(bmt.table[i].bad_index))) |
||
324 | + { |
||
325 | + MSG(INIT, "block 0x%x is not mark bad, should be power lost last time\n", bmt.table[i].bad_index); |
||
326 | + mark_block_bad_bmt(OFFSET(bmt.table[i].bad_index)); |
||
327 | + } |
||
328 | + } |
||
329 | + |
||
330 | + return bmt_index; |
||
331 | + } |
||
332 | + } |
||
333 | + |
||
334 | + MSG(INIT, "bmt block not found!\n"); |
||
335 | + return 0; |
||
336 | +} |
||
337 | + |
||
338 | +/************************************************************************* |
||
339 | +* Find an available block and erase. * |
||
340 | +* start_from_end: if true, find available block from end of flash. * |
||
341 | +* else, find from the beginning of the pool * |
||
342 | +* need_erase: if true, all unmapped blocks in the pool will be erased * |
||
343 | +*************************************************************************/ |
||
344 | +static int find_available_block(bool start_from_end) |
||
345 | +{ |
||
346 | + int i; // , j; |
||
347 | + int block = system_block_count; |
||
348 | + int direction; |
||
349 | + // int avail_index = 0; |
||
350 | + MSG(INIT, "Try to find_available_block, pool_erase: %d\n", pool_erased); |
||
351 | + |
||
352 | + // erase all un-mapped blocks in pool when finding avaliable block |
||
353 | + if (!pool_erased) |
||
354 | + { |
||
355 | + MSG(INIT, "Erase all un-mapped blocks in pool\n"); |
||
356 | + for (i = 0; i < bmt_block_count; i++) |
||
357 | + { |
||
358 | + if (block == bmt_block_index) |
||
359 | + { |
||
360 | + MSG(INIT, "Skip bmt block 0x%x\n", block); |
||
361 | + continue; |
||
362 | + } |
||
363 | + |
||
364 | + if (nand_block_bad_bmt(OFFSET(block + i))) |
||
365 | + { |
||
366 | + MSG(INIT, "Skip bad block 0x%x\n", block + i); |
||
367 | + continue; |
||
368 | + } |
||
369 | +//if(block==4095) |
||
370 | +//{ |
||
371 | +// continue; |
||
372 | +//} |
||
373 | + |
||
374 | + if (is_block_mapped(block + i) >= 0) |
||
375 | + { |
||
376 | + MSG(INIT, "Skip mapped block 0x%x\n", block + i); |
||
377 | + continue; |
||
378 | + } |
||
379 | + |
||
380 | + if (!nand_erase_bmt(OFFSET(block + i))) |
||
381 | + { |
||
382 | + MSG(INIT, "Erase block 0x%x failed\n", block + i); |
||
383 | + mark_block_bad_bmt(OFFSET(block + i)); |
||
384 | + } |
||
385 | + } |
||
386 | + |
||
387 | + pool_erased = 1; |
||
388 | + } |
||
389 | + |
||
390 | + if (start_from_end) |
||
391 | + { |
||
392 | + block = total_block_count - 1; |
||
393 | + direction = -1; |
||
394 | + } else |
||
395 | + { |
||
396 | + block = system_block_count; |
||
397 | + direction = 1; |
||
398 | + } |
||
399 | + |
||
400 | + for (i = 0; i < bmt_block_count; i++, block += direction) |
||
401 | + { |
||
402 | + if (block == bmt_block_index) |
||
403 | + { |
||
404 | + MSG(INIT, "Skip bmt block 0x%x\n", block); |
||
405 | + continue; |
||
406 | + } |
||
407 | + |
||
408 | + if (nand_block_bad_bmt(OFFSET(block))) |
||
409 | + { |
||
410 | + MSG(INIT, "Skip bad block 0x%x\n", block); |
||
411 | + continue; |
||
412 | + } |
||
413 | + |
||
414 | + if (is_block_mapped(block) >= 0) |
||
415 | + { |
||
416 | + MSG(INIT, "Skip mapped block 0x%x\n", block); |
||
417 | + continue; |
||
418 | + } |
||
419 | + |
||
420 | + MSG(INIT, "Find block 0x%x available\n", block); |
||
421 | + return block; |
||
422 | + } |
||
423 | + |
||
424 | + return 0; |
||
425 | +} |
||
426 | + |
||
427 | +static unsigned short get_bad_index_from_oob(u8 * oob_buf) |
||
428 | +{ |
||
429 | + unsigned short index; |
||
430 | + memcpy(&index, oob_buf + OOB_INDEX_OFFSET, OOB_INDEX_SIZE); |
||
431 | + |
||
432 | + return index; |
||
433 | +} |
||
434 | + |
||
435 | +void set_bad_index_to_oob(u8 * oob, u16 index) |
||
436 | +{ |
||
437 | + memcpy(oob + OOB_INDEX_OFFSET, &index, sizeof(index)); |
||
438 | +} |
||
439 | + |
||
440 | +static int migrate_from_bad(int offset, u8 * write_dat, u8 * write_oob) |
||
441 | +{ |
||
442 | + int page; |
||
443 | + int error_block = offset / BLOCK_SIZE_BMT; |
||
444 | + int error_page = (offset / PAGE_SIZE_BMT) % page_per_block; |
||
445 | + int to_index; |
||
446 | + |
||
447 | + memcpy(oob_buf, write_oob, MAX_OOB_SIZE); |
||
448 | + |
||
449 | + to_index = find_available_block(false); |
||
450 | + |
||
451 | + if (!to_index) |
||
452 | + { |
||
453 | + MSG(INIT, "Cannot find an available block for BMT\n"); |
||
454 | + return 0; |
||
455 | + } |
||
456 | + |
||
457 | + { // migrate error page first |
||
458 | + MSG(INIT, "Write error page: 0x%x\n", error_page); |
||
459 | + if (!write_dat) |
||
460 | + { |
||
461 | + nand_read_page_bmt(PAGE_ADDR(error_block) + error_page, dat_buf, NULL); |
||
462 | + write_dat = dat_buf; |
||
463 | + } |
||
464 | + // memcpy(oob_buf, write_oob, MAX_OOB_SIZE); |
||
465 | + |
||
466 | + if (error_block < system_block_count) |
||
467 | + set_bad_index_to_oob(oob_buf, error_block); // if error_block is already a mapped block, original mapping index is in OOB. |
||
468 | + |
||
469 | + if (!nand_write_page_bmt(PAGE_ADDR(to_index) + error_page, write_dat, oob_buf)) |
||
470 | + { |
||
471 | + MSG(INIT, "Write to page 0x%x fail\n", PAGE_ADDR(to_index) + error_page); |
||
472 | + mark_block_bad_bmt(to_index); |
||
473 | + return migrate_from_bad(offset, write_dat, write_oob); |
||
474 | + } |
||
475 | + } |
||
476 | + |
||
477 | + for (page = 0; page < page_per_block; page++) |
||
478 | + { |
||
479 | + if (page != error_page) |
||
480 | + { |
||
481 | + nand_read_page_bmt(PAGE_ADDR(error_block) + page, dat_buf, oob_buf); |
||
482 | + if (is_page_used(dat_buf, oob_buf)) |
||
483 | + { |
||
484 | + if (error_block < system_block_count) |
||
485 | + { |
||
486 | + set_bad_index_to_oob(oob_buf, error_block); |
||
487 | + } |
||
488 | + MSG(INIT, "\tmigrate page 0x%x to page 0x%x\n", PAGE_ADDR(error_block) + page, PAGE_ADDR(to_index) + page); |
||
489 | + if (!nand_write_page_bmt(PAGE_ADDR(to_index) + page, dat_buf, oob_buf)) |
||
490 | + { |
||
491 | + MSG(INIT, "Write to page 0x%x fail\n", PAGE_ADDR(to_index) + page); |
||
492 | + mark_block_bad_bmt(to_index); |
||
493 | + return migrate_from_bad(offset, write_dat, write_oob); |
||
494 | + } |
||
495 | + } |
||
496 | + } |
||
497 | + } |
||
498 | + |
||
499 | + MSG(INIT, "Migrate from 0x%x to 0x%x done!\n", error_block, to_index); |
||
500 | + |
||
501 | + return to_index; |
||
502 | +} |
||
503 | + |
||
504 | +static bool write_bmt_to_flash(u8 * dat, u8 * oob) |
||
505 | +{ |
||
506 | + bool need_erase = true; |
||
507 | + MSG(INIT, "Try to write BMT\n"); |
||
508 | + |
||
509 | + if (bmt_block_index == 0) |
||
510 | + { |
||
511 | + // if we don't have index, we don't need to erase found block as it has been erased in find_available_block() |
||
512 | + need_erase = false; |
||
513 | + if (!(bmt_block_index = find_available_block(true))) |
||
514 | + { |
||
515 | + MSG(INIT, "Cannot find an available block for BMT\n"); |
||
516 | + return false; |
||
517 | + } |
||
518 | + } |
||
519 | + |
||
520 | + MSG(INIT, "Find BMT block: 0x%x\n", bmt_block_index); |
||
521 | + |
||
522 | + // write bmt to flash |
||
523 | + if (need_erase) |
||
524 | + { |
||
525 | + if (!nand_erase_bmt(OFFSET(bmt_block_index))) |
||
526 | + { |
||
527 | + MSG(INIT, "BMT block erase fail, mark bad: 0x%x\n", bmt_block_index); |
||
528 | + mark_block_bad_bmt(OFFSET(bmt_block_index)); |
||
529 | + // bmt.bad_count++; |
||
530 | + |
||
531 | + bmt_block_index = 0; |
||
532 | + return write_bmt_to_flash(dat, oob); // recursive call |
||
533 | + } |
||
534 | + } |
||
535 | + |
||
536 | + if (!nand_write_page_bmt(PAGE_ADDR(bmt_block_index), dat, oob)) |
||
537 | + { |
||
538 | + MSG(INIT, "Write BMT data fail, need to write again\n"); |
||
539 | + mark_block_bad_bmt(OFFSET(bmt_block_index)); |
||
540 | + // bmt.bad_count++; |
||
541 | + |
||
542 | + bmt_block_index = 0; |
||
543 | + return write_bmt_to_flash(dat, oob); // recursive call |
||
544 | + } |
||
545 | + |
||
546 | + MSG(INIT, "Write BMT data to block 0x%x success\n", bmt_block_index); |
||
547 | + return true; |
||
548 | +} |
||
549 | + |
||
550 | +/******************************************************************* |
||
551 | +* Reconstruct bmt, called when found bmt info doesn't match bad |
||
552 | +* block info in flash. |
||
553 | +* |
||
554 | +* Return NULL for failure |
||
555 | +*******************************************************************/ |
||
556 | +bmt_struct *reconstruct_bmt(bmt_struct * bmt) |
||
557 | +{ |
||
558 | + int i; |
||
559 | + int index = system_block_count; |
||
560 | + unsigned short bad_index; |
||
561 | + int mapped; |
||
562 | + |
||
563 | + // init everything in BMT struct |
||
564 | + bmt->version = BMT_VERSION; |
||
565 | + bmt->bad_count = 0; |
||
566 | + bmt->mapped_count = 0; |
||
567 | + |
||
568 | + memset(bmt->table, 0, bmt_block_count * sizeof(bmt_entry)); |
||
569 | + |
||
570 | + for (i = 0; i < bmt_block_count; i++, index++) |
||
571 | + { |
||
572 | + if (nand_block_bad_bmt(OFFSET(index))) |
||
573 | + { |
||
574 | + MSG(INIT, "Skip bad block: 0x%x\n", index); |
||
575 | + // bmt->bad_count++; |
||
576 | + continue; |
||
577 | + } |
||
578 | + |
||
579 | + MSG(INIT, "read page: 0x%x\n", PAGE_ADDR(index)); |
||
580 | + nand_read_page_bmt(PAGE_ADDR(index), dat_buf, oob_buf); |
||
581 | + /* if (mtk_nand_read_page_hw(PAGE_ADDR(index), dat_buf)) |
||
582 | + { |
||
583 | + MSG(INIT, "Error when read block %d\n", bmt_block_index); |
||
584 | + continue; |
||
585 | + } */ |
||
586 | + |
||
587 | + if ((bad_index = get_bad_index_from_oob(oob_buf)) >= system_block_count) |
||
588 | + { |
||
589 | + MSG(INIT, "get bad index: 0x%x\n", bad_index); |
||
590 | + if (bad_index != 0xFFFF) |
||
591 | + MSG(INIT, "Invalid bad index found in block 0x%x, bad index 0x%x\n", index, bad_index); |
||
592 | + continue; |
||
593 | + } |
||
594 | + |
||
595 | + MSG(INIT, "Block 0x%x is mapped to bad block: 0x%x\n", index, bad_index); |
||
596 | + |
||
597 | + if (!nand_block_bad_bmt(OFFSET(bad_index))) |
||
598 | + { |
||
599 | + MSG(INIT, "\tbut block 0x%x is not marked as bad, invalid mapping\n", bad_index); |
||
600 | + continue; // no need to erase here, it will be erased later when trying to write BMT |
||
601 | + } |
||
602 | + |
||
603 | + if ((mapped = is_block_mapped(bad_index)) >= 0) |
||
604 | + { |
||
605 | + MSG(INIT, "bad block 0x%x is mapped to 0x%x, should be caused by power lost, replace with one\n", bmt->table[mapped].bad_index, bmt->table[mapped].mapped_index); |
||
606 | + bmt->table[mapped].mapped_index = index; // use new one instead. |
||
607 | + } else |
||
608 | + { |
||
609 | + // add mapping to BMT |
||
610 | + bmt->table[bmt->mapped_count].bad_index = bad_index; |
||
611 | + bmt->table[bmt->mapped_count].mapped_index = index; |
||
612 | + bmt->mapped_count++; |
||
613 | + } |
||
614 | + |
||
615 | + MSG(INIT, "Add mapping: 0x%x -> 0x%x to BMT\n", bad_index, index); |
||
616 | + |
||
617 | + } |
||
618 | + |
||
619 | + MSG(INIT, "Scan replace pool done, mapped block: %d\n", bmt->mapped_count); |
||
620 | + // dump_bmt_info(bmt); |
||
621 | + |
||
622 | + // fill NAND BMT buffer |
||
623 | + memset(oob_buf, 0xFF, sizeof(oob_buf)); |
||
624 | + fill_nand_bmt_buffer(bmt, dat_buf, oob_buf); |
||
625 | + |
||
626 | + // write BMT back |
||
627 | + if (!write_bmt_to_flash(dat_buf, oob_buf)) |
||
628 | + { |
||
629 | + MSG(INIT, "TRAGEDY: cannot find a place to write BMT!!!!\n"); |
||
630 | + } |
||
631 | + |
||
632 | + return bmt; |
||
633 | +} |
||
634 | + |
||
635 | +/******************************************************************* |
||
636 | +* [BMT Interface] |
||
637 | +* |
||
638 | +* Description: |
||
639 | +* Init bmt from nand. Reconstruct if not found or data error |
||
640 | +* |
||
641 | +* Parameter: |
||
642 | +* size: size of bmt and replace pool |
||
643 | +* |
||
644 | +* Return: |
||
645 | +* NULL for failure, and a bmt struct for success |
||
646 | +*******************************************************************/ |
||
647 | +bmt_struct *init_bmt(struct nand_chip * chip, int size) |
||
648 | +{ |
||
649 | + struct mtk_nand_host *host; |
||
650 | + |
||
651 | + if (size > 0 && size < MAX_BMT_SIZE) |
||
652 | + { |
||
653 | + MSG(INIT, "Init bmt table, size: %d\n", size); |
||
654 | + bmt_block_count = size; |
||
655 | + } else |
||
656 | + { |
||
657 | + MSG(INIT, "Invalid bmt table size: %d\n", size); |
||
658 | + return NULL; |
||
659 | + } |
||
660 | + nand_chip_bmt = chip; |
||
661 | + system_block_count = chip->chipsize >> chip->phys_erase_shift; |
||
662 | + total_block_count = bmt_block_count + system_block_count; |
||
663 | + page_per_block = BLOCK_SIZE_BMT / PAGE_SIZE_BMT; |
||
664 | + host = (struct mtk_nand_host *)chip->priv; |
||
665 | + mtd_bmt = host->mtd; |
||
666 | + |
||
667 | + MSG(INIT, "mtd_bmt: %p, nand_chip_bmt: %p\n", mtd_bmt, nand_chip_bmt); |
||
668 | + MSG(INIT, "bmt count: %d, system count: %d\n", bmt_block_count, system_block_count); |
||
669 | + |
||
670 | + // set this flag, and unmapped block in pool will be erased. |
||
671 | + pool_erased = 0; |
||
672 | + memset(bmt.table, 0, size * sizeof(bmt_entry)); |
||
673 | + if ((bmt_block_index = load_bmt_data(system_block_count, size))) |
||
674 | + { |
||
675 | + MSG(INIT, "Load bmt data success @ block 0x%x\n", bmt_block_index); |
||
676 | + dump_bmt_info(&bmt); |
||
677 | + return &bmt; |
||
678 | + } else |
||
679 | + { |
||
680 | + MSG(INIT, "Load bmt data fail, need re-construct!\n"); |
||
681 | +#ifndef __UBOOT_NAND__ // BMT is not re-constructed in UBOOT. |
||
682 | + if (reconstruct_bmt(&bmt)) |
||
683 | + return &bmt; |
||
684 | + else |
||
685 | +#endif |
||
686 | + return NULL; |
||
687 | + } |
||
688 | +} |
||
689 | + |
||
690 | +/******************************************************************* |
||
691 | +* [BMT Interface] |
||
692 | +* |
||
693 | +* Description: |
||
694 | +* Update BMT. |
||
695 | +* |
||
696 | +* Parameter: |
||
697 | +* offset: update block/page offset. |
||
698 | +* reason: update reason, see update_reason_t for reason. |
||
699 | +* dat/oob: data and oob buffer for write fail. |
||
700 | +* |
||
701 | +* Return: |
||
702 | +* Return true for success, and false for failure. |
||
703 | +*******************************************************************/ |
||
704 | +bool update_bmt(u32 offset, update_reason_t reason, u8 * dat, u8 * oob) |
||
705 | +{ |
||
706 | + int map_index; |
||
707 | + int orig_bad_block = -1; |
||
708 | + // int bmt_update_index; |
||
709 | + int i; |
||
710 | + int bad_index = offset / BLOCK_SIZE_BMT; |
||
711 | + |
||
712 | +#ifndef MTK_NAND_BMT |
||
713 | + return false; |
||
714 | +#endif |
||
715 | + if (reason == UPDATE_WRITE_FAIL) |
||
716 | + { |
||
717 | + MSG(INIT, "Write fail, need to migrate\n"); |
||
718 | + if (!(map_index = migrate_from_bad(offset, dat, oob))) |
||
719 | + { |
||
720 | + MSG(INIT, "migrate fail\n"); |
||
721 | + return false; |
||
722 | + } |
||
723 | + } else |
||
724 | + { |
||
725 | + if (!(map_index = find_available_block(false))) |
||
726 | + { |
||
727 | + MSG(INIT, "Cannot find block in pool\n"); |
||
728 | + return false; |
||
729 | + } |
||
730 | + } |
||
731 | + |
||
732 | + // now let's update BMT |
||
733 | + if (bad_index >= system_block_count) // mapped block become bad, find original bad block |
||
734 | + { |
||
735 | + for (i = 0; i < bmt_block_count; i++) |
||
736 | + { |
||
737 | + if (bmt.table[i].mapped_index == bad_index) |
||
738 | + { |
||
739 | + orig_bad_block = bmt.table[i].bad_index; |
||
740 | + break; |
||
741 | + } |
||
742 | + } |
||
743 | + // bmt.bad_count++; |
||
744 | + MSG(INIT, "Mapped block becomes bad, orig bad block is 0x%x\n", orig_bad_block); |
||
745 | + |
||
746 | + bmt.table[i].mapped_index = map_index; |
||
747 | + } else |
||
748 | + { |
||
749 | + bmt.table[bmt.mapped_count].mapped_index = map_index; |
||
750 | + bmt.table[bmt.mapped_count].bad_index = bad_index; |
||
751 | + bmt.mapped_count++; |
||
752 | + } |
||
753 | + |
||
754 | + memset(oob_buf, 0xFF, sizeof(oob_buf)); |
||
755 | + fill_nand_bmt_buffer(&bmt, dat_buf, oob_buf); |
||
756 | + if (!write_bmt_to_flash(dat_buf, oob_buf)) |
||
757 | + return false; |
||
758 | + |
||
759 | + mark_block_bad_bmt(offset); |
||
760 | + |
||
761 | + return true; |
||
762 | +} |
||
763 | + |
||
764 | +/******************************************************************* |
||
765 | +* [BMT Interface] |
||
766 | +* |
||
767 | +* Description: |
||
768 | +* Given an block index, return mapped index if it's mapped, else |
||
769 | +* return given index. |
||
770 | +* |
||
771 | +* Parameter: |
||
772 | +* index: given an block index. This value cannot exceed |
||
773 | +* system_block_count. |
||
774 | +* |
||
775 | +* Return NULL for failure |
||
776 | +*******************************************************************/ |
||
777 | +u16 get_mapping_block_index(int index) |
||
778 | +{ |
||
779 | + int i; |
||
780 | +#ifndef MTK_NAND_BMT |
||
781 | + return index; |
||
782 | +#endif |
||
783 | + if (index > system_block_count) |
||
784 | + { |
||
785 | + return index; |
||
786 | + } |
||
787 | + |
||
788 | + for (i = 0; i < bmt.mapped_count; i++) |
||
789 | + { |
||
790 | + if (bmt.table[i].bad_index == index) |
||
791 | + { |
||
792 | + return bmt.table[i].mapped_index; |
||
793 | + } |
||
794 | + } |
||
795 | + |
||
796 | + return index; |
||
797 | +} |
||
798 | +#ifdef __KERNEL_NAND__ |
||
799 | +EXPORT_SYMBOL_GPL(init_bmt); |
||
800 | +EXPORT_SYMBOL_GPL(update_bmt); |
||
801 | +EXPORT_SYMBOL_GPL(get_mapping_block_index); |
||
802 | + |
||
803 | +MODULE_LICENSE("GPL"); |
||
804 | +MODULE_AUTHOR("MediaTek"); |
||
805 | +MODULE_DESCRIPTION("Bad Block mapping management for MediaTek NAND Flash Driver"); |
||
806 | +#endif |
||
807 | --- /dev/null |
||
808 | +++ b/drivers/mtd/nand/bmt.h |
||
809 | @@ -0,0 +1,80 @@ |
||
810 | +#ifndef __BMT_H__ |
||
811 | +#define __BMT_H__ |
||
812 | + |
||
813 | +#include "nand_def.h" |
||
814 | + |
||
815 | +#if defined(__PRELOADER_NAND__) |
||
816 | + |
||
817 | +#include "nand.h" |
||
818 | + |
||
819 | +#elif defined(__UBOOT_NAND__) |
||
820 | + |
||
821 | +#include <linux/mtd/nand.h> |
||
822 | +#include "mtk_nand2.h" |
||
823 | + |
||
824 | +#elif defined(__KERNEL_NAND__) |
||
825 | + |
||
826 | +#include <linux/mtd/mtd.h> |
||
827 | +#include <linux/mtd/rawnand.h> |
||
828 | +#include <linux/module.h> |
||
829 | +#include "mtk_nand2.h" |
||
830 | + |
||
831 | +#endif |
||
832 | + |
||
833 | + |
||
834 | +#define MAX_BMT_SIZE (0x80) |
||
835 | +#define BMT_VERSION (1) // initial version |
||
836 | + |
||
837 | +#define MAIN_SIGNATURE_OFFSET (0) |
||
838 | +#define OOB_SIGNATURE_OFFSET (1) |
||
839 | +#define OOB_INDEX_OFFSET (29) |
||
840 | +#define OOB_INDEX_SIZE (2) |
||
841 | +#define FAKE_INDEX (0xAAAA) |
||
842 | + |
||
843 | +typedef struct _bmt_entry_ |
||
844 | +{ |
||
845 | + u16 bad_index; // bad block index |
||
846 | + u16 mapped_index; // mapping block index in the replace pool |
||
847 | +} bmt_entry; |
||
848 | + |
||
849 | +typedef enum |
||
850 | +{ |
||
851 | + UPDATE_ERASE_FAIL, |
||
852 | + UPDATE_WRITE_FAIL, |
||
853 | + UPDATE_UNMAPPED_BLOCK, |
||
854 | + UPDATE_REASON_COUNT, |
||
855 | +} update_reason_t; |
||
856 | + |
||
857 | +typedef struct |
||
858 | +{ |
||
859 | + bmt_entry table[MAX_BMT_SIZE]; |
||
860 | + u8 version; |
||
861 | + u8 mapped_count; // mapped block count in pool |
||
862 | + u8 bad_count; // bad block count in pool. Not used in V1 |
||
863 | +} bmt_struct; |
||
864 | + |
||
865 | +/*************************************************************** |
||
866 | +* * |
||
867 | +* Interface BMT need to use * |
||
868 | +* * |
||
869 | +***************************************************************/ |
||
870 | +extern bool mtk_nand_exec_read_page(struct mtd_info *mtd, u32 row, u32 page_size, u8 * dat, u8 * oob); |
||
871 | +extern int mtk_nand_block_bad_hw(struct mtd_info *mtd, loff_t ofs); |
||
872 | +extern int mtk_nand_erase_hw(struct mtd_info *mtd, int page); |
||
873 | +extern int mtk_nand_block_markbad_hw(struct mtd_info *mtd, loff_t ofs); |
||
874 | +extern int mtk_nand_exec_write_page(struct mtd_info *mtd, u32 row, u32 page_size, u8 * dat, u8 * oob); |
||
875 | + |
||
876 | + |
||
877 | +/*************************************************************** |
||
878 | +* * |
||
879 | +* Different function interface for preloader/uboot/kernel * |
||
880 | +* * |
||
881 | +***************************************************************/ |
||
882 | +void set_bad_index_to_oob(u8 * oob, u16 index); |
||
883 | + |
||
884 | + |
||
885 | +bmt_struct *init_bmt(struct nand_chip *nand, int size); |
||
886 | +bool update_bmt(u32 offset, update_reason_t reason, u8 * dat, u8 * oob); |
||
887 | +unsigned short get_mapping_block_index(int index); |
||
888 | + |
||
889 | +#endif // #ifndef __BMT_H__ |
||
890 | --- /dev/null |
||
891 | +++ b/drivers/mtd/nand/dev-nand.c |
||
892 | @@ -0,0 +1,63 @@ |
||
893 | +#include <linux/init.h> |
||
894 | +#include <linux/kernel.h> |
||
895 | +#include <linux/platform_device.h> |
||
896 | + |
||
897 | +#include "mt6575_typedefs.h" |
||
898 | + |
||
899 | +#define RALINK_NAND_CTRL_BASE 0xBE003000 |
||
900 | +#define NFI_base RALINK_NAND_CTRL_BASE |
||
901 | +#define RALINK_NANDECC_CTRL_BASE 0xBE003800 |
||
902 | +#define NFIECC_base RALINK_NANDECC_CTRL_BASE |
||
903 | +#define MT7621_NFI_IRQ_ID SURFBOARDINT_NAND |
||
904 | +#define MT7621_NFIECC_IRQ_ID SURFBOARDINT_NAND_ECC |
||
905 | + |
||
906 | +#define SURFBOARDINT_NAND 22 |
||
907 | +#define SURFBOARDINT_NAND_ECC 23 |
||
908 | + |
||
909 | +static struct resource MT7621_resource_nand[] = { |
||
910 | + { |
||
911 | + .start = NFI_base, |
||
912 | + .end = NFI_base + 0x1A0, |
||
913 | + .flags = IORESOURCE_MEM, |
||
914 | + }, |
||
915 | + { |
||
916 | + .start = NFIECC_base, |
||
917 | + .end = NFIECC_base + 0x150, |
||
918 | + .flags = IORESOURCE_MEM, |
||
919 | + }, |
||
920 | + { |
||
921 | + .start = MT7621_NFI_IRQ_ID, |
||
922 | + .flags = IORESOURCE_IRQ, |
||
923 | + }, |
||
924 | + { |
||
925 | + .start = MT7621_NFIECC_IRQ_ID, |
||
926 | + .flags = IORESOURCE_IRQ, |
||
927 | + }, |
||
928 | +}; |
||
929 | + |
||
930 | +static struct platform_device MT7621_nand_dev = { |
||
931 | + .name = "MT7621-NAND", |
||
932 | + .id = 0, |
||
933 | + .num_resources = ARRAY_SIZE(MT7621_resource_nand), |
||
934 | + .resource = MT7621_resource_nand, |
||
935 | + .dev = { |
||
936 | + .platform_data = &mt7621_nand_hw, |
||
937 | + }, |
||
938 | +}; |
||
939 | + |
||
940 | + |
||
941 | +int __init mtk_nand_register(void) |
||
942 | +{ |
||
943 | + |
||
944 | + int retval = 0; |
||
945 | + |
||
946 | + retval = platform_device_register(&MT7621_nand_dev); |
||
947 | + if (retval != 0) { |
||
948 | + printk(KERN_ERR "register nand device fail\n"); |
||
949 | + return retval; |
||
950 | + } |
||
951 | + |
||
952 | + |
||
953 | + return retval; |
||
954 | +} |
||
955 | +arch_initcall(mtk_nand_register); |
||
956 | --- /dev/null |
||
957 | +++ b/drivers/mtd/nand/mt6575_typedefs.h |
||
958 | @@ -0,0 +1,340 @@ |
||
959 | +/* Copyright Statement: |
||
960 | + * |
||
961 | + * This software/firmware and related documentation ("MediaTek Software") are |
||
962 | + * protected under relevant copyright laws. The information contained herein |
||
963 | + * is confidential and proprietary to MediaTek Inc. and/or its licensors. |
||
964 | + * Without the prior written permission of MediaTek inc. and/or its licensors, |
||
965 | + * any reproduction, modification, use or disclosure of MediaTek Software, |
||
966 | + * and information contained herein, in whole or in part, shall be strictly prohibited. |
||
967 | + */ |
||
968 | +/* MediaTek Inc. (C) 2010. All rights reserved. |
||
969 | + * |
||
970 | + * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES |
||
971 | + * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE") |
||
972 | + * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON |
||
973 | + * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES, |
||
974 | + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF |
||
975 | + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT. |
||
976 | + * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE |
||
977 | + * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR |
||
978 | + * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH |
||
979 | + * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES |
||
980 | + * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES |
||
981 | + * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK |
||
982 | + * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR |
||
983 | + * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND |
||
984 | + * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE, |
||
985 | + * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE, |
||
986 | + * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO |
||
987 | + * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. |
||
988 | + * |
||
989 | + * The following software/firmware and/or related documentation ("MediaTek Software") |
||
990 | + * have been modified by MediaTek Inc. All revisions are subject to any receiver's |
||
991 | + * applicable license agreements with MediaTek Inc. |
||
992 | + */ |
||
993 | + |
||
994 | +/***************************************************************************** |
||
995 | +* Copyright Statement: |
||
996 | +* -------------------- |
||
997 | +* This software is protected by Copyright and the information contained |
||
998 | +* herein is confidential. The software may not be copied and the information |
||
999 | +* contained herein may not be used or disclosed except with the written |
||
1000 | +* permission of MediaTek Inc. (C) 2008 |
||
1001 | +* |
||
1002 | +* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES |
||
1003 | +* THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE") |
||
1004 | +* RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO BUYER ON |
||
1005 | +* AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES, |
||
1006 | +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF |
||
1007 | +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT. |
||
1008 | +* NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE |
||
1009 | +* SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR |
||
1010 | +* SUPPLIED WITH THE MEDIATEK SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH |
||
1011 | +* THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO |
||
1012 | +* NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S |
||
1013 | +* SPECIFICATION OR TO CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. |
||
1014 | +* |
||
1015 | +* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE |
||
1016 | +* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE, |
||
1017 | +* AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE, |
||
1018 | +* OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY BUYER TO |
||
1019 | +* MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. |
||
1020 | +* |
||
1021 | +* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE |
||
1022 | +* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT OF |
||
1023 | +* LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING THEREOF AND |
||
1024 | +* RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN FRANCISCO, CA, UNDER |
||
1025 | +* THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE (ICC). |
||
1026 | +* |
||
1027 | +*****************************************************************************/ |
||
1028 | + |
||
1029 | +#ifndef _MT6575_TYPEDEFS_H |
||
1030 | +#define _MT6575_TYPEDEFS_H |
||
1031 | + |
||
1032 | +#if defined (__KERNEL_NAND__) |
||
1033 | +#include <linux/bug.h> |
||
1034 | +#else |
||
1035 | +#define true 1 |
||
1036 | +#define false 0 |
||
1037 | +#define bool u8 |
||
1038 | +#endif |
||
1039 | + |
||
1040 | +// --------------------------------------------------------------------------- |
||
1041 | +// Basic Type Definitions |
||
1042 | +// --------------------------------------------------------------------------- |
||
1043 | + |
||
1044 | +typedef volatile unsigned char *P_kal_uint8; |
||
1045 | +typedef volatile unsigned short *P_kal_uint16; |
||
1046 | +typedef volatile unsigned int *P_kal_uint32; |
||
1047 | + |
||
1048 | +typedef long LONG; |
||
1049 | +typedef unsigned char UBYTE; |
||
1050 | +typedef short SHORT; |
||
1051 | + |
||
1052 | +typedef signed char kal_int8; |
||
1053 | +typedef signed short kal_int16; |
||
1054 | +typedef signed int kal_int32; |
||
1055 | +typedef long long kal_int64; |
||
1056 | +typedef unsigned char kal_uint8; |
||
1057 | +typedef unsigned short kal_uint16; |
||
1058 | +typedef unsigned int kal_uint32; |
||
1059 | +typedef unsigned long long kal_uint64; |
||
1060 | +typedef char kal_char; |
||
1061 | + |
||
1062 | +typedef unsigned int *UINT32P; |
||
1063 | +typedef volatile unsigned short *UINT16P; |
||
1064 | +typedef volatile unsigned char *UINT8P; |
||
1065 | +typedef unsigned char *U8P; |
||
1066 | + |
||
1067 | +typedef volatile unsigned char *P_U8; |
||
1068 | +typedef volatile signed char *P_S8; |
||
1069 | +typedef volatile unsigned short *P_U16; |
||
1070 | +typedef volatile signed short *P_S16; |
||
1071 | +typedef volatile unsigned int *P_U32; |
||
1072 | +typedef volatile signed int *P_S32; |
||
1073 | +typedef unsigned long long *P_U64; |
||
1074 | +typedef signed long long *P_S64; |
||
1075 | + |
||
1076 | +typedef unsigned char U8; |
||
1077 | +typedef signed char S8; |
||
1078 | +typedef unsigned short U16; |
||
1079 | +typedef signed short S16; |
||
1080 | +typedef unsigned int U32; |
||
1081 | +typedef signed int S32; |
||
1082 | +typedef unsigned long long U64; |
||
1083 | +typedef signed long long S64; |
||
1084 | +//typedef unsigned char bool; |
||
1085 | + |
||
1086 | +typedef unsigned char UINT8; |
||
1087 | +typedef unsigned short UINT16; |
||
1088 | +typedef unsigned int UINT32; |
||
1089 | +typedef unsigned short USHORT; |
||
1090 | +typedef signed char INT8; |
||
1091 | +typedef signed short INT16; |
||
1092 | +typedef signed int INT32; |
||
1093 | +typedef unsigned int DWORD; |
||
1094 | +typedef void VOID; |
||
1095 | +typedef unsigned char BYTE; |
||
1096 | +typedef float FLOAT; |
||
1097 | + |
||
1098 | +typedef char *LPCSTR; |
||
1099 | +typedef short *LPWSTR; |
||
1100 | + |
||
1101 | + |
||
1102 | +// --------------------------------------------------------------------------- |
||
1103 | +// Constants |
||
1104 | +// --------------------------------------------------------------------------- |
||
1105 | + |
||
1106 | +#define IMPORT EXTERN |
||
1107 | +#ifndef __cplusplus |
||
1108 | + #define EXTERN extern |
||
1109 | +#else |
||
1110 | + #define EXTERN extern "C" |
||
1111 | +#endif |
||
1112 | +#define LOCAL static |
||
1113 | +#define GLOBAL |
||
1114 | +#define EXPORT GLOBAL |
||
1115 | + |
||
1116 | +#define EQ == |
||
1117 | +#define NEQ != |
||
1118 | +#define AND && |
||
1119 | +#define OR || |
||
1120 | +#define XOR(A,B) ((!(A) AND (B)) OR ((A) AND !(B))) |
||
1121 | + |
||
1122 | +#ifndef FALSE |
||
1123 | + #define FALSE (0) |
||
1124 | +#endif |
||
1125 | + |
||
1126 | +#ifndef TRUE |
||
1127 | + #define TRUE (1) |
||
1128 | +#endif |
||
1129 | + |
||
1130 | +#ifndef NULL |
||
1131 | + #define NULL (0) |
||
1132 | +#endif |
||
1133 | + |
||
1134 | +//enum boolean {false, true}; |
||
1135 | +enum {RX, TX, NONE}; |
||
1136 | + |
||
1137 | +#ifndef BOOL |
||
1138 | +typedef unsigned char BOOL; |
||
1139 | +#endif |
||
1140 | + |
||
1141 | +typedef enum { |
||
1142 | + KAL_FALSE = 0, |
||
1143 | + KAL_TRUE = 1, |
||
1144 | +} kal_bool; |
||
1145 | + |
||
1146 | + |
||
1147 | +// --------------------------------------------------------------------------- |
||
1148 | +// Type Casting |
||
1149 | +// --------------------------------------------------------------------------- |
||
1150 | + |
||
1151 | +#define AS_INT32(x) (*(INT32 *)((void*)x)) |
||
1152 | +#define AS_INT16(x) (*(INT16 *)((void*)x)) |
||
1153 | +#define AS_INT8(x) (*(INT8 *)((void*)x)) |
||
1154 | + |
||
1155 | +#define AS_UINT32(x) (*(UINT32 *)((void*)x)) |
||
1156 | +#define AS_UINT16(x) (*(UINT16 *)((void*)x)) |
||
1157 | +#define AS_UINT8(x) (*(UINT8 *)((void*)x)) |
||
1158 | + |
||
1159 | + |
||
1160 | +// --------------------------------------------------------------------------- |
||
1161 | +// Register Manipulations |
||
1162 | +// --------------------------------------------------------------------------- |
||
1163 | + |
||
1164 | +#define READ_REGISTER_UINT32(reg) \ |
||
1165 | + (*(volatile UINT32 * const)(reg)) |
||
1166 | + |
||
1167 | +#define WRITE_REGISTER_UINT32(reg, val) \ |
||
1168 | + (*(volatile UINT32 * const)(reg)) = (val) |
||
1169 | + |
||
1170 | +#define READ_REGISTER_UINT16(reg) \ |
||
1171 | + (*(volatile UINT16 * const)(reg)) |
||
1172 | + |
||
1173 | +#define WRITE_REGISTER_UINT16(reg, val) \ |
||
1174 | + (*(volatile UINT16 * const)(reg)) = (val) |
||
1175 | + |
||
1176 | +#define READ_REGISTER_UINT8(reg) \ |
||
1177 | + (*(volatile UINT8 * const)(reg)) |
||
1178 | + |
||
1179 | +#define WRITE_REGISTER_UINT8(reg, val) \ |
||
1180 | + (*(volatile UINT8 * const)(reg)) = (val) |
||
1181 | + |
||
1182 | +#define INREG8(x) READ_REGISTER_UINT8((UINT8*)((void*)(x))) |
||
1183 | +#define OUTREG8(x, y) WRITE_REGISTER_UINT8((UINT8*)((void*)(x)), (UINT8)(y)) |
||
1184 | +#define SETREG8(x, y) OUTREG8(x, INREG8(x)|(y)) |
||
1185 | +#define CLRREG8(x, y) OUTREG8(x, INREG8(x)&~(y)) |
||
1186 | +#define MASKREG8(x, y, z) OUTREG8(x, (INREG8(x)&~(y))|(z)) |
||
1187 | + |
||
1188 | +#define INREG16(x) READ_REGISTER_UINT16((UINT16*)((void*)(x))) |
||
1189 | +#define OUTREG16(x, y) WRITE_REGISTER_UINT16((UINT16*)((void*)(x)),(UINT16)(y)) |
||
1190 | +#define SETREG16(x, y) OUTREG16(x, INREG16(x)|(y)) |
||
1191 | +#define CLRREG16(x, y) OUTREG16(x, INREG16(x)&~(y)) |
||
1192 | +#define MASKREG16(x, y, z) OUTREG16(x, (INREG16(x)&~(y))|(z)) |
||
1193 | + |
||
1194 | +#define INREG32(x) READ_REGISTER_UINT32((UINT32*)((void*)(x))) |
||
1195 | +#define OUTREG32(x, y) WRITE_REGISTER_UINT32((UINT32*)((void*)(x)), (UINT32)(y)) |
||
1196 | +#define SETREG32(x, y) OUTREG32(x, INREG32(x)|(y)) |
||
1197 | +#define CLRREG32(x, y) OUTREG32(x, INREG32(x)&~(y)) |
||
1198 | +#define MASKREG32(x, y, z) OUTREG32(x, (INREG32(x)&~(y))|(z)) |
||
1199 | + |
||
1200 | + |
||
1201 | +#define DRV_Reg8(addr) INREG8(addr) |
||
1202 | +#define DRV_WriteReg8(addr, data) OUTREG8(addr, data) |
||
1203 | +#define DRV_SetReg8(addr, data) SETREG8(addr, data) |
||
1204 | +#define DRV_ClrReg8(addr, data) CLRREG8(addr, data) |
||
1205 | + |
||
1206 | +#define DRV_Reg16(addr) INREG16(addr) |
||
1207 | +#define DRV_WriteReg16(addr, data) OUTREG16(addr, data) |
||
1208 | +#define DRV_SetReg16(addr, data) SETREG16(addr, data) |
||
1209 | +#define DRV_ClrReg16(addr, data) CLRREG16(addr, data) |
||
1210 | + |
||
1211 | +#define DRV_Reg32(addr) INREG32(addr) |
||
1212 | +#define DRV_WriteReg32(addr, data) OUTREG32(addr, data) |
||
1213 | +#define DRV_SetReg32(addr, data) SETREG32(addr, data) |
||
1214 | +#define DRV_ClrReg32(addr, data) CLRREG32(addr, data) |
||
1215 | + |
||
1216 | +// !!! DEPRECATED, WILL BE REMOVED LATER !!! |
||
1217 | +#define DRV_Reg(addr) DRV_Reg16(addr) |
||
1218 | +#define DRV_WriteReg(addr, data) DRV_WriteReg16(addr, data) |
||
1219 | +#define DRV_SetReg(addr, data) DRV_SetReg16(addr, data) |
||
1220 | +#define DRV_ClrReg(addr, data) DRV_ClrReg16(addr, data) |
||
1221 | + |
||
1222 | + |
||
1223 | +// --------------------------------------------------------------------------- |
||
1224 | +// Compiler Time Deduction Macros |
||
1225 | +// --------------------------------------------------------------------------- |
||
1226 | + |
||
1227 | +#define _MASK_OFFSET_1(x, n) ((x) & 0x1) ? (n) : |
||
1228 | +#define _MASK_OFFSET_2(x, n) _MASK_OFFSET_1((x), (n)) _MASK_OFFSET_1((x) >> 1, (n) + 1) |
||
1229 | +#define _MASK_OFFSET_4(x, n) _MASK_OFFSET_2((x), (n)) _MASK_OFFSET_2((x) >> 2, (n) + 2) |
||
1230 | +#define _MASK_OFFSET_8(x, n) _MASK_OFFSET_4((x), (n)) _MASK_OFFSET_4((x) >> 4, (n) + 4) |
||
1231 | +#define _MASK_OFFSET_16(x, n) _MASK_OFFSET_8((x), (n)) _MASK_OFFSET_8((x) >> 8, (n) + 8) |
||
1232 | +#define _MASK_OFFSET_32(x, n) _MASK_OFFSET_16((x), (n)) _MASK_OFFSET_16((x) >> 16, (n) + 16) |
||
1233 | + |
||
1234 | +#define MASK_OFFSET_ERROR (0xFFFFFFFF) |
||
1235 | + |
||
1236 | +#define MASK_OFFSET(x) (_MASK_OFFSET_32(x, 0) MASK_OFFSET_ERROR) |
||
1237 | + |
||
1238 | + |
||
1239 | +// --------------------------------------------------------------------------- |
||
1240 | +// Assertions |
||
1241 | +// --------------------------------------------------------------------------- |
||
1242 | + |
||
1243 | +#ifndef ASSERT |
||
1244 | + #define ASSERT(expr) BUG_ON(!(expr)) |
||
1245 | +#endif |
||
1246 | + |
||
1247 | +#ifndef NOT_IMPLEMENTED |
||
1248 | + #define NOT_IMPLEMENTED() BUG_ON(1) |
||
1249 | +#endif |
||
1250 | + |
||
1251 | +#define STATIC_ASSERT(pred) STATIC_ASSERT_X(pred, __LINE__) |
||
1252 | +#define STATIC_ASSERT_X(pred, line) STATIC_ASSERT_XX(pred, line) |
||
1253 | +#define STATIC_ASSERT_XX(pred, line) \ |
||
1254 | + extern char assertion_failed_at_##line[(pred) ? 1 : -1] |
||
1255 | + |
||
1256 | +// --------------------------------------------------------------------------- |
||
1257 | +// Resolve Compiler Warnings |
||
1258 | +// --------------------------------------------------------------------------- |
||
1259 | + |
||
1260 | +#define NOT_REFERENCED(x) { (x) = (x); } |
||
1261 | + |
||
1262 | + |
||
1263 | +// --------------------------------------------------------------------------- |
||
1264 | +// Utilities |
||
1265 | +// --------------------------------------------------------------------------- |
||
1266 | + |
||
1267 | +#define MAXIMUM(A,B) (((A)>(B))?(A):(B)) |
||
1268 | +#define MINIMUM(A,B) (((A)<(B))?(A):(B)) |
||
1269 | + |
||
1270 | +#define ARY_SIZE(x) (sizeof((x)) / sizeof((x[0]))) |
||
1271 | +#define DVT_DELAYMACRO(u4Num) \ |
||
1272 | +{ \ |
||
1273 | + UINT32 u4Count = 0 ; \ |
||
1274 | + for (u4Count = 0; u4Count < u4Num; u4Count++ ); \ |
||
1275 | +} \ |
||
1276 | + |
||
1277 | +#define A68351B 0 |
||
1278 | +#define B68351B 1 |
||
1279 | +#define B68351D 2 |
||
1280 | +#define B68351E 3 |
||
1281 | +#define UNKNOWN_IC_VERSION 0xFF |
||
1282 | + |
||
1283 | +/* NAND driver */ |
||
1284 | +struct mtk_nand_host_hw { |
||
1285 | + unsigned int nfi_bus_width; /* NFI_BUS_WIDTH */ |
||
1286 | + unsigned int nfi_access_timing; /* NFI_ACCESS_TIMING */ |
||
1287 | + unsigned int nfi_cs_num; /* NFI_CS_NUM */ |
||
1288 | + unsigned int nand_sec_size; /* NAND_SECTOR_SIZE */ |
||
1289 | + unsigned int nand_sec_shift; /* NAND_SECTOR_SHIFT */ |
||
1290 | + unsigned int nand_ecc_size; |
||
1291 | + unsigned int nand_ecc_bytes; |
||
1292 | + unsigned int nand_ecc_mode; |
||
1293 | +}; |
||
1294 | +extern struct mtk_nand_host_hw mt7621_nand_hw; |
||
1295 | +extern unsigned int CFG_BLOCKSIZE; |
||
1296 | + |
||
1297 | +#endif // _MT6575_TYPEDEFS_H |
||
1298 | + |
||
1299 | --- /dev/null |
||
1300 | +++ b/drivers/mtd/nand/mtk_nand2.c |
||
1301 | @@ -0,0 +1,2345 @@ |
||
1302 | +/****************************************************************************** |
||
1303 | +* mtk_nand2.c - MTK NAND Flash Device Driver |
||
1304 | + * |
||
1305 | +* Copyright 2009-2012 MediaTek Co.,Ltd. |
||
1306 | + * |
||
1307 | +* DESCRIPTION: |
||
1308 | +* This file provid the other drivers nand relative functions |
||
1309 | + * |
||
1310 | +* modification history |
||
1311 | +* ---------------------------------------- |
||
1312 | +* v3.0, 11 Feb 2010, mtk |
||
1313 | +* ---------------------------------------- |
||
1314 | +******************************************************************************/ |
||
1315 | +#include "nand_def.h" |
||
1316 | +#include <linux/slab.h> |
||
1317 | +#include <linux/init.h> |
||
1318 | +#include <linux/module.h> |
||
1319 | +#include <linux/delay.h> |
||
1320 | +#include <linux/errno.h> |
||
1321 | +#include <linux/sched.h> |
||
1322 | +#include <linux/types.h> |
||
1323 | +#include <linux/wait.h> |
||
1324 | +#include <linux/spinlock.h> |
||
1325 | +#include <linux/interrupt.h> |
||
1326 | +#include <linux/mtd/mtd.h> |
||
1327 | +#include <linux/mtd/rawnand.h> |
||
1328 | +#include <linux/mtd/partitions.h> |
||
1329 | +#include <linux/mtd/nand_ecc.h> |
||
1330 | +#include <linux/dma-mapping.h> |
||
1331 | +#include <linux/jiffies.h> |
||
1332 | +#include <linux/platform_device.h> |
||
1333 | +#include <linux/proc_fs.h> |
||
1334 | +#include <linux/time.h> |
||
1335 | +#include <linux/mm.h> |
||
1336 | +#include <asm/io.h> |
||
1337 | +#include <asm/cacheflush.h> |
||
1338 | +#include <asm/uaccess.h> |
||
1339 | +#include <linux/miscdevice.h> |
||
1340 | +#include "mtk_nand2.h" |
||
1341 | +#include "nand_device_list.h" |
||
1342 | + |
||
1343 | +#include "bmt.h" |
||
1344 | +#include "partition.h" |
||
1345 | + |
||
1346 | +unsigned int CFG_BLOCKSIZE; |
||
1347 | + |
||
1348 | +static int shift_on_bbt = 0; |
||
1349 | +int mtk_nand_read_oob_hw(struct mtd_info *mtd, struct nand_chip *chip, int page); |
||
1350 | + |
||
1351 | +static const char * const probe_types[] = { "cmdlinepart", "ofpart", NULL }; |
||
1352 | + |
||
1353 | +#define NAND_CMD_STATUS_MULTI 0x71 |
||
1354 | + |
||
1355 | +void show_stack(struct task_struct *tsk, unsigned long *sp); |
||
1356 | +extern void mt_irq_set_sens(unsigned int irq, unsigned int sens); |
||
1357 | +extern void mt_irq_set_polarity(unsigned int irq,unsigned int polarity); |
||
1358 | + |
||
1359 | +struct mtk_nand_host mtk_nand_host; /* include mtd_info and nand_chip structs */ |
||
1360 | +struct mtk_nand_host_hw mt7621_nand_hw = { |
||
1361 | + .nfi_bus_width = 8, |
||
1362 | + .nfi_access_timing = NFI_DEFAULT_ACCESS_TIMING, |
||
1363 | + .nfi_cs_num = NFI_CS_NUM, |
||
1364 | + .nand_sec_size = 512, |
||
1365 | + .nand_sec_shift = 9, |
||
1366 | + .nand_ecc_size = 2048, |
||
1367 | + .nand_ecc_bytes = 32, |
||
1368 | + .nand_ecc_mode = NAND_ECC_HW, |
||
1369 | +}; |
||
1370 | + |
||
1371 | + |
||
1372 | +/******************************************************************************* |
||
1373 | + * Gloable Varible Definition |
||
1374 | + *******************************************************************************/ |
||
1375 | + |
||
1376 | +#define NFI_ISSUE_COMMAND(cmd, col_addr, row_addr, col_num, row_num) \ |
||
1377 | + do { \ |
||
1378 | + DRV_WriteReg(NFI_CMD_REG16,cmd);\ |
||
1379 | + while (DRV_Reg32(NFI_STA_REG32) & STA_CMD_STATE);\ |
||
1380 | + DRV_WriteReg32(NFI_COLADDR_REG32, col_addr);\ |
||
1381 | + DRV_WriteReg32(NFI_ROWADDR_REG32, row_addr);\ |
||
1382 | + DRV_WriteReg(NFI_ADDRNOB_REG16, col_num | (row_num<<ADDR_ROW_NOB_SHIFT));\ |
||
1383 | + while (DRV_Reg32(NFI_STA_REG32) & STA_ADDR_STATE);\ |
||
1384 | + }while(0); |
||
1385 | + |
||
1386 | +//------------------------------------------------------------------------------- |
||
1387 | +static struct NAND_CMD g_kCMD; |
||
1388 | +static u32 g_u4ChipVer; |
||
1389 | +bool g_bInitDone; |
||
1390 | +static bool g_bcmdstatus; |
||
1391 | +static u32 g_value = 0; |
||
1392 | +static int g_page_size; |
||
1393 | + |
||
1394 | +BOOL g_bHwEcc = true; |
||
1395 | + |
||
1396 | + |
||
1397 | +extern void nand_release_device(struct mtd_info *mtd); |
||
1398 | +extern int nand_get_device(struct nand_chip *chip, struct mtd_info *mtd, int new_state); |
||
1399 | + |
||
1400 | +#if defined(MTK_NAND_BMT) |
||
1401 | +static bmt_struct *g_bmt; |
||
1402 | +#endif |
||
1403 | +struct mtk_nand_host *host; |
||
1404 | +extern struct mtd_partition g_pasStatic_Partition[]; |
||
1405 | +int part_num = NUM_PARTITIONS; |
||
1406 | +int manu_id; |
||
1407 | +int dev_id; |
||
1408 | + |
||
1409 | +/* this constant was taken from linux/nand/nand.h v 3.14 |
||
1410 | + * in later versions it seems it was removed in order to save a bit of space |
||
1411 | + */ |
||
1412 | +#define NAND_MAX_OOBSIZE 774 |
||
1413 | +static u8 local_oob_buf[NAND_MAX_OOBSIZE]; |
||
1414 | + |
||
1415 | +static u8 nand_badblock_offset = 0; |
||
1416 | + |
||
1417 | +static void nand_bbt_set(struct mtd_info *mtd, int page, int flag) |
||
1418 | +{ |
||
1419 | + struct nand_chip *this = mtd->priv; |
||
1420 | + int block; |
||
1421 | + |
||
1422 | + block = (int)(page >> (this->bbt_erase_shift - this->page_shift - 1)); |
||
1423 | + this->bbt[block >> 3] &= ~(0x03 << (block & 0x6)); |
||
1424 | + this->bbt[block >> 3] |= (flag & 0x3) << (block & 0x6); |
||
1425 | +} |
||
1426 | + |
||
1427 | +static int nand_bbt_get(struct mtd_info *mtd, int page) |
||
1428 | +{ |
||
1429 | + struct nand_chip *this = mtd->priv; |
||
1430 | + int block; |
||
1431 | + |
||
1432 | + block = (int)(page >> (this->bbt_erase_shift - this->page_shift - 1)); |
||
1433 | + return (this->bbt[block >> 3] >> (block & 0x06)) & 0x03; |
||
1434 | +} |
||
1435 | + |
||
1436 | +void nand_enable_clock(void) |
||
1437 | +{ |
||
1438 | + //enable_clock(MT65XX_PDN_PERI_NFI, "NAND"); |
||
1439 | +} |
||
1440 | + |
||
1441 | +void nand_disable_clock(void) |
||
1442 | +{ |
||
1443 | + //disable_clock(MT65XX_PDN_PERI_NFI, "NAND"); |
||
1444 | +} |
||
1445 | + |
||
1446 | +struct nand_ecclayout { |
||
1447 | + __u32 eccbytes; |
||
1448 | + __u32 eccpos[MTD_MAX_ECCPOS_ENTRIES_LARGE]; |
||
1449 | + __u32 oobavail; |
||
1450 | + struct nand_oobfree oobfree[MTD_MAX_OOBFREE_ENTRIES_LARGE]; |
||
1451 | +}; |
||
1452 | + |
||
1453 | +static struct nand_ecclayout *layout; |
||
1454 | + |
||
1455 | +static struct nand_ecclayout nand_oob_16 = { |
||
1456 | + .eccbytes = 8, |
||
1457 | + .eccpos = {8, 9, 10, 11, 12, 13, 14, 15}, |
||
1458 | + .oobfree = {{1, 6}, {0, 0}} |
||
1459 | +}; |
||
1460 | + |
||
1461 | +struct nand_ecclayout nand_oob_64 = { |
||
1462 | + .eccbytes = 32, |
||
1463 | + .eccpos = {32, 33, 34, 35, 36, 37, 38, 39, |
||
1464 | + 40, 41, 42, 43, 44, 45, 46, 47, |
||
1465 | + 48, 49, 50, 51, 52, 53, 54, 55, |
||
1466 | + 56, 57, 58, 59, 60, 61, 62, 63}, |
||
1467 | + .oobfree = {{1, 7}, {9, 7}, {17, 7}, {25, 6}, {0, 0}} |
||
1468 | +}; |
||
1469 | + |
||
1470 | +struct nand_ecclayout nand_oob_128 = { |
||
1471 | + .eccbytes = 64, |
||
1472 | + .eccpos = { |
||
1473 | + 64, 65, 66, 67, 68, 69, 70, 71, |
||
1474 | + 72, 73, 74, 75, 76, 77, 78, 79, |
||
1475 | + 80, 81, 82, 83, 84, 85, 86, 86, |
||
1476 | + 88, 89, 90, 91, 92, 93, 94, 95, |
||
1477 | + 96, 97, 98, 99, 100, 101, 102, 103, |
||
1478 | + 104, 105, 106, 107, 108, 109, 110, 111, |
||
1479 | + 112, 113, 114, 115, 116, 117, 118, 119, |
||
1480 | + 120, 121, 122, 123, 124, 125, 126, 127}, |
||
1481 | + .oobfree = {{1, 7}, {9, 7}, {17, 7}, {25, 7}, {33, 7}, {41, 7}, {49, 7}, {57, 6}} |
||
1482 | +}; |
||
1483 | + |
||
1484 | +flashdev_info devinfo; |
||
1485 | + |
||
1486 | +void dump_nfi(void) |
||
1487 | +{ |
||
1488 | +} |
||
1489 | + |
||
1490 | +void dump_ecc(void) |
||
1491 | +{ |
||
1492 | +} |
||
1493 | + |
||
1494 | +u32 |
||
1495 | +nand_virt_to_phys_add(u32 va) |
||
1496 | +{ |
||
1497 | + u32 pageOffset = (va & (PAGE_SIZE - 1)); |
||
1498 | + pgd_t *pgd; |
||
1499 | + pmd_t *pmd; |
||
1500 | + pte_t *pte; |
||
1501 | + u32 pa; |
||
1502 | + |
||
1503 | + if (virt_addr_valid(va)) |
||
1504 | + return __virt_to_phys(va); |
||
1505 | + |
||
1506 | + if (NULL == current) { |
||
1507 | + printk(KERN_ERR "[nand_virt_to_phys_add] ERROR ,current is NULL! \n"); |
||
1508 | + return 0; |
||
1509 | + } |
||
1510 | + |
||
1511 | + if (NULL == current->mm) { |
||
1512 | + printk(KERN_ERR "[nand_virt_to_phys_add] ERROR current->mm is NULL! tgid=0x%x, name=%s \n", current->tgid, current->comm); |
||
1513 | + return 0; |
||
1514 | + } |
||
1515 | + |
||
1516 | + pgd = pgd_offset(current->mm, va); /* what is tsk->mm */ |
||
1517 | + if (pgd_none(*pgd) || pgd_bad(*pgd)) { |
||
1518 | + printk(KERN_ERR "[nand_virt_to_phys_add] ERROR, va=0x%x, pgd invalid! \n", va); |
||
1519 | + return 0; |
||
1520 | + } |
||
1521 | + |
||
1522 | + pmd = pmd_offset((pud_t *)pgd, va); |
||
1523 | + if (pmd_none(*pmd) || pmd_bad(*pmd)) { |
||
1524 | + printk(KERN_ERR "[nand_virt_to_phys_add] ERROR, va=0x%x, pmd invalid! \n", va); |
||
1525 | + return 0; |
||
1526 | + } |
||
1527 | + |
||
1528 | + pte = pte_offset_map(pmd, va); |
||
1529 | + if (pte_present(*pte)) { |
||
1530 | + pa = (pte_val(*pte) & (PAGE_MASK)) | pageOffset; |
||
1531 | + return pa; |
||
1532 | + } |
||
1533 | + |
||
1534 | + printk(KERN_ERR "[nand_virt_to_phys_add] ERROR va=0x%x, pte invalid! \n", va); |
||
1535 | + return 0; |
||
1536 | +} |
||
1537 | +EXPORT_SYMBOL(nand_virt_to_phys_add); |
||
1538 | + |
||
1539 | +bool |
||
1540 | +get_device_info(u16 id, u32 ext_id, flashdev_info * pdevinfo) |
||
1541 | +{ |
||
1542 | + u32 index; |
||
1543 | + for (index = 0; gen_FlashTable[index].id != 0; index++) { |
||
1544 | + if (id == gen_FlashTable[index].id && ext_id == gen_FlashTable[index].ext_id) { |
||
1545 | + pdevinfo->id = gen_FlashTable[index].id; |
||
1546 | + pdevinfo->ext_id = gen_FlashTable[index].ext_id; |
||
1547 | + pdevinfo->blocksize = gen_FlashTable[index].blocksize; |
||
1548 | + pdevinfo->addr_cycle = gen_FlashTable[index].addr_cycle; |
||
1549 | + pdevinfo->iowidth = gen_FlashTable[index].iowidth; |
||
1550 | + pdevinfo->timmingsetting = gen_FlashTable[index].timmingsetting; |
||
1551 | + pdevinfo->advancedmode = gen_FlashTable[index].advancedmode; |
||
1552 | + pdevinfo->pagesize = gen_FlashTable[index].pagesize; |
||
1553 | + pdevinfo->sparesize = gen_FlashTable[index].sparesize; |
||
1554 | + pdevinfo->totalsize = gen_FlashTable[index].totalsize; |
||
1555 | + memcpy(pdevinfo->devciename, gen_FlashTable[index].devciename, sizeof(pdevinfo->devciename)); |
||
1556 | + printk(KERN_INFO "Device found in MTK table, ID: %x, EXT_ID: %x\n", id, ext_id); |
||
1557 | + |
||
1558 | + goto find; |
||
1559 | + } |
||
1560 | + } |
||
1561 | + |
||
1562 | +find: |
||
1563 | + if (0 == pdevinfo->id) { |
||
1564 | + printk(KERN_INFO "Device not found, ID: %x\n", id); |
||
1565 | + return false; |
||
1566 | + } else { |
||
1567 | + return true; |
||
1568 | + } |
||
1569 | +} |
||
1570 | + |
||
1571 | +static void |
||
1572 | +ECC_Config(struct mtk_nand_host_hw *hw,u32 ecc_bit) |
||
1573 | +{ |
||
1574 | + u32 u4ENCODESize; |
||
1575 | + u32 u4DECODESize; |
||
1576 | + u32 ecc_bit_cfg = ECC_CNFG_ECC4; |
||
1577 | + |
||
1578 | + switch(ecc_bit){ |
||
1579 | + case 4: |
||
1580 | + ecc_bit_cfg = ECC_CNFG_ECC4; |
||
1581 | + break; |
||
1582 | + case 8: |
||
1583 | + ecc_bit_cfg = ECC_CNFG_ECC8; |
||
1584 | + break; |
||
1585 | + case 10: |
||
1586 | + ecc_bit_cfg = ECC_CNFG_ECC10; |
||
1587 | + break; |
||
1588 | + case 12: |
||
1589 | + ecc_bit_cfg = ECC_CNFG_ECC12; |
||
1590 | + break; |
||
1591 | + default: |
||
1592 | + break; |
||
1593 | + } |
||
1594 | + DRV_WriteReg16(ECC_DECCON_REG16, DEC_DE); |
||
1595 | + do { |
||
1596 | + } while (!DRV_Reg16(ECC_DECIDLE_REG16)); |
||
1597 | + |
||
1598 | + DRV_WriteReg16(ECC_ENCCON_REG16, ENC_DE); |
||
1599 | + do { |
||
1600 | + } while (!DRV_Reg32(ECC_ENCIDLE_REG32)); |
||
1601 | + |
||
1602 | + /* setup FDM register base */ |
||
1603 | + DRV_WriteReg32(ECC_FDMADDR_REG32, NFI_FDM0L_REG32); |
||
1604 | + |
||
1605 | + /* Sector + FDM */ |
||
1606 | + u4ENCODESize = (hw->nand_sec_size + 8) << 3; |
||
1607 | + /* Sector + FDM + YAFFS2 meta data bits */ |
||
1608 | + u4DECODESize = ((hw->nand_sec_size + 8) << 3) + ecc_bit * 13; |
||
1609 | + |
||
1610 | + /* configure ECC decoder && encoder */ |
||
1611 | + DRV_WriteReg32(ECC_DECCNFG_REG32, ecc_bit_cfg | DEC_CNFG_NFI | DEC_CNFG_EMPTY_EN | (u4DECODESize << DEC_CNFG_CODE_SHIFT)); |
||
1612 | + |
||
1613 | + DRV_WriteReg32(ECC_ENCCNFG_REG32, ecc_bit_cfg | ENC_CNFG_NFI | (u4ENCODESize << ENC_CNFG_MSG_SHIFT)); |
||
1614 | + NFI_SET_REG32(ECC_DECCNFG_REG32, DEC_CNFG_EL); |
||
1615 | +} |
||
1616 | + |
||
1617 | +static void |
||
1618 | +ECC_Decode_Start(void) |
||
1619 | +{ |
||
1620 | + while (!(DRV_Reg16(ECC_DECIDLE_REG16) & DEC_IDLE)) |
||
1621 | + ; |
||
1622 | + DRV_WriteReg16(ECC_DECCON_REG16, DEC_EN); |
||
1623 | +} |
||
1624 | + |
||
1625 | +static void |
||
1626 | +ECC_Decode_End(void) |
||
1627 | +{ |
||
1628 | + while (!(DRV_Reg16(ECC_DECIDLE_REG16) & DEC_IDLE)) |
||
1629 | + ; |
||
1630 | + DRV_WriteReg16(ECC_DECCON_REG16, DEC_DE); |
||
1631 | +} |
||
1632 | + |
||
1633 | +static void |
||
1634 | +ECC_Encode_Start(void) |
||
1635 | +{ |
||
1636 | + while (!(DRV_Reg32(ECC_ENCIDLE_REG32) & ENC_IDLE)) |
||
1637 | + ; |
||
1638 | + mb(); |
||
1639 | + DRV_WriteReg16(ECC_ENCCON_REG16, ENC_EN); |
||
1640 | +} |
||
1641 | + |
||
1642 | +static void |
||
1643 | +ECC_Encode_End(void) |
||
1644 | +{ |
||
1645 | + /* wait for device returning idle */ |
||
1646 | + while (!(DRV_Reg32(ECC_ENCIDLE_REG32) & ENC_IDLE)) ; |
||
1647 | + mb(); |
||
1648 | + DRV_WriteReg16(ECC_ENCCON_REG16, ENC_DE); |
||
1649 | +} |
||
1650 | + |
||
1651 | +static bool |
||
1652 | +mtk_nand_check_bch_error(struct mtd_info *mtd, u8 * pDataBuf, u32 u4SecIndex, u32 u4PageAddr) |
||
1653 | +{ |
||
1654 | + bool bRet = true; |
||
1655 | + u16 u2SectorDoneMask = 1 << u4SecIndex; |
||
1656 | + u32 u4ErrorNumDebug, i, u4ErrNum; |
||
1657 | + u32 timeout = 0xFFFF; |
||
1658 | + // int el; |
||
1659 | + u32 au4ErrBitLoc[6]; |
||
1660 | + u32 u4ErrByteLoc, u4BitOffset; |
||
1661 | + u32 u4ErrBitLoc1th, u4ErrBitLoc2nd; |
||
1662 | + |
||
1663 | + //4 // Wait for Decode Done |
||
1664 | + while (0 == (u2SectorDoneMask & DRV_Reg16(ECC_DECDONE_REG16))) { |
||
1665 | + timeout--; |
||
1666 | + if (0 == timeout) |
||
1667 | + return false; |
||
1668 | + } |
||
1669 | + /* We will manually correct the error bits in the last sector, not all the sectors of the page! */ |
||
1670 | + memset(au4ErrBitLoc, 0x0, sizeof(au4ErrBitLoc)); |
||
1671 | + u4ErrorNumDebug = DRV_Reg32(ECC_DECENUM_REG32); |
||
1672 | + u4ErrNum = DRV_Reg32(ECC_DECENUM_REG32) >> (u4SecIndex << 2); |
||
1673 | + u4ErrNum &= 0xF; |
||
1674 | + |
||
1675 | + if (u4ErrNum) { |
||
1676 | + if (0xF == u4ErrNum) { |
||
1677 | + mtd->ecc_stats.failed++; |
||
1678 | + bRet = false; |
||
1679 | + printk(KERN_ERR"mtk_nand: UnCorrectable at PageAddr=%d\n", u4PageAddr); |
||
1680 | + } else { |
||
1681 | + for (i = 0; i < ((u4ErrNum + 1) >> 1); ++i) { |
||
1682 | + au4ErrBitLoc[i] = DRV_Reg32(ECC_DECEL0_REG32 + i); |
||
1683 | + u4ErrBitLoc1th = au4ErrBitLoc[i] & 0x1FFF; |
||
1684 | + if (u4ErrBitLoc1th < 0x1000) { |
||
1685 | + u4ErrByteLoc = u4ErrBitLoc1th / 8; |
||
1686 | + u4BitOffset = u4ErrBitLoc1th % 8; |
||
1687 | + pDataBuf[u4ErrByteLoc] = pDataBuf[u4ErrByteLoc] ^ (1 << u4BitOffset); |
||
1688 | + mtd->ecc_stats.corrected++; |
||
1689 | + } else { |
||
1690 | + mtd->ecc_stats.failed++; |
||
1691 | + } |
||
1692 | + u4ErrBitLoc2nd = (au4ErrBitLoc[i] >> 16) & 0x1FFF; |
||
1693 | + if (0 != u4ErrBitLoc2nd) { |
||
1694 | + if (u4ErrBitLoc2nd < 0x1000) { |
||
1695 | + u4ErrByteLoc = u4ErrBitLoc2nd / 8; |
||
1696 | + u4BitOffset = u4ErrBitLoc2nd % 8; |
||
1697 | + pDataBuf[u4ErrByteLoc] = pDataBuf[u4ErrByteLoc] ^ (1 << u4BitOffset); |
||
1698 | + mtd->ecc_stats.corrected++; |
||
1699 | + } else { |
||
1700 | + mtd->ecc_stats.failed++; |
||
1701 | + //printk(KERN_ERR"UnCorrectable High ErrLoc=%d\n", au4ErrBitLoc[i]); |
||
1702 | + } |
||
1703 | + } |
||
1704 | + } |
||
1705 | + } |
||
1706 | + if (0 == (DRV_Reg16(ECC_DECFER_REG16) & (1 << u4SecIndex))) |
||
1707 | + bRet = false; |
||
1708 | + } |
||
1709 | + return bRet; |
||
1710 | +} |
||
1711 | + |
||
1712 | +static bool |
||
1713 | +mtk_nand_RFIFOValidSize(u16 u2Size) |
||
1714 | +{ |
||
1715 | + u32 timeout = 0xFFFF; |
||
1716 | + while (FIFO_RD_REMAIN(DRV_Reg16(NFI_FIFOSTA_REG16)) < u2Size) { |
||
1717 | + timeout--; |
||
1718 | + if (0 == timeout) |
||
1719 | + return false; |
||
1720 | + } |
||
1721 | + return true; |
||
1722 | +} |
||
1723 | + |
||
1724 | +static bool |
||
1725 | +mtk_nand_WFIFOValidSize(u16 u2Size) |
||
1726 | +{ |
||
1727 | + u32 timeout = 0xFFFF; |
||
1728 | + |
||
1729 | + while (FIFO_WR_REMAIN(DRV_Reg16(NFI_FIFOSTA_REG16)) > u2Size) { |
||
1730 | + timeout--; |
||
1731 | + if (0 == timeout) |
||
1732 | + return false; |
||
1733 | + } |
||
1734 | + return true; |
||
1735 | +} |
||
1736 | + |
||
1737 | +static bool |
||
1738 | +mtk_nand_status_ready(u32 u4Status) |
||
1739 | +{ |
||
1740 | + u32 timeout = 0xFFFF; |
||
1741 | + |
||
1742 | + while ((DRV_Reg32(NFI_STA_REG32) & u4Status) != 0) { |
||
1743 | + timeout--; |
||
1744 | + if (0 == timeout) |
||
1745 | + return false; |
||
1746 | + } |
||
1747 | + return true; |
||
1748 | +} |
||
1749 | + |
||
1750 | +static bool |
||
1751 | +mtk_nand_reset(void) |
||
1752 | +{ |
||
1753 | + int timeout = 0xFFFF; |
||
1754 | + if (DRV_Reg16(NFI_MASTERSTA_REG16)) { |
||
1755 | + mb(); |
||
1756 | + DRV_WriteReg16(NFI_CON_REG16, CON_FIFO_FLUSH | CON_NFI_RST); |
||
1757 | + while (DRV_Reg16(NFI_MASTERSTA_REG16)) { |
||
1758 | + timeout--; |
||
1759 | + if (!timeout) |
||
1760 | + MSG(INIT, "Wait for NFI_MASTERSTA timeout\n"); |
||
1761 | + } |
||
1762 | + } |
||
1763 | + /* issue reset operation */ |
||
1764 | + mb(); |
||
1765 | + DRV_WriteReg16(NFI_CON_REG16, CON_FIFO_FLUSH | CON_NFI_RST); |
||
1766 | + |
||
1767 | + return mtk_nand_status_ready(STA_NFI_FSM_MASK | STA_NAND_BUSY) && mtk_nand_RFIFOValidSize(0) && mtk_nand_WFIFOValidSize(0); |
||
1768 | +} |
||
1769 | + |
||
1770 | +static void |
||
1771 | +mtk_nand_set_mode(u16 u2OpMode) |
||
1772 | +{ |
||
1773 | + u16 u2Mode = DRV_Reg16(NFI_CNFG_REG16); |
||
1774 | + u2Mode &= ~CNFG_OP_MODE_MASK; |
||
1775 | + u2Mode |= u2OpMode; |
||
1776 | + DRV_WriteReg16(NFI_CNFG_REG16, u2Mode); |
||
1777 | +} |
||
1778 | + |
||
1779 | +static void |
||
1780 | +mtk_nand_set_autoformat(bool bEnable) |
||
1781 | +{ |
||
1782 | + if (bEnable) |
||
1783 | + NFI_SET_REG16(NFI_CNFG_REG16, CNFG_AUTO_FMT_EN); |
||
1784 | + else |
||
1785 | + NFI_CLN_REG16(NFI_CNFG_REG16, CNFG_AUTO_FMT_EN); |
||
1786 | +} |
||
1787 | + |
||
1788 | +static void |
||
1789 | +mtk_nand_configure_fdm(u16 u2FDMSize) |
||
1790 | +{ |
||
1791 | + NFI_CLN_REG16(NFI_PAGEFMT_REG16, PAGEFMT_FDM_MASK | PAGEFMT_FDM_ECC_MASK); |
||
1792 | + NFI_SET_REG16(NFI_PAGEFMT_REG16, u2FDMSize << PAGEFMT_FDM_SHIFT); |
||
1793 | + NFI_SET_REG16(NFI_PAGEFMT_REG16, u2FDMSize << PAGEFMT_FDM_ECC_SHIFT); |
||
1794 | +} |
||
1795 | + |
||
1796 | +static void |
||
1797 | +mtk_nand_configure_lock(void) |
||
1798 | +{ |
||
1799 | + u32 u4WriteColNOB = 2; |
||
1800 | + u32 u4WriteRowNOB = 3; |
||
1801 | + u32 u4EraseColNOB = 0; |
||
1802 | + u32 u4EraseRowNOB = 3; |
||
1803 | + DRV_WriteReg16(NFI_LOCKANOB_REG16, |
||
1804 | + (u4WriteColNOB << PROG_CADD_NOB_SHIFT) | (u4WriteRowNOB << PROG_RADD_NOB_SHIFT) | (u4EraseColNOB << ERASE_CADD_NOB_SHIFT) | (u4EraseRowNOB << ERASE_RADD_NOB_SHIFT)); |
||
1805 | + |
||
1806 | + if (CHIPVER_ECO_1 == g_u4ChipVer) { |
||
1807 | + int i; |
||
1808 | + for (i = 0; i < 16; ++i) { |
||
1809 | + DRV_WriteReg32(NFI_LOCK00ADD_REG32 + (i << 1), 0xFFFFFFFF); |
||
1810 | + DRV_WriteReg32(NFI_LOCK00FMT_REG32 + (i << 1), 0xFFFFFFFF); |
||
1811 | + } |
||
1812 | + //DRV_WriteReg16(NFI_LOCKANOB_REG16, 0x0); |
||
1813 | + DRV_WriteReg32(NFI_LOCKCON_REG32, 0xFFFFFFFF); |
||
1814 | + DRV_WriteReg16(NFI_LOCK_REG16, NFI_LOCK_ON); |
||
1815 | + } |
||
1816 | +} |
||
1817 | + |
||
1818 | +static bool |
||
1819 | +mtk_nand_pio_ready(void) |
||
1820 | +{ |
||
1821 | + int count = 0; |
||
1822 | + while (!(DRV_Reg16(NFI_PIO_DIRDY_REG16) & 1)) { |
||
1823 | + count++; |
||
1824 | + if (count > 0xffff) { |
||
1825 | + printk("PIO_DIRDY timeout\n"); |
||
1826 | + return false; |
||
1827 | + } |
||
1828 | + } |
||
1829 | + |
||
1830 | + return true; |
||
1831 | +} |
||
1832 | + |
||
1833 | +static bool |
||
1834 | +mtk_nand_set_command(u16 command) |
||
1835 | +{ |
||
1836 | + mb(); |
||
1837 | + DRV_WriteReg16(NFI_CMD_REG16, command); |
||
1838 | + return mtk_nand_status_ready(STA_CMD_STATE); |
||
1839 | +} |
||
1840 | + |
||
1841 | +static bool |
||
1842 | +mtk_nand_set_address(u32 u4ColAddr, u32 u4RowAddr, u16 u2ColNOB, u16 u2RowNOB) |
||
1843 | +{ |
||
1844 | + mb(); |
||
1845 | + DRV_WriteReg32(NFI_COLADDR_REG32, u4ColAddr); |
||
1846 | + DRV_WriteReg32(NFI_ROWADDR_REG32, u4RowAddr); |
||
1847 | + DRV_WriteReg16(NFI_ADDRNOB_REG16, u2ColNOB | (u2RowNOB << ADDR_ROW_NOB_SHIFT)); |
||
1848 | + return mtk_nand_status_ready(STA_ADDR_STATE); |
||
1849 | +} |
||
1850 | + |
||
1851 | +static void mtk_nfc_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl) |
||
1852 | +{ |
||
1853 | + if (ctrl & NAND_ALE) { |
||
1854 | + mtk_nand_set_address(dat, 0, 1, 0); |
||
1855 | + } else if (ctrl & NAND_CLE) { |
||
1856 | + mtk_nand_reset(); |
||
1857 | + mtk_nand_set_mode(0x6000); |
||
1858 | + mtk_nand_set_command(dat); |
||
1859 | + } |
||
1860 | +} |
||
1861 | + |
||
1862 | +static bool |
||
1863 | +mtk_nand_check_RW_count(u16 u2WriteSize) |
||
1864 | +{ |
||
1865 | + u32 timeout = 0xFFFF; |
||
1866 | + u16 u2SecNum = u2WriteSize >> 9; |
||
1867 | + |
||
1868 | + while (ADDRCNTR_CNTR(DRV_Reg16(NFI_ADDRCNTR_REG16)) < u2SecNum) { |
||
1869 | + timeout--; |
||
1870 | + if (0 == timeout) { |
||
1871 | + printk(KERN_INFO "[%s] timeout\n", __FUNCTION__); |
||
1872 | + return false; |
||
1873 | + } |
||
1874 | + } |
||
1875 | + return true; |
||
1876 | +} |
||
1877 | + |
||
1878 | +static bool |
||
1879 | +mtk_nand_ready_for_read(struct nand_chip *nand, u32 u4RowAddr, u32 u4ColAddr, bool full, u8 * buf) |
||
1880 | +{ |
||
1881 | + /* Reset NFI HW internal state machine and flush NFI in/out FIFO */ |
||
1882 | + bool bRet = false; |
||
1883 | + u16 sec_num = 1 << (nand->page_shift - 9); |
||
1884 | + u32 col_addr = u4ColAddr; |
||
1885 | + u32 colnob = 2, rownob = devinfo.addr_cycle - 2; |
||
1886 | + if (nand->options & NAND_BUSWIDTH_16) |
||
1887 | + col_addr /= 2; |
||
1888 | + |
||
1889 | + if (!mtk_nand_reset()) |
||
1890 | + goto cleanup; |
||
1891 | + if (g_bHwEcc) { |
||
1892 | + NFI_SET_REG16(NFI_CNFG_REG16, CNFG_HW_ECC_EN); |
||
1893 | + } else { |
||
1894 | + NFI_CLN_REG16(NFI_CNFG_REG16, CNFG_HW_ECC_EN); |
||
1895 | + } |
||
1896 | + |
||
1897 | + mtk_nand_set_mode(CNFG_OP_READ); |
||
1898 | + NFI_SET_REG16(NFI_CNFG_REG16, CNFG_READ_EN); |
||
1899 | + DRV_WriteReg16(NFI_CON_REG16, sec_num << CON_NFI_SEC_SHIFT); |
||
1900 | + |
||
1901 | + if (full) { |
||
1902 | + NFI_CLN_REG16(NFI_CNFG_REG16, CNFG_AHB); |
||
1903 | + |
||
1904 | + if (g_bHwEcc) |
||
1905 | + NFI_SET_REG16(NFI_CNFG_REG16, CNFG_HW_ECC_EN); |
||
1906 | + else |
||
1907 | + NFI_CLN_REG16(NFI_CNFG_REG16, CNFG_HW_ECC_EN); |
||
1908 | + } else { |
||
1909 | + NFI_CLN_REG16(NFI_CNFG_REG16, CNFG_HW_ECC_EN); |
||
1910 | + NFI_CLN_REG16(NFI_CNFG_REG16, CNFG_AHB); |
||
1911 | + } |
||
1912 | + |
||
1913 | + mtk_nand_set_autoformat(full); |
||
1914 | + if (full) |
||
1915 | + if (g_bHwEcc) |
||
1916 | + ECC_Decode_Start(); |
||
1917 | + if (!mtk_nand_set_command(NAND_CMD_READ0)) |
||
1918 | + goto cleanup; |
||
1919 | + if (!mtk_nand_set_address(col_addr, u4RowAddr, colnob, rownob)) |
||
1920 | + goto cleanup; |
||
1921 | + if (!mtk_nand_set_command(NAND_CMD_READSTART)) |
||
1922 | + goto cleanup; |
||
1923 | + if (!mtk_nand_status_ready(STA_NAND_BUSY)) |
||
1924 | + goto cleanup; |
||
1925 | + |
||
1926 | + bRet = true; |
||
1927 | + |
||
1928 | +cleanup: |
||
1929 | + return bRet; |
||
1930 | +} |
||
1931 | + |
||
1932 | +static bool |
||
1933 | +mtk_nand_ready_for_write(struct nand_chip *nand, u32 u4RowAddr, u32 col_addr, bool full, u8 * buf) |
||
1934 | +{ |
||
1935 | + bool bRet = false; |
||
1936 | + u32 sec_num = 1 << (nand->page_shift - 9); |
||
1937 | + u32 colnob = 2, rownob = devinfo.addr_cycle - 2; |
||
1938 | + if (nand->options & NAND_BUSWIDTH_16) |
||
1939 | + col_addr /= 2; |
||
1940 | + |
||
1941 | + /* Reset NFI HW internal state machine and flush NFI in/out FIFO */ |
||
1942 | + if (!mtk_nand_reset()) |
||
1943 | + return false; |
||
1944 | + |
||
1945 | + mtk_nand_set_mode(CNFG_OP_PRGM); |
||
1946 | + |
||
1947 | + NFI_CLN_REG16(NFI_CNFG_REG16, CNFG_READ_EN); |
||
1948 | + |
||
1949 | + DRV_WriteReg16(NFI_CON_REG16, sec_num << CON_NFI_SEC_SHIFT); |
||
1950 | + |
||
1951 | + if (full) { |
||
1952 | + NFI_CLN_REG16(NFI_CNFG_REG16, CNFG_AHB); |
||
1953 | + if (g_bHwEcc) |
||
1954 | + NFI_SET_REG16(NFI_CNFG_REG16, CNFG_HW_ECC_EN); |
||
1955 | + else |
||
1956 | + NFI_CLN_REG16(NFI_CNFG_REG16, CNFG_HW_ECC_EN); |
||
1957 | + } else { |
||
1958 | + NFI_CLN_REG16(NFI_CNFG_REG16, CNFG_HW_ECC_EN); |
||
1959 | + NFI_CLN_REG16(NFI_CNFG_REG16, CNFG_AHB); |
||
1960 | + } |
||
1961 | + |
||
1962 | + mtk_nand_set_autoformat(full); |
||
1963 | + |
||
1964 | + if (full) |
||
1965 | + if (g_bHwEcc) |
||
1966 | + ECC_Encode_Start(); |
||
1967 | + |
||
1968 | + if (!mtk_nand_set_command(NAND_CMD_SEQIN)) |
||
1969 | + goto cleanup; |
||
1970 | + //1 FIXED ME: For Any Kind of AddrCycle |
||
1971 | + if (!mtk_nand_set_address(col_addr, u4RowAddr, colnob, rownob)) |
||
1972 | + goto cleanup; |
||
1973 | + |
||
1974 | + if (!mtk_nand_status_ready(STA_NAND_BUSY)) |
||
1975 | + goto cleanup; |
||
1976 | + |
||
1977 | + bRet = true; |
||
1978 | + |
||
1979 | +cleanup: |
||
1980 | + return bRet; |
||
1981 | +} |
||
1982 | + |
||
1983 | +static bool |
||
1984 | +mtk_nand_check_dececc_done(u32 u4SecNum) |
||
1985 | +{ |
||
1986 | + u32 timeout, dec_mask; |
||
1987 | + |
||
1988 | + timeout = 0xffff; |
||
1989 | + dec_mask = (1 << u4SecNum) - 1; |
||
1990 | + while ((dec_mask != DRV_Reg(ECC_DECDONE_REG16)) && timeout > 0) |
||
1991 | + timeout--; |
||
1992 | + if (timeout == 0) { |
||
1993 | + MSG(VERIFY, "ECC_DECDONE: timeout\n"); |
||
1994 | + return false; |
||
1995 | + } |
||
1996 | + return true; |
||
1997 | +} |
||
1998 | + |
||
1999 | +static bool |
||
2000 | +mtk_nand_mcu_read_data(u8 * buf, u32 length) |
||
2001 | +{ |
||
2002 | + int timeout = 0xffff; |
||
2003 | + u32 i; |
||
2004 | + u32 *buf32 = (u32 *) buf; |
||
2005 | + if ((u32) buf % 4 || length % 4) |
||
2006 | + NFI_SET_REG16(NFI_CNFG_REG16, CNFG_BYTE_RW); |
||
2007 | + else |
||
2008 | + NFI_CLN_REG16(NFI_CNFG_REG16, CNFG_BYTE_RW); |
||
2009 | + |
||
2010 | + //DRV_WriteReg32(NFI_STRADDR_REG32, 0); |
||
2011 | + mb(); |
||
2012 | + NFI_SET_REG16(NFI_CON_REG16, CON_NFI_BRD); |
||
2013 | + |
||
2014 | + if ((u32) buf % 4 || length % 4) { |
||
2015 | + for (i = 0; (i < (length)) && (timeout > 0);) { |
||
2016 | + if (DRV_Reg16(NFI_PIO_DIRDY_REG16) & 1) { |
||
2017 | + *buf++ = (u8) DRV_Reg32(NFI_DATAR_REG32); |
||
2018 | + i++; |
||
2019 | + } else { |
||
2020 | + timeout--; |
||
2021 | + } |
||
2022 | + if (0 == timeout) { |
||
2023 | + printk(KERN_ERR "[%s] timeout\n", __FUNCTION__); |
||
2024 | + dump_nfi(); |
||
2025 | + return false; |
||
2026 | + } |
||
2027 | + } |
||
2028 | + } else { |
||
2029 | + for (i = 0; (i < (length >> 2)) && (timeout > 0);) { |
||
2030 | + if (DRV_Reg16(NFI_PIO_DIRDY_REG16) & 1) { |
||
2031 | + *buf32++ = DRV_Reg32(NFI_DATAR_REG32); |
||
2032 | + i++; |
||
2033 | + } else { |
||
2034 | + timeout--; |
||
2035 | + } |
||
2036 | + if (0 == timeout) { |
||
2037 | + printk(KERN_ERR "[%s] timeout\n", __FUNCTION__); |
||
2038 | + dump_nfi(); |
||
2039 | + return false; |
||
2040 | + } |
||
2041 | + } |
||
2042 | + } |
||
2043 | + return true; |
||
2044 | +} |
||
2045 | + |
||
2046 | +static bool |
||
2047 | +mtk_nand_read_page_data(struct mtd_info *mtd, u8 * pDataBuf, u32 u4Size) |
||
2048 | +{ |
||
2049 | + return mtk_nand_mcu_read_data(pDataBuf, u4Size); |
||
2050 | +} |
||
2051 | + |
||
2052 | +static bool |
||
2053 | +mtk_nand_mcu_write_data(struct mtd_info *mtd, const u8 * buf, u32 length) |
||
2054 | +{ |
||
2055 | + u32 timeout = 0xFFFF; |
||
2056 | + u32 i; |
||
2057 | + u32 *pBuf32; |
||
2058 | + NFI_CLN_REG16(NFI_CNFG_REG16, CNFG_BYTE_RW); |
||
2059 | + mb(); |
||
2060 | + NFI_SET_REG16(NFI_CON_REG16, CON_NFI_BWR); |
||
2061 | + pBuf32 = (u32 *) buf; |
||
2062 | + |
||
2063 | + if ((u32) buf % 4 || length % 4) |
||
2064 | + NFI_SET_REG16(NFI_CNFG_REG16, CNFG_BYTE_RW); |
||
2065 | + else |
||
2066 | + NFI_CLN_REG16(NFI_CNFG_REG16, CNFG_BYTE_RW); |
||
2067 | + |
||
2068 | + if ((u32) buf % 4 || length % 4) { |
||
2069 | + for (i = 0; (i < (length)) && (timeout > 0);) { |
||
2070 | + if (DRV_Reg16(NFI_PIO_DIRDY_REG16) & 1) { |
||
2071 | + DRV_WriteReg32(NFI_DATAW_REG32, *buf++); |
||
2072 | + i++; |
||
2073 | + } else { |
||
2074 | + timeout--; |
||
2075 | + } |
||
2076 | + if (0 == timeout) { |
||
2077 | + printk(KERN_ERR "[%s] timeout\n", __FUNCTION__); |
||
2078 | + dump_nfi(); |
||
2079 | + return false; |
||
2080 | + } |
||
2081 | + } |
||
2082 | + } else { |
||
2083 | + for (i = 0; (i < (length >> 2)) && (timeout > 0);) { |
||
2084 | + if (DRV_Reg16(NFI_PIO_DIRDY_REG16) & 1) { |
||
2085 | + DRV_WriteReg32(NFI_DATAW_REG32, *pBuf32++); |
||
2086 | + i++; |
||
2087 | + } else { |
||
2088 | + timeout--; |
||
2089 | + } |
||
2090 | + if (0 == timeout) { |
||
2091 | + printk(KERN_ERR "[%s] timeout\n", __FUNCTION__); |
||
2092 | + dump_nfi(); |
||
2093 | + return false; |
||
2094 | + } |
||
2095 | + } |
||
2096 | + } |
||
2097 | + |
||
2098 | + return true; |
||
2099 | +} |
||
2100 | + |
||
2101 | +static bool |
||
2102 | +mtk_nand_write_page_data(struct mtd_info *mtd, u8 * buf, u32 size) |
||
2103 | +{ |
||
2104 | + return mtk_nand_mcu_write_data(mtd, buf, size); |
||
2105 | +} |
||
2106 | + |
||
2107 | +static void |
||
2108 | +mtk_nand_read_fdm_data(u8 * pDataBuf, u32 u4SecNum) |
||
2109 | +{ |
||
2110 | + u32 i; |
||
2111 | + u32 *pBuf32 = (u32 *) pDataBuf; |
||
2112 | + |
||
2113 | + if (pBuf32) { |
||
2114 | + for (i = 0; i < u4SecNum; ++i) { |
||
2115 | + *pBuf32++ = DRV_Reg32(NFI_FDM0L_REG32 + (i << 1)); |
||
2116 | + *pBuf32++ = DRV_Reg32(NFI_FDM0M_REG32 + (i << 1)); |
||
2117 | + } |
||
2118 | + } |
||
2119 | +} |
||
2120 | + |
||
2121 | +static u8 fdm_buf[64]; |
||
2122 | +static void |
||
2123 | +mtk_nand_write_fdm_data(struct nand_chip *chip, u8 * pDataBuf, u32 u4SecNum) |
||
2124 | +{ |
||
2125 | + u32 i, j; |
||
2126 | + u8 checksum = 0; |
||
2127 | + bool empty = true; |
||
2128 | + struct nand_oobfree *free_entry; |
||
2129 | + u32 *pBuf32; |
||
2130 | + |
||
2131 | + memcpy(fdm_buf, pDataBuf, u4SecNum * 8); |
||
2132 | + |
||
2133 | + free_entry = layout->oobfree; |
||
2134 | + for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free_entry[i].length; i++) { |
||
2135 | + for (j = 0; j < free_entry[i].length; j++) { |
||
2136 | + if (pDataBuf[free_entry[i].offset + j] != 0xFF) |
||
2137 | + empty = false; |
||
2138 | + checksum ^= pDataBuf[free_entry[i].offset + j]; |
||
2139 | + } |
||
2140 | + } |
||
2141 | + |
||
2142 | + if (!empty) { |
||
2143 | + fdm_buf[free_entry[i - 1].offset + free_entry[i - 1].length] = checksum; |
||
2144 | + } |
||
2145 | + |
||
2146 | + pBuf32 = (u32 *) fdm_buf; |
||
2147 | + for (i = 0; i < u4SecNum; ++i) { |
||
2148 | + DRV_WriteReg32(NFI_FDM0L_REG32 + (i << 1), *pBuf32++); |
||
2149 | + DRV_WriteReg32(NFI_FDM0M_REG32 + (i << 1), *pBuf32++); |
||
2150 | + } |
||
2151 | +} |
||
2152 | + |
||
2153 | +static void |
||
2154 | +mtk_nand_stop_read(void) |
||
2155 | +{ |
||
2156 | + NFI_CLN_REG16(NFI_CON_REG16, CON_NFI_BRD); |
||
2157 | + mtk_nand_reset(); |
||
2158 | + if (g_bHwEcc) |
||
2159 | + ECC_Decode_End(); |
||
2160 | + DRV_WriteReg16(NFI_INTR_EN_REG16, 0); |
||
2161 | +} |
||
2162 | + |
||
2163 | +static void |
||
2164 | +mtk_nand_stop_write(void) |
||
2165 | +{ |
||
2166 | + NFI_CLN_REG16(NFI_CON_REG16, CON_NFI_BWR); |
||
2167 | + if (g_bHwEcc) |
||
2168 | + ECC_Encode_End(); |
||
2169 | + DRV_WriteReg16(NFI_INTR_EN_REG16, 0); |
||
2170 | +} |
||
2171 | + |
||
2172 | +bool |
||
2173 | +mtk_nand_exec_read_page(struct mtd_info *mtd, u32 u4RowAddr, u32 u4PageSize, u8 * pPageBuf, u8 * pFDMBuf) |
||
2174 | +{ |
||
2175 | + u8 *buf; |
||
2176 | + bool bRet = true; |
||
2177 | + struct nand_chip *nand = mtd->priv; |
||
2178 | + u32 u4SecNum = u4PageSize >> 9; |
||
2179 | + |
||
2180 | + buf = pPageBuf; |
||
2181 | + if (mtk_nand_ready_for_read(nand, u4RowAddr, 0, true, buf)) { |
||
2182 | + int j; |
||
2183 | + for (j = 0 ; j < u4SecNum; j++) { |
||
2184 | + if (!mtk_nand_read_page_data(mtd, buf+j*512, 512)) |
||
2185 | + bRet = false; |
||
2186 | + if(g_bHwEcc && !mtk_nand_check_dececc_done(j+1)) |
||
2187 | + bRet = false; |
||
2188 | + if(g_bHwEcc && !mtk_nand_check_bch_error(mtd, buf+j*512, j, u4RowAddr)) |
||
2189 | + bRet = false; |
||
2190 | + } |
||
2191 | + if (!mtk_nand_status_ready(STA_NAND_BUSY)) |
||
2192 | + bRet = false; |
||
2193 | + |
||
2194 | + mtk_nand_read_fdm_data(pFDMBuf, u4SecNum); |
||
2195 | + mtk_nand_stop_read(); |
||
2196 | + } |
||
2197 | + |
||
2198 | + return bRet; |
||
2199 | +} |
||
2200 | + |
||
2201 | +int |
||
2202 | +mtk_nand_exec_write_page(struct mtd_info *mtd, u32 u4RowAddr, u32 u4PageSize, u8 * pPageBuf, u8 * pFDMBuf) |
||
2203 | +{ |
||
2204 | + struct nand_chip *chip = mtd->priv; |
||
2205 | + u32 u4SecNum = u4PageSize >> 9; |
||
2206 | + u8 *buf; |
||
2207 | + u8 status; |
||
2208 | + |
||
2209 | + MSG(WRITE, "mtk_nand_exec_write_page, page: 0x%x\n", u4RowAddr); |
||
2210 | + |
||
2211 | + buf = pPageBuf; |
||
2212 | + |
||
2213 | + if (mtk_nand_ready_for_write(chip, u4RowAddr, 0, true, buf)) { |
||
2214 | + mtk_nand_write_fdm_data(chip, pFDMBuf, u4SecNum); |
||
2215 | + (void)mtk_nand_write_page_data(mtd, buf, u4PageSize); |
||
2216 | + (void)mtk_nand_check_RW_count(u4PageSize); |
||
2217 | + mtk_nand_stop_write(); |
||
2218 | + (void)mtk_nand_set_command(NAND_CMD_PAGEPROG); |
||
2219 | + while (DRV_Reg32(NFI_STA_REG32) & STA_NAND_BUSY) ; |
||
2220 | + } |
||
2221 | + |
||
2222 | + status = chip->waitfunc(mtd, chip); |
||
2223 | + if (status & NAND_STATUS_FAIL) |
||
2224 | + return -EIO; |
||
2225 | + return 0; |
||
2226 | +} |
||
2227 | + |
||
2228 | +static int |
||
2229 | +get_start_end_block(struct mtd_info *mtd, int block, int *start_blk, int *end_blk) |
||
2230 | +{ |
||
2231 | + struct nand_chip *chip = mtd->priv; |
||
2232 | + int i; |
||
2233 | + |
||
2234 | + *start_blk = 0; |
||
2235 | + for (i = 0; i <= part_num; i++) |
||
2236 | + { |
||
2237 | + if (i == part_num) |
||
2238 | + { |
||
2239 | + // try the last reset partition |
||
2240 | + *end_blk = (chip->chipsize >> chip->phys_erase_shift) - 1; |
||
2241 | + if (*start_blk <= *end_blk) |
||
2242 | + { |
||
2243 | + if ((block >= *start_blk) && (block <= *end_blk)) |
||
2244 | + break; |
||
2245 | + } |
||
2246 | + } |
||
2247 | + // skip All partition entry |
||
2248 | + else if (g_pasStatic_Partition[i].size == MTDPART_SIZ_FULL) |
||
2249 | + { |
||
2250 | + continue; |
||
2251 | + } |
||
2252 | + *end_blk = *start_blk + (g_pasStatic_Partition[i].size >> chip->phys_erase_shift) - 1; |
||
2253 | + if ((block >= *start_blk) && (block <= *end_blk)) |
||
2254 | + break; |
||
2255 | + *start_blk = *end_blk + 1; |
||
2256 | + } |
||
2257 | + if (*start_blk > *end_blk) |
||
2258 | + { |
||
2259 | + return -1; |
||
2260 | + } |
||
2261 | + return 0; |
||
2262 | +} |
||
2263 | + |
||
2264 | +static int |
||
2265 | +block_remap(struct mtd_info *mtd, int block) |
||
2266 | +{ |
||
2267 | + struct nand_chip *chip = mtd->priv; |
||
2268 | + int start_blk, end_blk; |
||
2269 | + int j, block_offset; |
||
2270 | + int bad_block = 0; |
||
2271 | + |
||
2272 | + if (chip->bbt == NULL) { |
||
2273 | + printk("ERROR!! no bbt table for block_remap\n"); |
||
2274 | + return -1; |
||
2275 | + } |
||
2276 | + |
||
2277 | + if (get_start_end_block(mtd, block, &start_blk, &end_blk) < 0) { |
||
2278 | + printk("ERROR!! can not find start_blk and end_blk\n"); |
||
2279 | + return -1; |
||
2280 | + } |
||
2281 | + |
||
2282 | + block_offset = block - start_blk; |
||
2283 | + for (j = start_blk; j <= end_blk;j++) { |
||
2284 | + if (((chip->bbt[j >> 2] >> ((j<<1) & 0x6)) & 0x3) == 0x0) { |
||
2285 | + if (!block_offset) |
||
2286 | + break; |
||
2287 | + block_offset--; |
||
2288 | + } else { |
||
2289 | + bad_block++; |
||
2290 | + } |
||
2291 | + } |
||
2292 | + if (j <= end_blk) { |
||
2293 | + return j; |
||
2294 | + } else { |
||
2295 | + // remap to the bad block |
||
2296 | + for (j = end_blk; bad_block > 0; j--) |
||
2297 | + { |
||
2298 | + if (((chip->bbt[j >> 2] >> ((j<<1) & 0x6)) & 0x3) != 0x0) |
||
2299 | + { |
||
2300 | + bad_block--; |
||
2301 | + if (bad_block <= block_offset) |
||
2302 | + return j; |
||
2303 | + } |
||
2304 | + } |
||
2305 | + } |
||
2306 | + |
||
2307 | + printk("Error!! block_remap error\n"); |
||
2308 | + return -1; |
||
2309 | +} |
||
2310 | + |
||
2311 | +int |
||
2312 | +check_block_remap(struct mtd_info *mtd, int block) |
||
2313 | +{ |
||
2314 | + if (shift_on_bbt) |
||
2315 | + return block_remap(mtd, block); |
||
2316 | + else |
||
2317 | + return block; |
||
2318 | +} |
||
2319 | +EXPORT_SYMBOL(check_block_remap); |
||
2320 | + |
||
2321 | + |
||
2322 | +static int |
||
2323 | +write_next_on_fail(struct mtd_info *mtd, char *write_buf, int page, int * to_blk) |
||
2324 | +{ |
||
2325 | + struct nand_chip *chip = mtd->priv; |
||
2326 | + int i, j, to_page = 0, first_page; |
||
2327 | + char *buf, *oob; |
||
2328 | + int start_blk = 0, end_blk; |
||
2329 | + int mapped_block; |
||
2330 | + int page_per_block_bit = chip->phys_erase_shift - chip->page_shift; |
||
2331 | + int block = page >> page_per_block_bit; |
||
2332 | + |
||
2333 | + // find next available block in the same MTD partition |
||
2334 | + mapped_block = block_remap(mtd, block); |
||
2335 | + if (mapped_block == -1) |
||
2336 | + return NAND_STATUS_FAIL; |
||
2337 | + |
||
2338 | + get_start_end_block(mtd, block, &start_blk, &end_blk); |
||
2339 | + |
||
2340 | + buf = kzalloc(mtd->writesize + mtd->oobsize, GFP_KERNEL | GFP_DMA); |
||
2341 | + if (buf == NULL) |
||
2342 | + return -1; |
||
2343 | + |
||
2344 | + oob = buf + mtd->writesize; |
||
2345 | + for ((*to_blk) = block + 1; (*to_blk) <= end_blk ; (*to_blk)++) { |
||
2346 | + if (nand_bbt_get(mtd, (*to_blk) << page_per_block_bit) == 0) { |
||
2347 | + int status; |
||
2348 | + status = mtk_nand_erase_hw(mtd, (*to_blk) << page_per_block_bit); |
||
2349 | + if (status & NAND_STATUS_FAIL) { |
||
2350 | + mtk_nand_block_markbad_hw(mtd, (*to_blk) << chip->phys_erase_shift); |
||
2351 | + nand_bbt_set(mtd, (*to_blk) << page_per_block_bit, 0x3); |
||
2352 | + } else { |
||
2353 | + /* good block */ |
||
2354 | + to_page = (*to_blk) << page_per_block_bit; |
||
2355 | + break; |
||
2356 | + } |
||
2357 | + } |
||
2358 | + } |
||
2359 | + |
||
2360 | + if (!to_page) { |
||
2361 | + kfree(buf); |
||
2362 | + return -1; |
||
2363 | + } |
||
2364 | + |
||
2365 | + first_page = (page >> page_per_block_bit) << page_per_block_bit; |
||
2366 | + for (i = 0; i < (1 << page_per_block_bit); i++) { |
||
2367 | + if ((first_page + i) != page) { |
||
2368 | + mtk_nand_read_oob_hw(mtd, chip, (first_page+i)); |
||
2369 | + for (j = 0; j < mtd->oobsize; j++) |
||
2370 | + if (chip->oob_poi[j] != (unsigned char)0xff) |
||
2371 | + break; |
||
2372 | + if (j < mtd->oobsize) { |
||
2373 | + mtk_nand_exec_read_page(mtd, (first_page+i), mtd->writesize, buf, oob); |
||
2374 | + memset(oob, 0xff, mtd->oobsize); |
||
2375 | + if (mtk_nand_exec_write_page(mtd, to_page + i, mtd->writesize, (u8 *)buf, oob) != 0) { |
||
2376 | + int ret, new_blk = 0; |
||
2377 | + nand_bbt_set(mtd, to_page, 0x3); |
||
2378 | + ret = write_next_on_fail(mtd, buf, to_page + i, &new_blk); |
||
2379 | + if (ret) { |
||
2380 | + kfree(buf); |
||
2381 | + mtk_nand_block_markbad_hw(mtd, to_page << chip->page_shift); |
||
2382 | + return ret; |
||
2383 | + } |
||
2384 | + mtk_nand_block_markbad_hw(mtd, to_page << chip->page_shift); |
||
2385 | + *to_blk = new_blk; |
||
2386 | + to_page = ((*to_blk) << page_per_block_bit); |
||
2387 | + } |
||
2388 | + } |
||
2389 | + } else { |
||
2390 | + memset(chip->oob_poi, 0xff, mtd->oobsize); |
||
2391 | + if (mtk_nand_exec_write_page(mtd, to_page + i, mtd->writesize, (u8 *)write_buf, chip->oob_poi) != 0) { |
||
2392 | + int ret, new_blk = 0; |
||
2393 | + nand_bbt_set(mtd, to_page, 0x3); |
||
2394 | + ret = write_next_on_fail(mtd, write_buf, to_page + i, &new_blk); |
||
2395 | + if (ret) { |
||
2396 | + kfree(buf); |
||
2397 | + mtk_nand_block_markbad_hw(mtd, to_page << chip->page_shift); |
||
2398 | + return ret; |
||
2399 | + } |
||
2400 | + mtk_nand_block_markbad_hw(mtd, to_page << chip->page_shift); |
||
2401 | + *to_blk = new_blk; |
||
2402 | + to_page = ((*to_blk) << page_per_block_bit); |
||
2403 | + } |
||
2404 | + } |
||
2405 | + } |
||
2406 | + |
||
2407 | + kfree(buf); |
||
2408 | + |
||
2409 | + return 0; |
||
2410 | +} |
||
2411 | + |
||
2412 | +static int |
||
2413 | +mtk_nand_write_page(struct mtd_info *mtd, struct nand_chip *chip, uint32_t offset, |
||
2414 | + int data_len, const u8 * buf, int oob_required, int page, int raw) |
||
2415 | +{ |
||
2416 | + int page_per_block = 1 << (chip->phys_erase_shift - chip->page_shift); |
||
2417 | + int block = page / page_per_block; |
||
2418 | + u16 page_in_block = page % page_per_block; |
||
2419 | + int mapped_block = block; |
||
2420 | + |
||
2421 | +#if defined(MTK_NAND_BMT) |
||
2422 | + mapped_block = get_mapping_block_index(block); |
||
2423 | + // write bad index into oob |
||
2424 | + if (mapped_block != block) |
||
2425 | + set_bad_index_to_oob(chip->oob_poi, block); |
||
2426 | + else |
||
2427 | + set_bad_index_to_oob(chip->oob_poi, FAKE_INDEX); |
||
2428 | +#else |
||
2429 | + if (shift_on_bbt) { |
||
2430 | + mapped_block = block_remap(mtd, block); |
||
2431 | + if (mapped_block == -1) |
||
2432 | + return NAND_STATUS_FAIL; |
||
2433 | + if (nand_bbt_get(mtd, mapped_block << (chip->phys_erase_shift - chip->page_shift)) != 0x0) |
||
2434 | + return NAND_STATUS_FAIL; |
||
2435 | + } |
||
2436 | +#endif |
||
2437 | + do { |
||
2438 | + if (mtk_nand_exec_write_page(mtd, page_in_block + mapped_block * page_per_block, mtd->writesize, (u8 *)buf, chip->oob_poi)) { |
||
2439 | + MSG(INIT, "write fail at block: 0x%x, page: 0x%x\n", mapped_block, page_in_block); |
||
2440 | +#if defined(MTK_NAND_BMT) |
||
2441 | + if (update_bmt((page_in_block + mapped_block * page_per_block) << chip->page_shift, UPDATE_WRITE_FAIL, (u8 *) buf, chip->oob_poi)) { |
||
2442 | + MSG(INIT, "Update BMT success\n"); |
||
2443 | + return 0; |
||
2444 | + } else { |
||
2445 | + MSG(INIT, "Update BMT fail\n"); |
||
2446 | + return -EIO; |
||
2447 | + } |
||
2448 | +#else |
||
2449 | + { |
||
2450 | + int new_blk; |
||
2451 | + nand_bbt_set(mtd, page_in_block + mapped_block * page_per_block, 0x3); |
||
2452 | + if (write_next_on_fail(mtd, (char *)buf, page_in_block + mapped_block * page_per_block, &new_blk) != 0) |
||
2453 | + { |
||
2454 | + mtk_nand_block_markbad_hw(mtd, (page_in_block + mapped_block * page_per_block) << chip->page_shift); |
||
2455 | + return NAND_STATUS_FAIL; |
||
2456 | + } |
||
2457 | + mtk_nand_block_markbad_hw(mtd, (page_in_block + mapped_block * page_per_block) << chip->page_shift); |
||
2458 | + break; |
||
2459 | + } |
||
2460 | +#endif |
||
2461 | + } else |
||
2462 | + break; |
||
2463 | + } while(1); |
||
2464 | + |
||
2465 | + return 0; |
||
2466 | +} |
||
2467 | + |
||
2468 | +static void |
||
2469 | +mtk_nand_command_bp(struct mtd_info *mtd, unsigned int command, int column, int page_addr) |
||
2470 | +{ |
||
2471 | + struct nand_chip *nand = mtd->priv; |
||
2472 | + |
||
2473 | + switch (command) { |
||
2474 | + case NAND_CMD_SEQIN: |
||
2475 | + memset(g_kCMD.au1OOB, 0xFF, sizeof(g_kCMD.au1OOB)); |
||
2476 | + g_kCMD.pDataBuf = NULL; |
||
2477 | + g_kCMD.u4RowAddr = page_addr; |
||
2478 | + g_kCMD.u4ColAddr = column; |
||
2479 | + break; |
||
2480 | + |
||
2481 | + case NAND_CMD_PAGEPROG: |
||
2482 | + if (g_kCMD.pDataBuf || (0xFF != g_kCMD.au1OOB[nand_badblock_offset])) { |
||
2483 | + u8 *pDataBuf = g_kCMD.pDataBuf ? g_kCMD.pDataBuf : nand->buffers->databuf; |
||
2484 | + mtk_nand_exec_write_page(mtd, g_kCMD.u4RowAddr, mtd->writesize, pDataBuf, g_kCMD.au1OOB); |
||
2485 | + g_kCMD.u4RowAddr = (u32) - 1; |
||
2486 | + g_kCMD.u4OOBRowAddr = (u32) - 1; |
||
2487 | + } |
||
2488 | + break; |
||
2489 | + |
||
2490 | + case NAND_CMD_READOOB: |
||
2491 | + g_kCMD.u4RowAddr = page_addr; |
||
2492 | + g_kCMD.u4ColAddr = column + mtd->writesize; |
||
2493 | + break; |
||
2494 | + |
||
2495 | + case NAND_CMD_READ0: |
||
2496 | + g_kCMD.u4RowAddr = page_addr; |
||
2497 | + g_kCMD.u4ColAddr = column; |
||
2498 | + break; |
||
2499 | + |
||
2500 | + case NAND_CMD_ERASE1: |
||
2501 | + nand->state=FL_ERASING; |
||
2502 | + (void)mtk_nand_reset(); |
||
2503 | + mtk_nand_set_mode(CNFG_OP_ERASE); |
||
2504 | + (void)mtk_nand_set_command(NAND_CMD_ERASE1); |
||
2505 | + (void)mtk_nand_set_address(0, page_addr, 0, devinfo.addr_cycle - 2); |
||
2506 | + break; |
||
2507 | + |
||
2508 | + case NAND_CMD_ERASE2: |
||
2509 | + (void)mtk_nand_set_command(NAND_CMD_ERASE2); |
||
2510 | + while (DRV_Reg32(NFI_STA_REG32) & STA_NAND_BUSY) |
||
2511 | + ; |
||
2512 | + break; |
||
2513 | + |
||
2514 | + case NAND_CMD_STATUS: |
||
2515 | + (void)mtk_nand_reset(); |
||
2516 | + NFI_CLN_REG16(NFI_CNFG_REG16, CNFG_BYTE_RW); |
||
2517 | + mtk_nand_set_mode(CNFG_OP_SRD); |
||
2518 | + mtk_nand_set_mode(CNFG_READ_EN); |
||
2519 | + NFI_CLN_REG16(NFI_CNFG_REG16, CNFG_AHB); |
||
2520 | + NFI_CLN_REG16(NFI_CNFG_REG16, CNFG_HW_ECC_EN); |
||
2521 | + (void)mtk_nand_set_command(NAND_CMD_STATUS); |
||
2522 | + NFI_CLN_REG16(NFI_CON_REG16, CON_NFI_NOB_MASK); |
||
2523 | + mb(); |
||
2524 | + DRV_WriteReg16(NFI_CON_REG16, CON_NFI_SRD | (1 << CON_NFI_NOB_SHIFT)); |
||
2525 | + g_bcmdstatus = true; |
||
2526 | + break; |
||
2527 | + |
||
2528 | + case NAND_CMD_RESET: |
||
2529 | + (void)mtk_nand_reset(); |
||
2530 | + DRV_WriteReg16(NFI_INTR_EN_REG16, INTR_RST_DONE_EN); |
||
2531 | + (void)mtk_nand_set_command(NAND_CMD_RESET); |
||
2532 | + DRV_WriteReg16(NFI_BASE+0x44, 0xF1); |
||
2533 | + while(!(DRV_Reg16(NFI_INTR_REG16)&INTR_RST_DONE_EN)) |
||
2534 | + ; |
||
2535 | + break; |
||
2536 | + |
||
2537 | + case NAND_CMD_READID: |
||
2538 | + mtk_nand_reset(); |
||
2539 | + /* Disable HW ECC */ |
||
2540 | + NFI_CLN_REG16(NFI_CNFG_REG16, CNFG_HW_ECC_EN); |
||
2541 | + NFI_CLN_REG16(NFI_CNFG_REG16, CNFG_AHB); |
||
2542 | + NFI_SET_REG16(NFI_CNFG_REG16, CNFG_READ_EN | CNFG_BYTE_RW); |
||
2543 | + (void)mtk_nand_reset(); |
||
2544 | + mb(); |
||
2545 | + mtk_nand_set_mode(CNFG_OP_SRD); |
||
2546 | + (void)mtk_nand_set_command(NAND_CMD_READID); |
||
2547 | + (void)mtk_nand_set_address(0, 0, 1, 0); |
||
2548 | + DRV_WriteReg16(NFI_CON_REG16, CON_NFI_SRD); |
||
2549 | + while (DRV_Reg32(NFI_STA_REG32) & STA_DATAR_STATE) |
||
2550 | + ; |
||
2551 | + break; |
||
2552 | + |
||
2553 | + default: |
||
2554 | + BUG(); |
||
2555 | + break; |
||
2556 | + } |
||
2557 | +} |
||
2558 | + |
||
2559 | +static void |
||
2560 | +mtk_nand_select_chip(struct mtd_info *mtd, int chip) |
||
2561 | +{ |
||
2562 | + if ((chip == -1) && (false == g_bInitDone)) { |
||
2563 | + struct nand_chip *nand = mtd->priv; |
||
2564 | + struct mtk_nand_host *host = nand->priv; |
||
2565 | + struct mtk_nand_host_hw *hw = host->hw; |
||
2566 | + u32 spare_per_sector = mtd->oobsize / (mtd->writesize / 512); |
||
2567 | + u32 ecc_bit = 4; |
||
2568 | + u32 spare_bit = PAGEFMT_SPARE_16; |
||
2569 | + |
||
2570 | + if (spare_per_sector >= 28) { |
||
2571 | + spare_bit = PAGEFMT_SPARE_28; |
||
2572 | + ecc_bit = 12; |
||
2573 | + spare_per_sector = 28; |
||
2574 | + } else if (spare_per_sector >= 27) { |
||
2575 | + spare_bit = PAGEFMT_SPARE_27; |
||
2576 | + ecc_bit = 8; |
||
2577 | + spare_per_sector = 27; |
||
2578 | + } else if (spare_per_sector >= 26) { |
||
2579 | + spare_bit = PAGEFMT_SPARE_26; |
||
2580 | + ecc_bit = 8; |
||
2581 | + spare_per_sector = 26; |
||
2582 | + } else if (spare_per_sector >= 16) { |
||
2583 | + spare_bit = PAGEFMT_SPARE_16; |
||
2584 | + ecc_bit = 4; |
||
2585 | + spare_per_sector = 16; |
||
2586 | + } else { |
||
2587 | + MSG(INIT, "[NAND]: NFI not support oobsize: %x\n", spare_per_sector); |
||
2588 | + ASSERT(0); |
||
2589 | + } |
||
2590 | + mtd->oobsize = spare_per_sector*(mtd->writesize/512); |
||
2591 | + MSG(INIT, "[NAND]select ecc bit:%d, sparesize :%d spare_per_sector=%d\n",ecc_bit,mtd->oobsize,spare_per_sector); |
||
2592 | + /* Setup PageFormat */ |
||
2593 | + if (4096 == mtd->writesize) { |
||
2594 | + NFI_SET_REG16(NFI_PAGEFMT_REG16, (spare_bit << PAGEFMT_SPARE_SHIFT) | PAGEFMT_4K); |
||
2595 | + nand->cmdfunc = mtk_nand_command_bp; |
||
2596 | + } else if (2048 == mtd->writesize) { |
||
2597 | + NFI_SET_REG16(NFI_PAGEFMT_REG16, (spare_bit << PAGEFMT_SPARE_SHIFT) | PAGEFMT_2K); |
||
2598 | + nand->cmdfunc = mtk_nand_command_bp; |
||
2599 | + } |
||
2600 | + ECC_Config(hw,ecc_bit); |
||
2601 | + g_bInitDone = true; |
||
2602 | + } |
||
2603 | + switch (chip) { |
||
2604 | + case -1: |
||
2605 | + break; |
||
2606 | + case 0: |
||
2607 | + case 1: |
||
2608 | + /* Jun Shen, 2011.04.13 */ |
||
2609 | + /* Note: MT6577 EVB NAND is mounted on CS0, but FPGA is CS1 */ |
||
2610 | + DRV_WriteReg16(NFI_CSEL_REG16, chip); |
||
2611 | + /* Jun Shen, 2011.04.13 */ |
||
2612 | + break; |
||
2613 | + } |
||
2614 | +} |
||
2615 | + |
||
2616 | +static uint8_t |
||
2617 | +mtk_nand_read_byte(struct mtd_info *mtd) |
||
2618 | +{ |
||
2619 | + uint8_t retval = 0; |
||
2620 | + |
||
2621 | + if (!mtk_nand_pio_ready()) { |
||
2622 | + printk("pio ready timeout\n"); |
||
2623 | + retval = false; |
||
2624 | + } |
||
2625 | + |
||
2626 | + if (g_bcmdstatus) { |
||
2627 | + retval = DRV_Reg8(NFI_DATAR_REG32); |
||
2628 | + NFI_CLN_REG16(NFI_CON_REG16, CON_NFI_NOB_MASK); |
||
2629 | + mtk_nand_reset(); |
||
2630 | + if (g_bHwEcc) { |
||
2631 | + NFI_SET_REG16(NFI_CNFG_REG16, CNFG_HW_ECC_EN); |
||
2632 | + } else { |
||
2633 | + NFI_CLN_REG16(NFI_CNFG_REG16, CNFG_HW_ECC_EN); |
||
2634 | + } |
||
2635 | + g_bcmdstatus = false; |
||
2636 | + } else |
||
2637 | + retval = DRV_Reg8(NFI_DATAR_REG32); |
||
2638 | + |
||
2639 | + return retval; |
||
2640 | +} |
||
2641 | + |
||
2642 | +static void |
||
2643 | +mtk_nand_read_buf(struct mtd_info *mtd, uint8_t * buf, int len) |
||
2644 | +{ |
||
2645 | + struct nand_chip *nand = (struct nand_chip *)mtd->priv; |
||
2646 | + struct NAND_CMD *pkCMD = &g_kCMD; |
||
2647 | + u32 u4ColAddr = pkCMD->u4ColAddr; |
||
2648 | + u32 u4PageSize = mtd->writesize; |
||
2649 | + |
||
2650 | + if (u4ColAddr < u4PageSize) { |
||
2651 | + if ((u4ColAddr == 0) && (len >= u4PageSize)) { |
||
2652 | + mtk_nand_exec_read_page(mtd, pkCMD->u4RowAddr, u4PageSize, buf, pkCMD->au1OOB); |
||
2653 | + if (len > u4PageSize) { |
||
2654 | + u32 u4Size = min(len - u4PageSize, sizeof(pkCMD->au1OOB)); |
||
2655 | + memcpy(buf + u4PageSize, pkCMD->au1OOB, u4Size); |
||
2656 | + } |
||
2657 | + } else { |
||
2658 | + mtk_nand_exec_read_page(mtd, pkCMD->u4RowAddr, u4PageSize, nand->buffers->databuf, pkCMD->au1OOB); |
||
2659 | + memcpy(buf, nand->buffers->databuf + u4ColAddr, len); |
||
2660 | + } |
||
2661 | + pkCMD->u4OOBRowAddr = pkCMD->u4RowAddr; |
||
2662 | + } else { |
||
2663 | + u32 u4Offset = u4ColAddr - u4PageSize; |
||
2664 | + u32 u4Size = min(len - u4Offset, sizeof(pkCMD->au1OOB)); |
||
2665 | + if (pkCMD->u4OOBRowAddr != pkCMD->u4RowAddr) { |
||
2666 | + mtk_nand_exec_read_page(mtd, pkCMD->u4RowAddr, u4PageSize, nand->buffers->databuf, pkCMD->au1OOB); |
||
2667 | + pkCMD->u4OOBRowAddr = pkCMD->u4RowAddr; |
||
2668 | + } |
||
2669 | + memcpy(buf, pkCMD->au1OOB + u4Offset, u4Size); |
||
2670 | + } |
||
2671 | + pkCMD->u4ColAddr += len; |
||
2672 | +} |
||
2673 | + |
||
2674 | +static void |
||
2675 | +mtk_nand_write_buf(struct mtd_info *mtd, const uint8_t * buf, int len) |
||
2676 | +{ |
||
2677 | + struct NAND_CMD *pkCMD = &g_kCMD; |
||
2678 | + u32 u4ColAddr = pkCMD->u4ColAddr; |
||
2679 | + u32 u4PageSize = mtd->writesize; |
||
2680 | + int i4Size, i; |
||
2681 | + |
||
2682 | + if (u4ColAddr >= u4PageSize) { |
||
2683 | + u32 u4Offset = u4ColAddr - u4PageSize; |
||
2684 | + u8 *pOOB = pkCMD->au1OOB + u4Offset; |
||
2685 | + i4Size = min(len, (int)(sizeof(pkCMD->au1OOB) - u4Offset)); |
||
2686 | + for (i = 0; i < i4Size; i++) { |
||
2687 | + pOOB[i] &= buf[i]; |
||
2688 | + } |
||
2689 | + } else { |
||
2690 | + pkCMD->pDataBuf = (u8 *) buf; |
||
2691 | + } |
||
2692 | + |
||
2693 | + pkCMD->u4ColAddr += len; |
||
2694 | +} |
||
2695 | + |
||
2696 | +static int |
||
2697 | +mtk_nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t * buf, int oob_required, int page) |
||
2698 | +{ |
||
2699 | + mtk_nand_write_buf(mtd, buf, mtd->writesize); |
||
2700 | + mtk_nand_write_buf(mtd, chip->oob_poi, mtd->oobsize); |
||
2701 | + return 0; |
||
2702 | +} |
||
2703 | + |
||
2704 | +static int |
||
2705 | +mtk_nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, uint8_t * buf, int oob_required, int page) |
||
2706 | +{ |
||
2707 | + struct NAND_CMD *pkCMD = &g_kCMD; |
||
2708 | + u32 u4ColAddr = pkCMD->u4ColAddr; |
||
2709 | + u32 u4PageSize = mtd->writesize; |
||
2710 | + |
||
2711 | + if (u4ColAddr == 0) { |
||
2712 | + mtk_nand_exec_read_page(mtd, pkCMD->u4RowAddr, u4PageSize, buf, chip->oob_poi); |
||
2713 | + pkCMD->u4ColAddr += u4PageSize + mtd->oobsize; |
||
2714 | + } |
||
2715 | + |
||
2716 | + return 0; |
||
2717 | +} |
||
2718 | + |
||
2719 | +static int |
||
2720 | +mtk_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip, u8 * buf, int page) |
||
2721 | +{ |
||
2722 | + int page_per_block = 1 << (chip->phys_erase_shift - chip->page_shift); |
||
2723 | + int block = page / page_per_block; |
||
2724 | + u16 page_in_block = page % page_per_block; |
||
2725 | + int mapped_block = block; |
||
2726 | + |
||
2727 | +#if defined (MTK_NAND_BMT) |
||
2728 | + mapped_block = get_mapping_block_index(block); |
||
2729 | + if (mtk_nand_exec_read_page(mtd, page_in_block + mapped_block * page_per_block, |
||
2730 | + mtd->writesize, buf, chip->oob_poi)) |
||
2731 | + return 0; |
||
2732 | +#else |
||
2733 | + if (shift_on_bbt) { |
||
2734 | + mapped_block = block_remap(mtd, block); |
||
2735 | + if (mapped_block == -1) |
||
2736 | + return NAND_STATUS_FAIL; |
||
2737 | + if (nand_bbt_get(mtd, mapped_block << (chip->phys_erase_shift - chip->page_shift)) != 0x0) |
||
2738 | + return NAND_STATUS_FAIL; |
||
2739 | + } |
||
2740 | + |
||
2741 | + if (mtk_nand_exec_read_page(mtd, page_in_block + mapped_block * page_per_block, mtd->writesize, buf, chip->oob_poi)) |
||
2742 | + return 0; |
||
2743 | + else |
||
2744 | + return -EIO; |
||
2745 | +#endif |
||
2746 | +} |
||
2747 | + |
||
2748 | +int |
||
2749 | +mtk_nand_erase_hw(struct mtd_info *mtd, int page) |
||
2750 | +{ |
||
2751 | + struct nand_chip *chip = (struct nand_chip *)mtd->priv; |
||
2752 | + |
||
2753 | + chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page); |
||
2754 | + chip->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1); |
||
2755 | + |
||
2756 | + return chip->waitfunc(mtd, chip); |
||
2757 | +} |
||
2758 | + |
||
2759 | +static int |
||
2760 | +mtk_nand_erase(struct mtd_info *mtd, int page) |
||
2761 | +{ |
||
2762 | + // get mapping |
||
2763 | + struct nand_chip *chip = mtd->priv; |
||
2764 | + int page_per_block = 1 << (chip->phys_erase_shift - chip->page_shift); |
||
2765 | + int page_in_block = page % page_per_block; |
||
2766 | + int block = page / page_per_block; |
||
2767 | + int mapped_block = block; |
||
2768 | + |
||
2769 | +#if defined(MTK_NAND_BMT) |
||
2770 | + mapped_block = get_mapping_block_index(block); |
||
2771 | +#else |
||
2772 | + if (shift_on_bbt) { |
||
2773 | + mapped_block = block_remap(mtd, block); |
||
2774 | + if (mapped_block == -1) |
||
2775 | + return NAND_STATUS_FAIL; |
||
2776 | + if (nand_bbt_get(mtd, mapped_block << (chip->phys_erase_shift - chip->page_shift)) != 0x0) |
||
2777 | + return NAND_STATUS_FAIL; |
||
2778 | + } |
||
2779 | +#endif |
||
2780 | + |
||
2781 | + do { |
||
2782 | + int status = mtk_nand_erase_hw(mtd, page_in_block + page_per_block * mapped_block); |
||
2783 | + |
||
2784 | + if (status & NAND_STATUS_FAIL) { |
||
2785 | +#if defined (MTK_NAND_BMT) |
||
2786 | + if (update_bmt( (page_in_block + mapped_block * page_per_block) << chip->page_shift, |
||
2787 | + UPDATE_ERASE_FAIL, NULL, NULL)) |
||
2788 | + { |
||
2789 | + MSG(INIT, "Erase fail at block: 0x%x, update BMT success\n", mapped_block); |
||
2790 | + return 0; |
||
2791 | + } else { |
||
2792 | + MSG(INIT, "Erase fail at block: 0x%x, update BMT fail\n", mapped_block); |
||
2793 | + return NAND_STATUS_FAIL; |
||
2794 | + } |
||
2795 | +#else |
||
2796 | + mtk_nand_block_markbad_hw(mtd, (page_in_block + mapped_block * page_per_block) << chip->page_shift); |
||
2797 | + nand_bbt_set(mtd, page_in_block + mapped_block * page_per_block, 0x3); |
||
2798 | + if (shift_on_bbt) { |
||
2799 | + mapped_block = block_remap(mtd, block); |
||
2800 | + if (mapped_block == -1) |
||
2801 | + return NAND_STATUS_FAIL; |
||
2802 | + if (nand_bbt_get(mtd, mapped_block << (chip->phys_erase_shift - chip->page_shift)) != 0x0) |
||
2803 | + return NAND_STATUS_FAIL; |
||
2804 | + } else |
||
2805 | + return NAND_STATUS_FAIL; |
||
2806 | +#endif |
||
2807 | + } else |
||
2808 | + break; |
||
2809 | + } while(1); |
||
2810 | + |
||
2811 | + return 0; |
||
2812 | +} |
||
2813 | + |
||
2814 | +static int |
||
2815 | +mtk_nand_read_oob_raw(struct mtd_info *mtd, uint8_t * buf, int page_addr, int len) |
||
2816 | +{ |
||
2817 | + struct nand_chip *chip = (struct nand_chip *)mtd->priv; |
||
2818 | + u32 col_addr = 0; |
||
2819 | + u32 sector = 0; |
||
2820 | + int res = 0; |
||
2821 | + u32 colnob = 2, rawnob = devinfo.addr_cycle - 2; |
||
2822 | + int randomread = 0; |
||
2823 | + int read_len = 0; |
||
2824 | + int sec_num = 1<<(chip->page_shift-9); |
||
2825 | + int spare_per_sector = mtd->oobsize/sec_num; |
||
2826 | + |
||
2827 | + if (len > NAND_MAX_OOBSIZE || len % OOB_AVAI_PER_SECTOR || !buf) { |
||
2828 | + printk(KERN_WARNING "[%s] invalid parameter, len: %d, buf: %p\n", __FUNCTION__, len, buf); |
||
2829 | + return -EINVAL; |
||
2830 | + } |
||
2831 | + if (len > spare_per_sector) |
||
2832 | + randomread = 1; |
||
2833 | + if (!randomread || !(devinfo.advancedmode & RAMDOM_READ)) { |
||
2834 | + while (len > 0) { |
||
2835 | + read_len = min(len, spare_per_sector); |
||
2836 | + col_addr = NAND_SECTOR_SIZE + sector * (NAND_SECTOR_SIZE + spare_per_sector); // TODO: Fix this hard-code 16 |
||
2837 | + if (!mtk_nand_ready_for_read(chip, page_addr, col_addr, false, NULL)) { |
||
2838 | + printk(KERN_WARNING "mtk_nand_ready_for_read return failed\n"); |
||
2839 | + res = -EIO; |
||
2840 | + goto error; |
||
2841 | + } |
||
2842 | + if (!mtk_nand_mcu_read_data(buf + spare_per_sector * sector, read_len)) { |
||
2843 | + printk(KERN_WARNING "mtk_nand_mcu_read_data return failed\n"); |
||
2844 | + res = -EIO; |
||
2845 | + goto error; |
||
2846 | + } |
||
2847 | + mtk_nand_check_RW_count(read_len); |
||
2848 | + mtk_nand_stop_read(); |
||
2849 | + sector++; |
||
2850 | + len -= read_len; |
||
2851 | + } |
||
2852 | + } else { |
||
2853 | + col_addr = NAND_SECTOR_SIZE; |
||
2854 | + if (chip->options & NAND_BUSWIDTH_16) |
||
2855 | + col_addr /= 2; |
||
2856 | + if (!mtk_nand_reset()) |
||
2857 | + goto error; |
||
2858 | + mtk_nand_set_mode(0x6000); |
||
2859 | + NFI_SET_REG16(NFI_CNFG_REG16, CNFG_READ_EN); |
||
2860 | + DRV_WriteReg16(NFI_CON_REG16, 4 << CON_NFI_SEC_SHIFT); |
||
2861 | + |
||
2862 | + NFI_CLN_REG16(NFI_CNFG_REG16, CNFG_AHB); |
||
2863 | + NFI_CLN_REG16(NFI_CNFG_REG16, CNFG_HW_ECC_EN); |
||
2864 | + |
||
2865 | + mtk_nand_set_autoformat(false); |
||
2866 | + |
||
2867 | + if (!mtk_nand_set_command(NAND_CMD_READ0)) |
||
2868 | + goto error; |
||
2869 | + //1 FIXED ME: For Any Kind of AddrCycle |
||
2870 | + if (!mtk_nand_set_address(col_addr, page_addr, colnob, rawnob)) |
||
2871 | + goto error; |
||
2872 | + if (!mtk_nand_set_command(NAND_CMD_READSTART)) |
||
2873 | + goto error; |
||
2874 | + if (!mtk_nand_status_ready(STA_NAND_BUSY)) |
||
2875 | + goto error; |
||
2876 | + read_len = min(len, spare_per_sector); |
||
2877 | + if (!mtk_nand_mcu_read_data(buf + spare_per_sector * sector, read_len)) { |
||
2878 | + printk(KERN_WARNING "mtk_nand_mcu_read_data return failed first 16\n"); |
||
2879 | + res = -EIO; |
||
2880 | + goto error; |
||
2881 | + } |
||
2882 | + sector++; |
||
2883 | + len -= read_len; |
||
2884 | + mtk_nand_stop_read(); |
||
2885 | + while (len > 0) { |
||
2886 | + read_len = min(len, spare_per_sector); |
||
2887 | + if (!mtk_nand_set_command(0x05)) |
||
2888 | + goto error; |
||
2889 | + col_addr = NAND_SECTOR_SIZE + sector * (NAND_SECTOR_SIZE + spare_per_sector); |
||
2890 | + if (chip->options & NAND_BUSWIDTH_16) |
||
2891 | + col_addr /= 2; |
||
2892 | + DRV_WriteReg32(NFI_COLADDR_REG32, col_addr); |
||
2893 | + DRV_WriteReg16(NFI_ADDRNOB_REG16, 2); |
||
2894 | + DRV_WriteReg16(NFI_CON_REG16, 4 << CON_NFI_SEC_SHIFT); |
||
2895 | + if (!mtk_nand_status_ready(STA_ADDR_STATE)) |
||
2896 | + goto error; |
||
2897 | + if (!mtk_nand_set_command(0xE0)) |
||
2898 | + goto error; |
||
2899 | + if (!mtk_nand_status_ready(STA_NAND_BUSY)) |
||
2900 | + goto error; |
||
2901 | + if (!mtk_nand_mcu_read_data(buf + spare_per_sector * sector, read_len)) { |
||
2902 | + printk(KERN_WARNING "mtk_nand_mcu_read_data return failed first 16\n"); |
||
2903 | + res = -EIO; |
||
2904 | + goto error; |
||
2905 | + } |
||
2906 | + mtk_nand_stop_read(); |
||
2907 | + sector++; |
||
2908 | + len -= read_len; |
||
2909 | + } |
||
2910 | + } |
||
2911 | +error: |
||
2912 | + NFI_CLN_REG16(NFI_CON_REG16, CON_NFI_BRD); |
||
2913 | + return res; |
||
2914 | +} |
||
2915 | + |
||
2916 | +static int |
||
2917 | +mtk_nand_write_oob_raw(struct mtd_info *mtd, const uint8_t * buf, int page_addr, int len) |
||
2918 | +{ |
||
2919 | + struct nand_chip *chip = mtd->priv; |
||
2920 | + u32 col_addr = 0; |
||
2921 | + u32 sector = 0; |
||
2922 | + int write_len = 0; |
||
2923 | + int status; |
||
2924 | + int sec_num = 1<<(chip->page_shift-9); |
||
2925 | + int spare_per_sector = mtd->oobsize/sec_num; |
||
2926 | + |
||
2927 | + if (len > NAND_MAX_OOBSIZE || len % OOB_AVAI_PER_SECTOR || !buf) { |
||
2928 | + printk(KERN_WARNING "[%s] invalid parameter, len: %d, buf: %p\n", __FUNCTION__, len, buf); |
||
2929 | + return -EINVAL; |
||
2930 | + } |
||
2931 | + |
||
2932 | + while (len > 0) { |
||
2933 | + write_len = min(len, spare_per_sector); |
||
2934 | + col_addr = sector * (NAND_SECTOR_SIZE + spare_per_sector) + NAND_SECTOR_SIZE; |
||
2935 | + if (!mtk_nand_ready_for_write(chip, page_addr, col_addr, false, NULL)) |
||
2936 | + return -EIO; |
||
2937 | + if (!mtk_nand_mcu_write_data(mtd, buf + sector * spare_per_sector, write_len)) |
||
2938 | + return -EIO; |
||
2939 | + (void)mtk_nand_check_RW_count(write_len); |
||
2940 | + NFI_CLN_REG16(NFI_CON_REG16, CON_NFI_BWR); |
||
2941 | + (void)mtk_nand_set_command(NAND_CMD_PAGEPROG); |
||
2942 | + while (DRV_Reg32(NFI_STA_REG32) & STA_NAND_BUSY) |
||
2943 | + ; |
||
2944 | + status = chip->waitfunc(mtd, chip); |
||
2945 | + if (status & NAND_STATUS_FAIL) { |
||
2946 | + printk(KERN_INFO "status: %d\n", status); |
||
2947 | + return -EIO; |
||
2948 | + } |
||
2949 | + len -= write_len; |
||
2950 | + sector++; |
||
2951 | + } |
||
2952 | + |
||
2953 | + return 0; |
||
2954 | +} |
||
2955 | + |
||
2956 | +static int |
||
2957 | +mtk_nand_write_oob_hw(struct mtd_info *mtd, struct nand_chip *chip, int page) |
||
2958 | +{ |
||
2959 | + int i, iter; |
||
2960 | + int sec_num = 1<<(chip->page_shift-9); |
||
2961 | + int spare_per_sector = mtd->oobsize/sec_num; |
||
2962 | + |
||
2963 | + memcpy(local_oob_buf, chip->oob_poi, mtd->oobsize); |
||
2964 | + |
||
2965 | + // copy ecc data |
||
2966 | + for (i = 0; i < layout->eccbytes; i++) { |
||
2967 | + iter = (i / (spare_per_sector-OOB_AVAI_PER_SECTOR)) * spare_per_sector + OOB_AVAI_PER_SECTOR + i % (spare_per_sector-OOB_AVAI_PER_SECTOR); |
||
2968 | + local_oob_buf[iter] = chip->oob_poi[layout->eccpos[i]]; |
||
2969 | + } |
||
2970 | + |
||
2971 | + // copy FDM data |
||
2972 | + for (i = 0; i < sec_num; i++) |
||
2973 | + memcpy(&local_oob_buf[i * spare_per_sector], &chip->oob_poi[i * OOB_AVAI_PER_SECTOR], OOB_AVAI_PER_SECTOR); |
||
2974 | + |
||
2975 | + return mtk_nand_write_oob_raw(mtd, local_oob_buf, page, mtd->oobsize); |
||
2976 | +} |
||
2977 | + |
||
2978 | +static int mtk_nand_write_oob(struct mtd_info *mtd, struct nand_chip *chip, int page) |
||
2979 | +{ |
||
2980 | + int page_per_block = 1 << (chip->phys_erase_shift - chip->page_shift); |
||
2981 | + int block = page / page_per_block; |
||
2982 | + u16 page_in_block = page % page_per_block; |
||
2983 | + int mapped_block = block; |
||
2984 | + |
||
2985 | +#if defined(MTK_NAND_BMT) |
||
2986 | + mapped_block = get_mapping_block_index(block); |
||
2987 | + // write bad index into oob |
||
2988 | + if (mapped_block != block) |
||
2989 | + set_bad_index_to_oob(chip->oob_poi, block); |
||
2990 | + else |
||
2991 | + set_bad_index_to_oob(chip->oob_poi, FAKE_INDEX); |
||
2992 | +#else |
||
2993 | + if (shift_on_bbt) |
||
2994 | + { |
||
2995 | + mapped_block = block_remap(mtd, block); |
||
2996 | + if (mapped_block == -1) |
||
2997 | + return NAND_STATUS_FAIL; |
||
2998 | + if (nand_bbt_get(mtd, mapped_block << (chip->phys_erase_shift - chip->page_shift)) != 0x0) |
||
2999 | + return NAND_STATUS_FAIL; |
||
3000 | + } |
||
3001 | +#endif |
||
3002 | + do { |
||
3003 | + if (mtk_nand_write_oob_hw(mtd, chip, page_in_block + mapped_block * page_per_block /* page */)) { |
||
3004 | + MSG(INIT, "write oob fail at block: 0x%x, page: 0x%x\n", mapped_block, page_in_block); |
||
3005 | +#if defined(MTK_NAND_BMT) |
||
3006 | + if (update_bmt((page_in_block + mapped_block * page_per_block) << chip->page_shift, |
||
3007 | + UPDATE_WRITE_FAIL, NULL, chip->oob_poi)) |
||
3008 | + { |
||
3009 | + MSG(INIT, "Update BMT success\n"); |
||
3010 | + return 0; |
||
3011 | + } else { |
||
3012 | + MSG(INIT, "Update BMT fail\n"); |
||
3013 | + return -EIO; |
||
3014 | + } |
||
3015 | +#else |
||
3016 | + mtk_nand_block_markbad_hw(mtd, (page_in_block + mapped_block * page_per_block) << chip->page_shift); |
||
3017 | + nand_bbt_set(mtd, page_in_block + mapped_block * page_per_block, 0x3); |
||
3018 | + if (shift_on_bbt) { |
||
3019 | + mapped_block = block_remap(mtd, mapped_block); |
||
3020 | + if (mapped_block == -1) |
||
3021 | + return NAND_STATUS_FAIL; |
||
3022 | + if (nand_bbt_get(mtd, mapped_block << (chip->phys_erase_shift - chip->page_shift)) != 0x0) |
||
3023 | + return NAND_STATUS_FAIL; |
||
3024 | + } else { |
||
3025 | + return NAND_STATUS_FAIL; |
||
3026 | + } |
||
3027 | +#endif |
||
3028 | + } else |
||
3029 | + break; |
||
3030 | + } while (1); |
||
3031 | + |
||
3032 | + return 0; |
||
3033 | +} |
||
3034 | + |
||
3035 | +int |
||
3036 | +mtk_nand_block_markbad_hw(struct mtd_info *mtd, loff_t offset) |
||
3037 | +{ |
||
3038 | + struct nand_chip *chip = mtd->priv; |
||
3039 | + int block = (int)offset >> chip->phys_erase_shift; |
||
3040 | + int page = block * (1 << (chip->phys_erase_shift - chip->page_shift)); |
||
3041 | + u8 buf[8]; |
||
3042 | + |
||
3043 | + memset(buf, 0xFF, 8); |
||
3044 | + buf[0] = 0; |
||
3045 | + return mtk_nand_write_oob_raw(mtd, buf, page, 8); |
||
3046 | +} |
||
3047 | + |
||
3048 | +static int |
||
3049 | +mtk_nand_block_markbad(struct mtd_info *mtd, loff_t offset) |
||
3050 | +{ |
||
3051 | + struct nand_chip *chip = mtd->priv; |
||
3052 | + int block = (int)offset >> chip->phys_erase_shift; |
||
3053 | + int ret; |
||
3054 | + int mapped_block = block; |
||
3055 | + |
||
3056 | + nand_get_device(chip, mtd, FL_WRITING); |
||
3057 | + |
||
3058 | +#if defined(MTK_NAND_BMT) |
||
3059 | + mapped_block = get_mapping_block_index(block); |
||
3060 | + ret = mtk_nand_block_markbad_hw(mtd, mapped_block << chip->phys_erase_shift); |
||
3061 | +#else |
||
3062 | + if (shift_on_bbt) { |
||
3063 | + mapped_block = block_remap(mtd, block); |
||
3064 | + if (mapped_block == -1) { |
||
3065 | + printk("NAND mark bad failed\n"); |
||
3066 | + nand_release_device(mtd); |
||
3067 | + return NAND_STATUS_FAIL; |
||
3068 | + } |
||
3069 | + } |
||
3070 | + ret = mtk_nand_block_markbad_hw(mtd, mapped_block << chip->phys_erase_shift); |
||
3071 | +#endif |
||
3072 | + nand_release_device(mtd); |
||
3073 | + |
||
3074 | + return ret; |
||
3075 | +} |
||
3076 | + |
||
3077 | +int |
||
3078 | +mtk_nand_read_oob_hw(struct mtd_info *mtd, struct nand_chip *chip, int page) |
||
3079 | +{ |
||
3080 | + int i; |
||
3081 | + u8 iter = 0; |
||
3082 | + |
||
3083 | + int sec_num = 1<<(chip->page_shift-9); |
||
3084 | + int spare_per_sector = mtd->oobsize/sec_num; |
||
3085 | + |
||
3086 | + if (mtk_nand_read_oob_raw(mtd, chip->oob_poi, page, mtd->oobsize)) { |
||
3087 | + printk(KERN_ERR "[%s]mtk_nand_read_oob_raw return failed\n", __FUNCTION__); |
||
3088 | + return -EIO; |
||
3089 | + } |
||
3090 | + |
||
3091 | + // adjust to ecc physical layout to memory layout |
||
3092 | + /*********************************************************/ |
||
3093 | + /* FDM0 | ECC0 | FDM1 | ECC1 | FDM2 | ECC2 | FDM3 | ECC3 */ |
||
3094 | + /* 8B | 8B | 8B | 8B | 8B | 8B | 8B | 8B */ |
||
3095 | + /*********************************************************/ |
||
3096 | + |
||
3097 | + memcpy(local_oob_buf, chip->oob_poi, mtd->oobsize); |
||
3098 | + // copy ecc data |
||
3099 | + for (i = 0; i < layout->eccbytes; i++) { |
||
3100 | + iter = (i / (spare_per_sector-OOB_AVAI_PER_SECTOR)) * spare_per_sector + OOB_AVAI_PER_SECTOR + i % (spare_per_sector-OOB_AVAI_PER_SECTOR); |
||
3101 | + chip->oob_poi[layout->eccpos[i]] = local_oob_buf[iter]; |
||
3102 | + } |
||
3103 | + |
||
3104 | + // copy FDM data |
||
3105 | + for (i = 0; i < sec_num; i++) { |
||
3106 | + memcpy(&chip->oob_poi[i * OOB_AVAI_PER_SECTOR], &local_oob_buf[i * spare_per_sector], OOB_AVAI_PER_SECTOR); |
||
3107 | + } |
||
3108 | + |
||
3109 | + return 0; |
||
3110 | +} |
||
3111 | + |
||
3112 | +static int |
||
3113 | +mtk_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip, int page) |
||
3114 | +{ |
||
3115 | + int page_per_block = 1 << (chip->phys_erase_shift - chip->page_shift); |
||
3116 | + int block = page / page_per_block; |
||
3117 | + u16 page_in_block = page % page_per_block; |
||
3118 | + int mapped_block = block; |
||
3119 | + |
||
3120 | +#if defined (MTK_NAND_BMT) |
||
3121 | + mapped_block = get_mapping_block_index(block); |
||
3122 | + mtk_nand_read_oob_hw(mtd, chip, page_in_block + mapped_block * page_per_block); |
||
3123 | +#else |
||
3124 | + if (shift_on_bbt) { |
||
3125 | + mapped_block = block_remap(mtd, block); |
||
3126 | + if (mapped_block == -1) |
||
3127 | + return NAND_STATUS_FAIL; |
||
3128 | + // allow to read oob even if the block is bad |
||
3129 | + } |
||
3130 | + if (mtk_nand_read_oob_hw(mtd, chip, page_in_block + mapped_block * page_per_block)!=0) |
||
3131 | + return -1; |
||
3132 | +#endif |
||
3133 | + return 0; |
||
3134 | +} |
||
3135 | + |
||
3136 | +int |
||
3137 | +mtk_nand_block_bad_hw(struct mtd_info *mtd, loff_t ofs) |
||
3138 | +{ |
||
3139 | + struct nand_chip *chip = (struct nand_chip *)mtd->priv; |
||
3140 | + int page_addr = (int)(ofs >> chip->page_shift); |
||
3141 | + unsigned int page_per_block = 1 << (chip->phys_erase_shift - chip->page_shift); |
||
3142 | + unsigned char oob_buf[8]; |
||
3143 | + |
||
3144 | + page_addr &= ~(page_per_block - 1); |
||
3145 | + if (mtk_nand_read_oob_raw(mtd, oob_buf, page_addr, sizeof(oob_buf))) { |
||
3146 | + printk(KERN_WARNING "mtk_nand_read_oob_raw return error\n"); |
||
3147 | + return 1; |
||
3148 | + } |
||
3149 | + |
||
3150 | + if (oob_buf[0] != 0xff) { |
||
3151 | + printk(KERN_WARNING "Bad block detected at 0x%x, oob_buf[0] is 0x%x\n", page_addr, oob_buf[0]); |
||
3152 | + // dump_nfi(); |
||
3153 | + return 1; |
||
3154 | + } |
||
3155 | + |
||
3156 | + return 0; |
||
3157 | +} |
||
3158 | + |
||
3159 | +static int |
||
3160 | +mtk_nand_block_bad(struct mtd_info *mtd, loff_t ofs) |
||
3161 | +{ |
||
3162 | + struct nand_chip *chip = (struct nand_chip *)mtd->priv; |
||
3163 | + int block = (int)ofs >> chip->phys_erase_shift; |
||
3164 | + int mapped_block = block; |
||
3165 | + int ret; |
||
3166 | + |
||
3167 | +#if defined(MTK_NAND_BMT) |
||
3168 | + mapped_block = get_mapping_block_index(block); |
||
3169 | +#else |
||
3170 | + if (shift_on_bbt) { |
||
3171 | + mapped_block = block_remap(mtd, block); |
||
3172 | + } |
||
3173 | +#endif |
||
3174 | + |
||
3175 | + ret = mtk_nand_block_bad_hw(mtd, mapped_block << chip->phys_erase_shift); |
||
3176 | +#if defined (MTK_NAND_BMT) |
||
3177 | + if (ret) { |
||
3178 | + MSG(INIT, "Unmapped bad block: 0x%x\n", mapped_block); |
||
3179 | + if (update_bmt(mapped_block << chip->phys_erase_shift, UPDATE_UNMAPPED_BLOCK, NULL, NULL)) { |
||
3180 | + MSG(INIT, "Update BMT success\n"); |
||
3181 | + ret = 0; |
||
3182 | + } else { |
||
3183 | + MSG(INIT, "Update BMT fail\n"); |
||
3184 | + ret = 1; |
||
3185 | + } |
||
3186 | + } |
||
3187 | +#endif |
||
3188 | + |
||
3189 | + return ret; |
||
3190 | +} |
||
3191 | + |
||
3192 | +#ifdef CONFIG_MTD_NAND_VERIFY_WRITE |
||
3193 | +char gacBuf[4096 + 288]; |
||
3194 | + |
||
3195 | +static int |
||
3196 | +mtk_nand_verify_buf(struct mtd_info *mtd, const uint8_t * buf, int len) |
||
3197 | +{ |
||
3198 | + struct nand_chip *chip = (struct nand_chip *)mtd->priv; |
||
3199 | + struct NAND_CMD *pkCMD = &g_kCMD; |
||
3200 | + u32 u4PageSize = mtd->writesize; |
||
3201 | + u32 *pSrc, *pDst; |
||
3202 | + int i; |
||
3203 | + |
||
3204 | + mtk_nand_exec_read_page(mtd, pkCMD->u4RowAddr, u4PageSize, gacBuf, gacBuf + u4PageSize); |
||
3205 | + |
||
3206 | + pSrc = (u32 *) buf; |
||
3207 | + pDst = (u32 *) gacBuf; |
||
3208 | + len = len / sizeof(u32); |
||
3209 | + for (i = 0; i < len; ++i) { |
||
3210 | + if (*pSrc != *pDst) { |
||
3211 | + MSG(VERIFY, "mtk_nand_verify_buf page fail at page %d\n", pkCMD->u4RowAddr); |
||
3212 | + return -1; |
||
3213 | + } |
||
3214 | + pSrc++; |
||
3215 | + pDst++; |
||
3216 | + } |
||
3217 | + |
||
3218 | + pSrc = (u32 *) chip->oob_poi; |
||
3219 | + pDst = (u32 *) (gacBuf + u4PageSize); |
||
3220 | + |
||
3221 | + if ((pSrc[0] != pDst[0]) || (pSrc[1] != pDst[1]) || (pSrc[2] != pDst[2]) || (pSrc[3] != pDst[3]) || (pSrc[4] != pDst[4]) || (pSrc[5] != pDst[5])) { |
||
3222 | + // TODO: Ask Designer Why? |
||
3223 | + //(pSrc[6] != pDst[6]) || (pSrc[7] != pDst[7])) |
||
3224 | + MSG(VERIFY, "mtk_nand_verify_buf oob fail at page %d\n", pkCMD->u4RowAddr); |
||
3225 | + MSG(VERIFY, "0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", pSrc[0], pSrc[1], pSrc[2], pSrc[3], pSrc[4], pSrc[5], pSrc[6], pSrc[7]); |
||
3226 | + MSG(VERIFY, "0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", pDst[0], pDst[1], pDst[2], pDst[3], pDst[4], pDst[5], pDst[6], pDst[7]); |
||
3227 | + return -1; |
||
3228 | + } |
||
3229 | + return 0; |
||
3230 | +} |
||
3231 | +#endif |
||
3232 | + |
||
3233 | +static void |
||
3234 | +mtk_nand_init_hw(struct mtk_nand_host *host) { |
||
3235 | + struct mtk_nand_host_hw *hw = host->hw; |
||
3236 | + u32 data; |
||
3237 | + |
||
3238 | + data = DRV_Reg32(RALINK_SYSCTL_BASE+0x60); |
||
3239 | + data &= ~((0x3<<18)|(0x3<<16)); |
||
3240 | + data |= ((0x2<<18) |(0x2<<16)); |
||
3241 | + DRV_WriteReg32(RALINK_SYSCTL_BASE+0x60, data); |
||
3242 | + |
||
3243 | + MSG(INIT, "Enable NFI Clock\n"); |
||
3244 | + nand_enable_clock(); |
||
3245 | + |
||
3246 | + g_bInitDone = false; |
||
3247 | + g_kCMD.u4OOBRowAddr = (u32) - 1; |
||
3248 | + |
||
3249 | + /* Set default NFI access timing control */ |
||
3250 | + DRV_WriteReg32(NFI_ACCCON_REG32, hw->nfi_access_timing); |
||
3251 | + DRV_WriteReg16(NFI_CNFG_REG16, 0); |
||
3252 | + DRV_WriteReg16(NFI_PAGEFMT_REG16, 0); |
||
3253 | + |
||
3254 | + /* Reset the state machine and data FIFO, because flushing FIFO */ |
||
3255 | + (void)mtk_nand_reset(); |
||
3256 | + |
||
3257 | + /* Set the ECC engine */ |
||
3258 | + if (hw->nand_ecc_mode == NAND_ECC_HW) { |
||
3259 | + MSG(INIT, "%s : Use HW ECC\n", MODULE_NAME); |
||
3260 | + if (g_bHwEcc) |
||
3261 | + NFI_SET_REG32(NFI_CNFG_REG16, CNFG_HW_ECC_EN); |
||
3262 | + ECC_Config(host->hw,4); |
||
3263 | + mtk_nand_configure_fdm(8); |
||
3264 | + mtk_nand_configure_lock(); |
||
3265 | + } |
||
3266 | + |
||
3267 | + NFI_SET_REG16(NFI_IOCON_REG16, 0x47); |
||
3268 | +} |
||
3269 | + |
||
3270 | +static int mtk_nand_dev_ready(struct mtd_info *mtd) |
||
3271 | +{ |
||
3272 | + return !(DRV_Reg32(NFI_STA_REG32) & STA_NAND_BUSY); |
||
3273 | +} |
||
3274 | + |
||
3275 | +#define FACT_BBT_BLOCK_NUM 32 // use the latest 32 BLOCK for factory bbt table |
||
3276 | +#define FACT_BBT_OOB_SIGNATURE 1 |
||
3277 | +#define FACT_BBT_SIGNATURE_LEN 7 |
||
3278 | +const u8 oob_signature[] = "mtknand"; |
||
3279 | +static u8 *fact_bbt = 0; |
||
3280 | +static u32 bbt_size = 0; |
||
3281 | + |
||
3282 | +static int |
||
3283 | +read_fact_bbt(struct mtd_info *mtd, unsigned int page) |
||
3284 | +{ |
||
3285 | + struct nand_chip *chip = mtd->priv; |
||
3286 | + |
||
3287 | + // read oob |
||
3288 | + if (mtk_nand_read_oob_hw(mtd, chip, page)==0) |
||
3289 | + { |
||
3290 | + if (chip->oob_poi[nand_badblock_offset] != 0xFF) |
||
3291 | + { |
||
3292 | + printk("Bad Block on Page %x\n", page); |
||
3293 | + return -1; |
||
3294 | + } |
||
3295 | + if (memcmp(&chip->oob_poi[FACT_BBT_OOB_SIGNATURE], oob_signature, FACT_BBT_SIGNATURE_LEN) != 0) |
||
3296 | + { |
||
3297 | + printk("compare signature failed %x\n", page); |
||
3298 | + return -1; |
||
3299 | + } |
||
3300 | + if (mtk_nand_exec_read_page(mtd, page, mtd->writesize, chip->buffers->databuf, chip->oob_poi)) |
||
3301 | + { |
||
3302 | + printk("Signature matched and data read!\n"); |
||
3303 | + memcpy(fact_bbt, chip->buffers->databuf, (bbt_size <= mtd->writesize)? bbt_size:mtd->writesize); |
||
3304 | + return 0; |
||
3305 | + } |
||
3306 | + |
||
3307 | + } |
||
3308 | + printk("failed at page %x\n", page); |
||
3309 | + return -1; |
||
3310 | +} |
||
3311 | + |
||
3312 | +static int |
||
3313 | +load_fact_bbt(struct mtd_info *mtd) |
||
3314 | +{ |
||
3315 | + struct nand_chip *chip = mtd->priv; |
||
3316 | + int i; |
||
3317 | + u32 total_block; |
||
3318 | + |
||
3319 | + total_block = 1 << (chip->chip_shift - chip->phys_erase_shift); |
||
3320 | + bbt_size = total_block >> 2; |
||
3321 | + |
||
3322 | + if ((!fact_bbt) && (bbt_size)) |
||
3323 | + fact_bbt = (u8 *)kmalloc(bbt_size, GFP_KERNEL); |
||
3324 | + if (!fact_bbt) |
||
3325 | + return -1; |
||
3326 | + |
||
3327 | + for (i = total_block - 1; i >= (total_block - FACT_BBT_BLOCK_NUM); i--) |
||
3328 | + { |
||
3329 | + if (read_fact_bbt(mtd, i << (chip->phys_erase_shift - chip->page_shift)) == 0) |
||
3330 | + { |
||
3331 | + printk("load_fact_bbt success %d\n", i); |
||
3332 | + return 0; |
||
3333 | + } |
||
3334 | + |
||
3335 | + } |
||
3336 | + printk("load_fact_bbt failed\n"); |
||
3337 | + return -1; |
||
3338 | +} |
||
3339 | + |
||
3340 | +static int oob_mtk_ooblayout_ecc(struct mtd_info *mtd, int section, |
||
3341 | + struct mtd_oob_region *oobregion) |
||
3342 | +{ |
||
3343 | + oobregion->length = 8; |
||
3344 | + oobregion->offset = layout->eccpos[section * 8]; |
||
3345 | + |
||
3346 | + return 0; |
||
3347 | +} |
||
3348 | + |
||
3349 | +static int oob_mtk_ooblayout_free(struct mtd_info *mtd, int section, |
||
3350 | + struct mtd_oob_region *oobregion) |
||
3351 | +{ |
||
3352 | + if (section >= (layout->eccbytes / 8)) { |
||
3353 | + return -ERANGE; |
||
3354 | + } |
||
3355 | + oobregion->offset = layout->oobfree[section].offset; |
||
3356 | + oobregion->length = layout->oobfree[section].length; |
||
3357 | + |
||
3358 | + return 0; |
||
3359 | +} |
||
3360 | + |
||
3361 | + |
||
3362 | +static const struct mtd_ooblayout_ops oob_mtk_ops = { |
||
3363 | + .ecc = oob_mtk_ooblayout_ecc, |
||
3364 | + .free = oob_mtk_ooblayout_free, |
||
3365 | +}; |
||
3366 | + |
||
3367 | +static int |
||
3368 | +mtk_nand_probe(struct platform_device *pdev) |
||
3369 | +{ |
||
3370 | + struct mtd_part_parser_data ppdata; |
||
3371 | + struct mtk_nand_host_hw *hw; |
||
3372 | + struct nand_chip *nand_chip; |
||
3373 | + struct mtd_info *mtd; |
||
3374 | + u8 ext_id1, ext_id2, ext_id3; |
||
3375 | + int err = 0; |
||
3376 | + int id; |
||
3377 | + u32 ext_id; |
||
3378 | + int i; |
||
3379 | + u32 data; |
||
3380 | + |
||
3381 | + data = DRV_Reg32(RALINK_SYSCTL_BASE+0x60); |
||
3382 | + data &= ~((0x3<<18)|(0x3<<16)); |
||
3383 | + data |= ((0x2<<18) |(0x2<<16)); |
||
3384 | + DRV_WriteReg32(RALINK_SYSCTL_BASE+0x60, data); |
||
3385 | + |
||
3386 | + hw = &mt7621_nand_hw; |
||
3387 | + BUG_ON(!hw); |
||
3388 | + /* Allocate memory for the device structure (and zero it) */ |
||
3389 | + host = kzalloc(sizeof(struct mtk_nand_host), GFP_KERNEL); |
||
3390 | + if (!host) { |
||
3391 | + MSG(INIT, "mtk_nand: failed to allocate device structure.\n"); |
||
3392 | + return -ENOMEM; |
||
3393 | + } |
||
3394 | + |
||
3395 | + host->hw = hw; |
||
3396 | + |
||
3397 | + /* init mtd data structure */ |
||
3398 | + nand_chip = &host->nand_chip; |
||
3399 | + nand_chip->priv = host; /* link the private data structures */ |
||
3400 | + |
||
3401 | + mtd = host->mtd = &nand_chip->mtd; |
||
3402 | + mtd->priv = nand_chip; |
||
3403 | + mtd->owner = THIS_MODULE; |
||
3404 | + mtd->name = "MT7621-NAND"; |
||
3405 | + |
||
3406 | + hw->nand_ecc_mode = NAND_ECC_HW; |
||
3407 | + |
||
3408 | + /* Set address of NAND IO lines */ |
||
3409 | + nand_chip->IO_ADDR_R = (void __iomem *)NFI_DATAR_REG32; |
||
3410 | + nand_chip->IO_ADDR_W = (void __iomem *)NFI_DATAW_REG32; |
||
3411 | + nand_chip->chip_delay = 20; /* 20us command delay time */ |
||
3412 | + nand_chip->ecc.mode = hw->nand_ecc_mode; /* enable ECC */ |
||
3413 | + nand_chip->ecc.strength = 1; |
||
3414 | + nand_chip->read_byte = mtk_nand_read_byte; |
||
3415 | + nand_chip->read_buf = mtk_nand_read_buf; |
||
3416 | + nand_chip->write_buf = mtk_nand_write_buf; |
||
3417 | +#ifdef CONFIG_MTD_NAND_VERIFY_WRITE |
||
3418 | + nand_chip->verify_buf = mtk_nand_verify_buf; |
||
3419 | +#endif |
||
3420 | + nand_chip->select_chip = mtk_nand_select_chip; |
||
3421 | + nand_chip->dev_ready = mtk_nand_dev_ready; |
||
3422 | + nand_chip->cmdfunc = mtk_nand_command_bp; |
||
3423 | + nand_chip->ecc.read_page = mtk_nand_read_page_hwecc; |
||
3424 | + nand_chip->ecc.write_page = mtk_nand_write_page_hwecc; |
||
3425 | + |
||
3426 | + mtd_set_ooblayout(mtd, &oob_mtk_ops); |
||
3427 | + nand_chip->ecc.size = hw->nand_ecc_size; //2048 |
||
3428 | + nand_chip->ecc.bytes = hw->nand_ecc_bytes; //32 |
||
3429 | + |
||
3430 | + // For BMT, we need to revise driver architecture |
||
3431 | + nand_chip->write_page = mtk_nand_write_page; |
||
3432 | + nand_chip->ecc.write_oob = mtk_nand_write_oob; |
||
3433 | + nand_chip->block_markbad = mtk_nand_block_markbad; // need to add nand_get_device()/nand_release_device(). |
||
3434 | + nand_chip->read_page = mtk_nand_read_page; |
||
3435 | + nand_chip->ecc.read_oob = mtk_nand_read_oob; |
||
3436 | + nand_chip->block_bad = mtk_nand_block_bad; |
||
3437 | + nand_chip->cmd_ctrl = mtk_nfc_cmd_ctrl; |
||
3438 | + |
||
3439 | + //Qwert:Add for Uboot |
||
3440 | + mtk_nand_init_hw(host); |
||
3441 | + /* Select the device */ |
||
3442 | + nand_chip->select_chip(mtd, NFI_DEFAULT_CS); |
||
3443 | + |
||
3444 | + /* |
||
3445 | + * Reset the chip, required by some chips (e.g. Micron MT29FxGxxxxx) |
||
3446 | + * after power-up |
||
3447 | + */ |
||
3448 | + nand_chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); |
||
3449 | + |
||
3450 | + memset(&devinfo, 0 , sizeof(flashdev_info)); |
||
3451 | + |
||
3452 | + /* Send the command for reading device ID */ |
||
3453 | + |
||
3454 | + nand_chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); |
||
3455 | + |
||
3456 | + /* Read manufacturer and device IDs */ |
||
3457 | + manu_id = nand_chip->read_byte(mtd); |
||
3458 | + dev_id = nand_chip->read_byte(mtd); |
||
3459 | + id = dev_id | (manu_id << 8); |
||
3460 | + ext_id1 = nand_chip->read_byte(mtd); |
||
3461 | + ext_id2 = nand_chip->read_byte(mtd); |
||
3462 | + ext_id3 = nand_chip->read_byte(mtd); |
||
3463 | + ext_id = ext_id1 << 16 | ext_id2 << 8 | ext_id3; |
||
3464 | + if (!get_device_info(id, ext_id, &devinfo)) { |
||
3465 | + u32 chip_mode = RALINK_REG(RALINK_SYSCTL_BASE+0x010)&0x0F; |
||
3466 | + MSG(INIT, "Not Support this Device! \r\n"); |
||
3467 | + memset(&devinfo, 0 , sizeof(flashdev_info)); |
||
3468 | + MSG(INIT, "chip_mode=%08X\n",chip_mode); |
||
3469 | + |
||
3470 | + /* apply bootstrap first */ |
||
3471 | + devinfo.addr_cycle = 5; |
||
3472 | + devinfo.iowidth = 8; |
||
3473 | + |
||
3474 | + switch (chip_mode) { |
||
3475 | + case 10: |
||
3476 | + devinfo.pagesize = 2048; |
||
3477 | + devinfo.sparesize = 128; |
||
3478 | + devinfo.totalsize = 128; |
||
3479 | + devinfo.blocksize = 128; |
||
3480 | + break; |
||
3481 | + case 11: |
||
3482 | + devinfo.pagesize = 4096; |
||
3483 | + devinfo.sparesize = 128; |
||
3484 | + devinfo.totalsize = 1024; |
||
3485 | + devinfo.blocksize = 256; |
||
3486 | + break; |
||
3487 | + case 12: |
||
3488 | + devinfo.pagesize = 4096; |
||
3489 | + devinfo.sparesize = 224; |
||
3490 | + devinfo.totalsize = 2048; |
||
3491 | + devinfo.blocksize = 512; |
||
3492 | + break; |
||
3493 | + default: |
||
3494 | + case 1: |
||
3495 | + devinfo.pagesize = 2048; |
||
3496 | + devinfo.sparesize = 64; |
||
3497 | + devinfo.totalsize = 128; |
||
3498 | + devinfo.blocksize = 128; |
||
3499 | + break; |
||
3500 | + } |
||
3501 | + |
||
3502 | + devinfo.timmingsetting = NFI_DEFAULT_ACCESS_TIMING; |
||
3503 | + devinfo.devciename[0] = 'U'; |
||
3504 | + devinfo.advancedmode = 0; |
||
3505 | + } |
||
3506 | + mtd->writesize = devinfo.pagesize; |
||
3507 | + mtd->erasesize = (devinfo.blocksize<<10); |
||
3508 | + mtd->oobsize = devinfo.sparesize; |
||
3509 | + |
||
3510 | + nand_chip->chipsize = (devinfo.totalsize<<20); |
||
3511 | + nand_chip->page_shift = ffs(mtd->writesize) - 1; |
||
3512 | + nand_chip->pagemask = (nand_chip->chipsize >> nand_chip->page_shift) - 1; |
||
3513 | + nand_chip->phys_erase_shift = ffs(mtd->erasesize) - 1; |
||
3514 | + nand_chip->chip_shift = ffs(nand_chip->chipsize) - 1;//0x1C;//ffs(nand_chip->chipsize) - 1; |
||
3515 | + nand_chip->cmd_ctrl = mtk_nfc_cmd_ctrl; |
||
3516 | + |
||
3517 | + if (devinfo.pagesize == 4096) |
||
3518 | + layout = &nand_oob_128; |
||
3519 | + else if (devinfo.pagesize == 2048) |
||
3520 | + layout = &nand_oob_64; |
||
3521 | + else if (devinfo.pagesize == 512) |
||
3522 | + layout = &nand_oob_16; |
||
3523 | + |
||
3524 | + layout->eccbytes = devinfo.sparesize-OOB_AVAI_PER_SECTOR*(devinfo.pagesize/NAND_SECTOR_SIZE); |
||
3525 | + for (i = 0; i < layout->eccbytes; i++) |
||
3526 | + layout->eccpos[i]=OOB_AVAI_PER_SECTOR*(devinfo.pagesize/NAND_SECTOR_SIZE)+i; |
||
3527 | + |
||
3528 | + MSG(INIT, "Support this Device in MTK table! %x \r\n", id); |
||
3529 | + hw->nfi_bus_width = devinfo.iowidth; |
||
3530 | + DRV_WriteReg32(NFI_ACCCON_REG32, devinfo.timmingsetting); |
||
3531 | + |
||
3532 | + /* 16-bit bus width */ |
||
3533 | + if (hw->nfi_bus_width == 16) { |
||
3534 | + MSG(INIT, "%s : Set the 16-bit I/O settings!\n", MODULE_NAME); |
||
3535 | + nand_chip->options |= NAND_BUSWIDTH_16; |
||
3536 | + } |
||
3537 | + mtd->oobsize = devinfo.sparesize; |
||
3538 | + hw->nfi_cs_num = 1; |
||
3539 | + |
||
3540 | + nand_chip->options |= NAND_USE_BOUNCE_BUFFER; |
||
3541 | + nand_chip->buf_align = 16; |
||
3542 | + |
||
3543 | + /* Scan to find existance of the device */ |
||
3544 | + if (nand_scan(mtd, hw->nfi_cs_num)) { |
||
3545 | + MSG(INIT, "%s : nand_scan fail.\n", MODULE_NAME); |
||
3546 | + err = -ENXIO; |
||
3547 | + goto out; |
||
3548 | + } |
||
3549 | + |
||
3550 | + nand_chip->erase = mtk_nand_erase; |
||
3551 | + |
||
3552 | + g_page_size = mtd->writesize; |
||
3553 | + platform_set_drvdata(pdev, host); |
||
3554 | + if (hw->nfi_bus_width == 16) { |
||
3555 | + NFI_SET_REG16(NFI_PAGEFMT_REG16, PAGEFMT_DBYTE_EN); |
||
3556 | + } |
||
3557 | + |
||
3558 | + nand_chip->select_chip(mtd, 0); |
||
3559 | +#if defined(MTK_NAND_BMT) |
||
3560 | + nand_chip->chipsize -= (BMT_POOL_SIZE) << nand_chip->phys_erase_shift; |
||
3561 | +#endif |
||
3562 | + mtd->size = nand_chip->chipsize; |
||
3563 | + |
||
3564 | + CFG_BLOCKSIZE = mtd->erasesize; |
||
3565 | + |
||
3566 | +#if defined(MTK_NAND_BMT) |
||
3567 | + if (!g_bmt) { |
||
3568 | + if (!(g_bmt = init_bmt(nand_chip, BMT_POOL_SIZE))) { |
||
3569 | + MSG(INIT, "Error: init bmt failed\n"); |
||
3570 | + return 0; |
||
3571 | + } |
||
3572 | + } |
||
3573 | +#endif |
||
3574 | + |
||
3575 | + nand_set_flash_node(nand_chip, pdev->dev.of_node); |
||
3576 | + err = mtd_device_parse_register(mtd, probe_types, &ppdata, |
||
3577 | + NULL, 0); |
||
3578 | + if (!err) { |
||
3579 | + MSG(INIT, "[mtk_nand] probe successfully!\n"); |
||
3580 | + nand_disable_clock(); |
||
3581 | + shift_on_bbt = 1; |
||
3582 | + if (load_fact_bbt(mtd) == 0) { |
||
3583 | + int i; |
||
3584 | + for (i = 0; i < 0x100; i++) |
||
3585 | + nand_chip->bbt[i] |= fact_bbt[i]; |
||
3586 | + } |
||
3587 | + |
||
3588 | + return err; |
||
3589 | + } |
||
3590 | + |
||
3591 | +out: |
||
3592 | + MSG(INIT, "[NFI] mtk_nand_probe fail, err = %d!\n", err); |
||
3593 | + nand_release(mtd); |
||
3594 | + platform_set_drvdata(pdev, NULL); |
||
3595 | + kfree(host); |
||
3596 | + nand_disable_clock(); |
||
3597 | + return err; |
||
3598 | +} |
||
3599 | + |
||
3600 | +static int |
||
3601 | +mtk_nand_remove(struct platform_device *pdev) |
||
3602 | +{ |
||
3603 | + struct mtk_nand_host *host = platform_get_drvdata(pdev); |
||
3604 | + struct mtd_info *mtd = host->mtd; |
||
3605 | + struct nand_chip *nand_chip = &host->nand_chip; |
||
3606 | + |
||
3607 | + nand_release(mtd); |
||
3608 | + kfree(host); |
||
3609 | + nand_disable_clock(); |
||
3610 | + |
||
3611 | + return 0; |
||
3612 | +} |
||
3613 | + |
||
3614 | +static const struct of_device_id mt7621_nand_match[] = { |
||
3615 | + { .compatible = "mtk,mt7621-nand" }, |
||
3616 | + {}, |
||
3617 | +}; |
||
3618 | +MODULE_DEVICE_TABLE(of, mt7621_nand_match); |
||
3619 | + |
||
3620 | +static struct platform_driver mtk_nand_driver = { |
||
3621 | + .probe = mtk_nand_probe, |
||
3622 | + .remove = mtk_nand_remove, |
||
3623 | + .driver = { |
||
3624 | + .name = "MT7621-NAND", |
||
3625 | + .owner = THIS_MODULE, |
||
3626 | + .of_match_table = mt7621_nand_match, |
||
3627 | + }, |
||
3628 | +}; |
||
3629 | + |
||
3630 | +static int __init |
||
3631 | +mtk_nand_init(void) |
||
3632 | +{ |
||
3633 | + printk("MediaTek Nand driver init, version %s\n", VERSION); |
||
3634 | + |
||
3635 | + return platform_driver_register(&mtk_nand_driver); |
||
3636 | +} |
||
3637 | + |
||
3638 | +static void __exit |
||
3639 | +mtk_nand_exit(void) |
||
3640 | +{ |
||
3641 | + platform_driver_unregister(&mtk_nand_driver); |
||
3642 | +} |
||
3643 | + |
||
3644 | +module_init(mtk_nand_init); |
||
3645 | +module_exit(mtk_nand_exit); |
||
3646 | +MODULE_LICENSE("GPL"); |
||
3647 | --- /dev/null |
||
3648 | +++ b/drivers/mtd/nand/mtk_nand2.h |
||
3649 | @@ -0,0 +1,452 @@ |
||
3650 | +#ifndef __MTK_NAND_H |
||
3651 | +#define __MTK_NAND_H |
||
3652 | + |
||
3653 | +#define RALINK_NAND_CTRL_BASE 0xBE003000 |
||
3654 | +#define RALINK_SYSCTL_BASE 0xBE000000 |
||
3655 | +#define RALINK_NANDECC_CTRL_BASE 0xBE003800 |
||
3656 | +/******************************************************************************* |
||
3657 | + * NFI Register Definition |
||
3658 | + *******************************************************************************/ |
||
3659 | + |
||
3660 | +#define NFI_CNFG_REG16 ((volatile P_U16)(NFI_BASE+0x0000)) |
||
3661 | +#define NFI_PAGEFMT_REG16 ((volatile P_U16)(NFI_BASE+0x0004)) |
||
3662 | +#define NFI_CON_REG16 ((volatile P_U16)(NFI_BASE+0x0008)) |
||
3663 | +#define NFI_ACCCON_REG32 ((volatile P_U32)(NFI_BASE+0x000C)) |
||
3664 | +#define NFI_INTR_EN_REG16 ((volatile P_U16)(NFI_BASE+0x0010)) |
||
3665 | +#define NFI_INTR_REG16 ((volatile P_U16)(NFI_BASE+0x0014)) |
||
3666 | + |
||
3667 | +#define NFI_CMD_REG16 ((volatile P_U16)(NFI_BASE+0x0020)) |
||
3668 | + |
||
3669 | +#define NFI_ADDRNOB_REG16 ((volatile P_U16)(NFI_BASE+0x0030)) |
||
3670 | +#define NFI_COLADDR_REG32 ((volatile P_U32)(NFI_BASE+0x0034)) |
||
3671 | +#define NFI_ROWADDR_REG32 ((volatile P_U32)(NFI_BASE+0x0038)) |
||
3672 | + |
||
3673 | +#define NFI_STRDATA_REG16 ((volatile P_U16)(NFI_BASE+0x0040)) |
||
3674 | + |
||
3675 | +#define NFI_DATAW_REG32 ((volatile P_U32)(NFI_BASE+0x0050)) |
||
3676 | +#define NFI_DATAR_REG32 ((volatile P_U32)(NFI_BASE+0x0054)) |
||
3677 | +#define NFI_PIO_DIRDY_REG16 ((volatile P_U16)(NFI_BASE+0x0058)) |
||
3678 | + |
||
3679 | +#define NFI_STA_REG32 ((volatile P_U32)(NFI_BASE+0x0060)) |
||
3680 | +#define NFI_FIFOSTA_REG16 ((volatile P_U16)(NFI_BASE+0x0064)) |
||
3681 | +#define NFI_LOCKSTA_REG16 ((volatile P_U16)(NFI_BASE+0x0068)) |
||
3682 | + |
||
3683 | +#define NFI_ADDRCNTR_REG16 ((volatile P_U16)(NFI_BASE+0x0070)) |
||
3684 | + |
||
3685 | +#define NFI_STRADDR_REG32 ((volatile P_U32)(NFI_BASE+0x0080)) |
||
3686 | +#define NFI_BYTELEN_REG16 ((volatile P_U16)(NFI_BASE+0x0084)) |
||
3687 | + |
||
3688 | +#define NFI_CSEL_REG16 ((volatile P_U16)(NFI_BASE+0x0090)) |
||
3689 | +#define NFI_IOCON_REG16 ((volatile P_U16)(NFI_BASE+0x0094)) |
||
3690 | + |
||
3691 | +#define NFI_FDM0L_REG32 ((volatile P_U32)(NFI_BASE+0x00A0)) |
||
3692 | +#define NFI_FDM0M_REG32 ((volatile P_U32)(NFI_BASE+0x00A4)) |
||
3693 | + |
||
3694 | +#define NFI_LOCK_REG16 ((volatile P_U16)(NFI_BASE+0x0100)) |
||
3695 | +#define NFI_LOCKCON_REG32 ((volatile P_U32)(NFI_BASE+0x0104)) |
||
3696 | +#define NFI_LOCKANOB_REG16 ((volatile P_U16)(NFI_BASE+0x0108)) |
||
3697 | +#define NFI_LOCK00ADD_REG32 ((volatile P_U32)(NFI_BASE+0x0110)) |
||
3698 | +#define NFI_LOCK00FMT_REG32 ((volatile P_U32)(NFI_BASE+0x0114)) |
||
3699 | +#define NFI_LOCK01ADD_REG32 ((volatile P_U32)(NFI_BASE+0x0118)) |
||
3700 | +#define NFI_LOCK01FMT_REG32 ((volatile P_U32)(NFI_BASE+0x011C)) |
||
3701 | +#define NFI_LOCK02ADD_REG32 ((volatile P_U32)(NFI_BASE+0x0120)) |
||
3702 | +#define NFI_LOCK02FMT_REG32 ((volatile P_U32)(NFI_BASE+0x0124)) |
||
3703 | +#define NFI_LOCK03ADD_REG32 ((volatile P_U32)(NFI_BASE+0x0128)) |
||
3704 | +#define NFI_LOCK03FMT_REG32 ((volatile P_U32)(NFI_BASE+0x012C)) |
||
3705 | +#define NFI_LOCK04ADD_REG32 ((volatile P_U32)(NFI_BASE+0x0130)) |
||
3706 | +#define NFI_LOCK04FMT_REG32 ((volatile P_U32)(NFI_BASE+0x0134)) |
||
3707 | +#define NFI_LOCK05ADD_REG32 ((volatile P_U32)(NFI_BASE+0x0138)) |
||
3708 | +#define NFI_LOCK05FMT_REG32 ((volatile P_U32)(NFI_BASE+0x013C)) |
||
3709 | +#define NFI_LOCK06ADD_REG32 ((volatile P_U32)(NFI_BASE+0x0140)) |
||
3710 | +#define NFI_LOCK06FMT_REG32 ((volatile P_U32)(NFI_BASE+0x0144)) |
||
3711 | +#define NFI_LOCK07ADD_REG32 ((volatile P_U32)(NFI_BASE+0x0148)) |
||
3712 | +#define NFI_LOCK07FMT_REG32 ((volatile P_U32)(NFI_BASE+0x014C)) |
||
3713 | +#define NFI_LOCK08ADD_REG32 ((volatile P_U32)(NFI_BASE+0x0150)) |
||
3714 | +#define NFI_LOCK08FMT_REG32 ((volatile P_U32)(NFI_BASE+0x0154)) |
||
3715 | +#define NFI_LOCK09ADD_REG32 ((volatile P_U32)(NFI_BASE+0x0158)) |
||
3716 | +#define NFI_LOCK09FMT_REG32 ((volatile P_U32)(NFI_BASE+0x015C)) |
||
3717 | +#define NFI_LOCK10ADD_REG32 ((volatile P_U32)(NFI_BASE+0x0160)) |
||
3718 | +#define NFI_LOCK10FMT_REG32 ((volatile P_U32)(NFI_BASE+0x0164)) |
||
3719 | +#define NFI_LOCK11ADD_REG32 ((volatile P_U32)(NFI_BASE+0x0168)) |
||
3720 | +#define NFI_LOCK11FMT_REG32 ((volatile P_U32)(NFI_BASE+0x016C)) |
||
3721 | +#define NFI_LOCK12ADD_REG32 ((volatile P_U32)(NFI_BASE+0x0170)) |
||
3722 | +#define NFI_LOCK12FMT_REG32 ((volatile P_U32)(NFI_BASE+0x0174)) |
||
3723 | +#define NFI_LOCK13ADD_REG32 ((volatile P_U32)(NFI_BASE+0x0178)) |
||
3724 | +#define NFI_LOCK13FMT_REG32 ((volatile P_U32)(NFI_BASE+0x017C)) |
||
3725 | +#define NFI_LOCK14ADD_REG32 ((volatile P_U32)(NFI_BASE+0x0180)) |
||
3726 | +#define NFI_LOCK14FMT_REG32 ((volatile P_U32)(NFI_BASE+0x0184)) |
||
3727 | +#define NFI_LOCK15ADD_REG32 ((volatile P_U32)(NFI_BASE+0x0188)) |
||
3728 | +#define NFI_LOCK15FMT_REG32 ((volatile P_U32)(NFI_BASE+0x018C)) |
||
3729 | + |
||
3730 | +#define NFI_FIFODATA0_REG32 ((volatile P_U32)(NFI_BASE+0x0190)) |
||
3731 | +#define NFI_FIFODATA1_REG32 ((volatile P_U32)(NFI_BASE+0x0194)) |
||
3732 | +#define NFI_FIFODATA2_REG32 ((volatile P_U32)(NFI_BASE+0x0198)) |
||
3733 | +#define NFI_FIFODATA3_REG32 ((volatile P_U32)(NFI_BASE+0x019C)) |
||
3734 | +#define NFI_MASTERSTA_REG16 ((volatile P_U16)(NFI_BASE+0x0210)) |
||
3735 | + |
||
3736 | + |
||
3737 | +/******************************************************************************* |
||
3738 | + * NFI Register Field Definition |
||
3739 | + *******************************************************************************/ |
||
3740 | + |
||
3741 | +/* NFI_CNFG */ |
||
3742 | +#define CNFG_AHB (0x0001) |
||
3743 | +#define CNFG_READ_EN (0x0002) |
||
3744 | +#define CNFG_DMA_BURST_EN (0x0004) |
||
3745 | +#define CNFG_BYTE_RW (0x0040) |
||
3746 | +#define CNFG_HW_ECC_EN (0x0100) |
||
3747 | +#define CNFG_AUTO_FMT_EN (0x0200) |
||
3748 | +#define CNFG_OP_IDLE (0x0000) |
||
3749 | +#define CNFG_OP_READ (0x1000) |
||
3750 | +#define CNFG_OP_SRD (0x2000) |
||
3751 | +#define CNFG_OP_PRGM (0x3000) |
||
3752 | +#define CNFG_OP_ERASE (0x4000) |
||
3753 | +#define CNFG_OP_RESET (0x5000) |
||
3754 | +#define CNFG_OP_CUST (0x6000) |
||
3755 | +#define CNFG_OP_MODE_MASK (0x7000) |
||
3756 | +#define CNFG_OP_MODE_SHIFT (12) |
||
3757 | + |
||
3758 | +/* NFI_PAGEFMT */ |
||
3759 | +#define PAGEFMT_512 (0x0000) |
||
3760 | +#define PAGEFMT_2K (0x0001) |
||
3761 | +#define PAGEFMT_4K (0x0002) |
||
3762 | + |
||
3763 | +#define PAGEFMT_PAGE_MASK (0x0003) |
||
3764 | + |
||
3765 | +#define PAGEFMT_DBYTE_EN (0x0008) |
||
3766 | + |
||
3767 | +#define PAGEFMT_SPARE_16 (0x0000) |
||
3768 | +#define PAGEFMT_SPARE_26 (0x0001) |
||
3769 | +#define PAGEFMT_SPARE_27 (0x0002) |
||
3770 | +#define PAGEFMT_SPARE_28 (0x0003) |
||
3771 | +#define PAGEFMT_SPARE_MASK (0x0030) |
||
3772 | +#define PAGEFMT_SPARE_SHIFT (4) |
||
3773 | + |
||
3774 | +#define PAGEFMT_FDM_MASK (0x0F00) |
||
3775 | +#define PAGEFMT_FDM_SHIFT (8) |
||
3776 | + |
||
3777 | +#define PAGEFMT_FDM_ECC_MASK (0xF000) |
||
3778 | +#define PAGEFMT_FDM_ECC_SHIFT (12) |
||
3779 | + |
||
3780 | +/* NFI_CON */ |
||
3781 | +#define CON_FIFO_FLUSH (0x0001) |
||
3782 | +#define CON_NFI_RST (0x0002) |
||
3783 | +#define CON_NFI_SRD (0x0010) |
||
3784 | + |
||
3785 | +#define CON_NFI_NOB_MASK (0x0060) |
||
3786 | +#define CON_NFI_NOB_SHIFT (5) |
||
3787 | + |
||
3788 | +#define CON_NFI_BRD (0x0100) |
||
3789 | +#define CON_NFI_BWR (0x0200) |
||
3790 | + |
||
3791 | +#define CON_NFI_SEC_MASK (0xF000) |
||
3792 | +#define CON_NFI_SEC_SHIFT (12) |
||
3793 | + |
||
3794 | +/* NFI_ACCCON */ |
||
3795 | +#define ACCCON_SETTING () |
||
3796 | + |
||
3797 | +/* NFI_INTR_EN */ |
||
3798 | +#define INTR_RD_DONE_EN (0x0001) |
||
3799 | +#define INTR_WR_DONE_EN (0x0002) |
||
3800 | +#define INTR_RST_DONE_EN (0x0004) |
||
3801 | +#define INTR_ERASE_DONE_EN (0x0008) |
||
3802 | +#define INTR_BSY_RTN_EN (0x0010) |
||
3803 | +#define INTR_ACC_LOCK_EN (0x0020) |
||
3804 | +#define INTR_AHB_DONE_EN (0x0040) |
||
3805 | +#define INTR_ALL_INTR_DE (0x0000) |
||
3806 | +#define INTR_ALL_INTR_EN (0x007F) |
||
3807 | + |
||
3808 | +/* NFI_INTR */ |
||
3809 | +#define INTR_RD_DONE (0x0001) |
||
3810 | +#define INTR_WR_DONE (0x0002) |
||
3811 | +#define INTR_RST_DONE (0x0004) |
||
3812 | +#define INTR_ERASE_DONE (0x0008) |
||
3813 | +#define INTR_BSY_RTN (0x0010) |
||
3814 | +#define INTR_ACC_LOCK (0x0020) |
||
3815 | +#define INTR_AHB_DONE (0x0040) |
||
3816 | + |
||
3817 | +/* NFI_ADDRNOB */ |
||
3818 | +#define ADDR_COL_NOB_MASK (0x0003) |
||
3819 | +#define ADDR_COL_NOB_SHIFT (0) |
||
3820 | +#define ADDR_ROW_NOB_MASK (0x0030) |
||
3821 | +#define ADDR_ROW_NOB_SHIFT (4) |
||
3822 | + |
||
3823 | +/* NFI_STA */ |
||
3824 | +#define STA_READ_EMPTY (0x00001000) |
||
3825 | +#define STA_ACC_LOCK (0x00000010) |
||
3826 | +#define STA_CMD_STATE (0x00000001) |
||
3827 | +#define STA_ADDR_STATE (0x00000002) |
||
3828 | +#define STA_DATAR_STATE (0x00000004) |
||
3829 | +#define STA_DATAW_STATE (0x00000008) |
||
3830 | + |
||
3831 | +#define STA_NAND_FSM_MASK (0x1F000000) |
||
3832 | +#define STA_NAND_BUSY (0x00000100) |
||
3833 | +#define STA_NAND_BUSY_RETURN (0x00000200) |
||
3834 | +#define STA_NFI_FSM_MASK (0x000F0000) |
||
3835 | +#define STA_NFI_OP_MASK (0x0000000F) |
||
3836 | + |
||
3837 | +/* NFI_FIFOSTA */ |
||
3838 | +#define FIFO_RD_EMPTY (0x0040) |
||
3839 | +#define FIFO_RD_FULL (0x0080) |
||
3840 | +#define FIFO_WR_FULL (0x8000) |
||
3841 | +#define FIFO_WR_EMPTY (0x4000) |
||
3842 | +#define FIFO_RD_REMAIN(x) (0x1F&(x)) |
||
3843 | +#define FIFO_WR_REMAIN(x) ((0x1F00&(x))>>8) |
||
3844 | + |
||
3845 | +/* NFI_ADDRCNTR */ |
||
3846 | +#define ADDRCNTR_CNTR(x) ((0xF000&(x))>>12) |
||
3847 | +#define ADDRCNTR_OFFSET(x) (0x03FF&(x)) |
||
3848 | + |
||
3849 | +/* NFI_LOCK */ |
||
3850 | +#define NFI_LOCK_ON (0x0001) |
||
3851 | + |
||
3852 | +/* NFI_LOCKANOB */ |
||
3853 | +#define PROG_RADD_NOB_MASK (0x7000) |
||
3854 | +#define PROG_RADD_NOB_SHIFT (12) |
||
3855 | +#define PROG_CADD_NOB_MASK (0x0300) |
||
3856 | +#define PROG_CADD_NOB_SHIFT (8) |
||
3857 | +#define ERASE_RADD_NOB_MASK (0x0070) |
||
3858 | +#define ERASE_RADD_NOB_SHIFT (4) |
||
3859 | +#define ERASE_CADD_NOB_MASK (0x0007) |
||
3860 | +#define ERASE_CADD_NOB_SHIFT (0) |
||
3861 | + |
||
3862 | +/******************************************************************************* |
||
3863 | + * ECC Register Definition |
||
3864 | + *******************************************************************************/ |
||
3865 | + |
||
3866 | +#define ECC_ENCCON_REG16 ((volatile P_U16)(NFIECC_BASE+0x0000)) |
||
3867 | +#define ECC_ENCCNFG_REG32 ((volatile P_U32)(NFIECC_BASE+0x0004)) |
||
3868 | +#define ECC_ENCDIADDR_REG32 ((volatile P_U32)(NFIECC_BASE+0x0008)) |
||
3869 | +#define ECC_ENCIDLE_REG32 ((volatile P_U32)(NFIECC_BASE+0x000C)) |
||
3870 | +#define ECC_ENCPAR0_REG32 ((volatile P_U32)(NFIECC_BASE+0x0010)) |
||
3871 | +#define ECC_ENCPAR1_REG32 ((volatile P_U32)(NFIECC_BASE+0x0014)) |
||
3872 | +#define ECC_ENCPAR2_REG32 ((volatile P_U32)(NFIECC_BASE+0x0018)) |
||
3873 | +#define ECC_ENCPAR3_REG32 ((volatile P_U32)(NFIECC_BASE+0x001C)) |
||
3874 | +#define ECC_ENCPAR4_REG32 ((volatile P_U32)(NFIECC_BASE+0x0020)) |
||
3875 | +#define ECC_ENCSTA_REG32 ((volatile P_U32)(NFIECC_BASE+0x0024)) |
||
3876 | +#define ECC_ENCIRQEN_REG16 ((volatile P_U16)(NFIECC_BASE+0x0028)) |
||
3877 | +#define ECC_ENCIRQSTA_REG16 ((volatile P_U16)(NFIECC_BASE+0x002C)) |
||
3878 | + |
||
3879 | +#define ECC_DECCON_REG16 ((volatile P_U16)(NFIECC_BASE+0x0100)) |
||
3880 | +#define ECC_DECCNFG_REG32 ((volatile P_U32)(NFIECC_BASE+0x0104)) |
||
3881 | +#define ECC_DECDIADDR_REG32 ((volatile P_U32)(NFIECC_BASE+0x0108)) |
||
3882 | +#define ECC_DECIDLE_REG16 ((volatile P_U16)(NFIECC_BASE+0x010C)) |
||
3883 | +#define ECC_DECFER_REG16 ((volatile P_U16)(NFIECC_BASE+0x0110)) |
||
3884 | +#define ECC_DECENUM_REG32 ((volatile P_U32)(NFIECC_BASE+0x0114)) |
||
3885 | +#define ECC_DECDONE_REG16 ((volatile P_U16)(NFIECC_BASE+0x0118)) |
||
3886 | +#define ECC_DECEL0_REG32 ((volatile P_U32)(NFIECC_BASE+0x011C)) |
||
3887 | +#define ECC_DECEL1_REG32 ((volatile P_U32)(NFIECC_BASE+0x0120)) |
||
3888 | +#define ECC_DECEL2_REG32 ((volatile P_U32)(NFIECC_BASE+0x0124)) |
||
3889 | +#define ECC_DECEL3_REG32 ((volatile P_U32)(NFIECC_BASE+0x0128)) |
||
3890 | +#define ECC_DECEL4_REG32 ((volatile P_U32)(NFIECC_BASE+0x012C)) |
||
3891 | +#define ECC_DECEL5_REG32 ((volatile P_U32)(NFIECC_BASE+0x0130)) |
||
3892 | +#define ECC_DECIRQEN_REG16 ((volatile P_U16)(NFIECC_BASE+0x0134)) |
||
3893 | +#define ECC_DECIRQSTA_REG16 ((volatile P_U16)(NFIECC_BASE+0x0138)) |
||
3894 | +#define ECC_FDMADDR_REG32 ((volatile P_U32)(NFIECC_BASE+0x013C)) |
||
3895 | +#define ECC_DECFSM_REG32 ((volatile P_U32)(NFIECC_BASE+0x0140)) |
||
3896 | +#define ECC_SYNSTA_REG32 ((volatile P_U32)(NFIECC_BASE+0x0144)) |
||
3897 | +#define ECC_DECNFIDI_REG32 ((volatile P_U32)(NFIECC_BASE+0x0148)) |
||
3898 | +#define ECC_SYN0_REG32 ((volatile P_U32)(NFIECC_BASE+0x014C)) |
||
3899 | + |
||
3900 | +/******************************************************************************* |
||
3901 | + * ECC register definition |
||
3902 | + *******************************************************************************/ |
||
3903 | +/* ECC_ENCON */ |
||
3904 | +#define ENC_EN (0x0001) |
||
3905 | +#define ENC_DE (0x0000) |
||
3906 | + |
||
3907 | +/* ECC_ENCCNFG */ |
||
3908 | +#define ECC_CNFG_ECC4 (0x0000) |
||
3909 | +#define ECC_CNFG_ECC6 (0x0001) |
||
3910 | +#define ECC_CNFG_ECC8 (0x0002) |
||
3911 | +#define ECC_CNFG_ECC10 (0x0003) |
||
3912 | +#define ECC_CNFG_ECC12 (0x0004) |
||
3913 | +#define ECC_CNFG_ECC_MASK (0x00000007) |
||
3914 | + |
||
3915 | +#define ENC_CNFG_NFI (0x0010) |
||
3916 | +#define ENC_CNFG_MODE_MASK (0x0010) |
||
3917 | + |
||
3918 | +#define ENC_CNFG_META6 (0x10300000) |
||
3919 | +#define ENC_CNFG_META8 (0x10400000) |
||
3920 | + |
||
3921 | +#define ENC_CNFG_MSG_MASK (0x1FFF0000) |
||
3922 | +#define ENC_CNFG_MSG_SHIFT (0x10) |
||
3923 | + |
||
3924 | +/* ECC_ENCIDLE */ |
||
3925 | +#define ENC_IDLE (0x0001) |
||
3926 | + |
||
3927 | +/* ECC_ENCSTA */ |
||
3928 | +#define STA_FSM (0x001F) |
||
3929 | +#define STA_COUNT_PS (0xFF10) |
||
3930 | +#define STA_COUNT_MS (0x3FFF0000) |
||
3931 | + |
||
3932 | +/* ECC_ENCIRQEN */ |
||
3933 | +#define ENC_IRQEN (0x0001) |
||
3934 | + |
||
3935 | +/* ECC_ENCIRQSTA */ |
||
3936 | +#define ENC_IRQSTA (0x0001) |
||
3937 | + |
||
3938 | +/* ECC_DECCON */ |
||
3939 | +#define DEC_EN (0x0001) |
||
3940 | +#define DEC_DE (0x0000) |
||
3941 | + |
||
3942 | +/* ECC_ENCCNFG */ |
||
3943 | +#define DEC_CNFG_ECC4 (0x0000) |
||
3944 | +//#define DEC_CNFG_ECC6 (0x0001) |
||
3945 | +//#define DEC_CNFG_ECC12 (0x0002) |
||
3946 | +#define DEC_CNFG_NFI (0x0010) |
||
3947 | +//#define DEC_CNFG_META6 (0x10300000) |
||
3948 | +//#define DEC_CNFG_META8 (0x10400000) |
||
3949 | + |
||
3950 | +#define DEC_CNFG_FER (0x01000) |
||
3951 | +#define DEC_CNFG_EL (0x02000) |
||
3952 | +#define DEC_CNFG_CORRECT (0x03000) |
||
3953 | +#define DEC_CNFG_TYPE_MASK (0x03000) |
||
3954 | + |
||
3955 | +#define DEC_CNFG_EMPTY_EN (0x80000000) |
||
3956 | + |
||
3957 | +#define DEC_CNFG_CODE_MASK (0x1FFF0000) |
||
3958 | +#define DEC_CNFG_CODE_SHIFT (0x10) |
||
3959 | + |
||
3960 | +/* ECC_DECIDLE */ |
||
3961 | +#define DEC_IDLE (0x0001) |
||
3962 | + |
||
3963 | +/* ECC_DECFER */ |
||
3964 | +#define DEC_FER0 (0x0001) |
||
3965 | +#define DEC_FER1 (0x0002) |
||
3966 | +#define DEC_FER2 (0x0004) |
||
3967 | +#define DEC_FER3 (0x0008) |
||
3968 | +#define DEC_FER4 (0x0010) |
||
3969 | +#define DEC_FER5 (0x0020) |
||
3970 | +#define DEC_FER6 (0x0040) |
||
3971 | +#define DEC_FER7 (0x0080) |
||
3972 | + |
||
3973 | +/* ECC_DECENUM */ |
||
3974 | +#define ERR_NUM0 (0x0000000F) |
||
3975 | +#define ERR_NUM1 (0x000000F0) |
||
3976 | +#define ERR_NUM2 (0x00000F00) |
||
3977 | +#define ERR_NUM3 (0x0000F000) |
||
3978 | +#define ERR_NUM4 (0x000F0000) |
||
3979 | +#define ERR_NUM5 (0x00F00000) |
||
3980 | +#define ERR_NUM6 (0x0F000000) |
||
3981 | +#define ERR_NUM7 (0xF0000000) |
||
3982 | + |
||
3983 | +/* ECC_DECDONE */ |
||
3984 | +#define DEC_DONE0 (0x0001) |
||
3985 | +#define DEC_DONE1 (0x0002) |
||
3986 | +#define DEC_DONE2 (0x0004) |
||
3987 | +#define DEC_DONE3 (0x0008) |
||
3988 | +#define DEC_DONE4 (0x0010) |
||
3989 | +#define DEC_DONE5 (0x0020) |
||
3990 | +#define DEC_DONE6 (0x0040) |
||
3991 | +#define DEC_DONE7 (0x0080) |
||
3992 | + |
||
3993 | +/* ECC_DECIRQEN */ |
||
3994 | +#define DEC_IRQEN (0x0001) |
||
3995 | + |
||
3996 | +/* ECC_DECIRQSTA */ |
||
3997 | +#define DEC_IRQSTA (0x0001) |
||
3998 | + |
||
3999 | +#define CHIPVER_ECO_1 (0x8a00) |
||
4000 | +#define CHIPVER_ECO_2 (0x8a01) |
||
4001 | + |
||
4002 | +//#define NAND_PFM |
||
4003 | + |
||
4004 | +/******************************************************************************* |
||
4005 | + * Data Structure Definition |
||
4006 | + *******************************************************************************/ |
||
4007 | +struct mtk_nand_host |
||
4008 | +{ |
||
4009 | + struct nand_chip nand_chip; |
||
4010 | + struct mtd_info *mtd; |
||
4011 | + struct mtk_nand_host_hw *hw; |
||
4012 | +}; |
||
4013 | + |
||
4014 | +struct NAND_CMD |
||
4015 | +{ |
||
4016 | + u32 u4ColAddr; |
||
4017 | + u32 u4RowAddr; |
||
4018 | + u32 u4OOBRowAddr; |
||
4019 | + u8 au1OOB[288]; |
||
4020 | + u8* pDataBuf; |
||
4021 | +#ifdef NAND_PFM |
||
4022 | + u32 pureReadOOB; |
||
4023 | + u32 pureReadOOBNum; |
||
4024 | +#endif |
||
4025 | +}; |
||
4026 | + |
||
4027 | +/* |
||
4028 | + * ECC layout control structure. Exported to userspace for |
||
4029 | + * diagnosis and to allow creation of raw images |
||
4030 | +struct nand_ecclayout { |
||
4031 | + uint32_t eccbytes; |
||
4032 | + uint32_t eccpos[64]; |
||
4033 | + uint32_t oobavail; |
||
4034 | + struct nand_oobfree oobfree[MTD_MAX_OOBFREE_ENTRIES]; |
||
4035 | +}; |
||
4036 | +*/ |
||
4037 | +#define __DEBUG_NAND 1 /* Debug information on/off */ |
||
4038 | + |
||
4039 | +/* Debug message event */ |
||
4040 | +#define DBG_EVT_NONE 0x00000000 /* No event */ |
||
4041 | +#define DBG_EVT_INIT 0x00000001 /* Initial related event */ |
||
4042 | +#define DBG_EVT_VERIFY 0x00000002 /* Verify buffer related event */ |
||
4043 | +#define DBG_EVT_PERFORMANCE 0x00000004 /* Performance related event */ |
||
4044 | +#define DBG_EVT_READ 0x00000008 /* Read related event */ |
||
4045 | +#define DBG_EVT_WRITE 0x00000010 /* Write related event */ |
||
4046 | +#define DBG_EVT_ERASE 0x00000020 /* Erase related event */ |
||
4047 | +#define DBG_EVT_BADBLOCK 0x00000040 /* Badblock related event */ |
||
4048 | +#define DBG_EVT_POWERCTL 0x00000080 /* Suspend/Resume related event */ |
||
4049 | + |
||
4050 | +#define DBG_EVT_ALL 0xffffffff |
||
4051 | + |
||
4052 | +#define DBG_EVT_MASK (DBG_EVT_INIT) |
||
4053 | + |
||
4054 | +#if __DEBUG_NAND |
||
4055 | +#define MSG(evt, fmt, args...) \ |
||
4056 | +do { \ |
||
4057 | + if ((DBG_EVT_##evt) & DBG_EVT_MASK) { \ |
||
4058 | + printk(fmt, ##args); \ |
||
4059 | + } \ |
||
4060 | +} while(0) |
||
4061 | + |
||
4062 | +#define MSG_FUNC_ENTRY(f) MSG(FUC, "<FUN_ENT>: %s\n", __FUNCTION__) |
||
4063 | +#else |
||
4064 | +#define MSG(evt, fmt, args...) do{}while(0) |
||
4065 | +#define MSG_FUNC_ENTRY(f) do{}while(0) |
||
4066 | +#endif |
||
4067 | + |
||
4068 | +#define RAMDOM_READ 1<<0 |
||
4069 | +#define CACHE_READ 1<<1 |
||
4070 | + |
||
4071 | +typedef struct |
||
4072 | +{ |
||
4073 | + u16 id; //deviceid+menuid |
||
4074 | + u32 ext_id; |
||
4075 | + u8 addr_cycle; |
||
4076 | + u8 iowidth; |
||
4077 | + u16 totalsize; |
||
4078 | + u16 blocksize; |
||
4079 | + u16 pagesize; |
||
4080 | + u16 sparesize; |
||
4081 | + u32 timmingsetting; |
||
4082 | + char devciename[14]; |
||
4083 | + u32 advancedmode; // |
||
4084 | +}flashdev_info,*pflashdev_info; |
||
4085 | + |
||
4086 | +/* NAND driver */ |
||
4087 | +#if 0 |
||
4088 | +struct mtk_nand_host_hw { |
||
4089 | + unsigned int nfi_bus_width; /* NFI_BUS_WIDTH */ |
||
4090 | + unsigned int nfi_access_timing; /* NFI_ACCESS_TIMING */ |
||
4091 | + unsigned int nfi_cs_num; /* NFI_CS_NUM */ |
||
4092 | + unsigned int nand_sec_size; /* NAND_SECTOR_SIZE */ |
||
4093 | + unsigned int nand_sec_shift; /* NAND_SECTOR_SHIFT */ |
||
4094 | + unsigned int nand_ecc_size; |
||
4095 | + unsigned int nand_ecc_bytes; |
||
4096 | + unsigned int nand_ecc_mode; |
||
4097 | +}; |
||
4098 | +extern struct mtk_nand_host_hw mt7621_nand_hw; |
||
4099 | +extern u32 CFG_BLOCKSIZE; |
||
4100 | +#endif |
||
4101 | +#endif |
||
4102 | --- a/drivers/mtd/nand/nand_base.c |
||
4103 | +++ b/drivers/mtd/nand/nand_base.c |
||
4104 | @@ -48,7 +48,7 @@ |
||
4105 | #include <linux/mtd/partitions.h> |
||
4106 | #include <linux/of.h> |
||
4107 | |||
4108 | -static int nand_get_device(struct mtd_info *mtd, int new_state); |
||
4109 | +int nand_get_device(struct mtd_info *mtd, int new_state); |
||
4110 | |||
4111 | static int nand_do_write_oob(struct mtd_info *mtd, loff_t to, |
||
4112 | struct mtd_oob_ops *ops); |
||
4113 | @@ -240,7 +240,7 @@ static int check_offs_len(struct mtd_inf |
||
4114 | * |
||
4115 | * Release chip lock and wake up anyone waiting on the device. |
||
4116 | */ |
||
4117 | -static void nand_release_device(struct mtd_info *mtd) |
||
4118 | +void nand_release_device(struct mtd_info *mtd) |
||
4119 | { |
||
4120 | struct nand_chip *chip = mtd_to_nand(mtd); |
||
4121 | |||
4122 | @@ -968,7 +968,7 @@ static void panic_nand_get_device(struct |
||
4123 | * |
||
4124 | * Get the device and lock it for exclusive access |
||
4125 | */ |
||
4126 | -static int |
||
4127 | +int |
||
4128 | nand_get_device(struct mtd_info *mtd, int new_state) |
||
4129 | { |
||
4130 | struct nand_chip *chip = mtd_to_nand(mtd); |
||
4131 | --- /dev/null |
||
4132 | +++ b/drivers/mtd/nand/nand_def.h |
||
4133 | @@ -0,0 +1,123 @@ |
||
4134 | +#ifndef __NAND_DEF_H__ |
||
4135 | +#define __NAND_DEF_H__ |
||
4136 | + |
||
4137 | +#define VERSION "v2.1 Fix AHB virt2phys error" |
||
4138 | +#define MODULE_NAME "# MTK NAND #" |
||
4139 | +#define PROCNAME "driver/nand" |
||
4140 | + |
||
4141 | +#undef TESTTIME |
||
4142 | +//#define __UBOOT_NAND__ 1 |
||
4143 | +#define __KERNEL_NAND__ 1 |
||
4144 | +//#define __PRELOADER_NAND__ 1 |
||
4145 | +//#define PMT 1 |
||
4146 | +//#define _MTK_NAND_DUMMY_DRIVER |
||
4147 | +//#define CONFIG_BADBLOCK_CHECK 1 |
||
4148 | +//#ifdef CONFIG_BADBLOCK_CHECK |
||
4149 | +//#define MTK_NAND_BMT 1 |
||
4150 | +//#endif |
||
4151 | +#define ECC_ENABLE 1 |
||
4152 | +#define MANUAL_CORRECT 1 |
||
4153 | +//#define __INTERNAL_USE_AHB_MODE__ (0) |
||
4154 | +#define SKIP_BAD_BLOCK |
||
4155 | +#define FACT_BBT |
||
4156 | + |
||
4157 | +#ifndef NAND_OTP_SUPPORT |
||
4158 | +#define NAND_OTP_SUPPORT 0 |
||
4159 | +#endif |
||
4160 | + |
||
4161 | +/******************************************************************************* |
||
4162 | + * Macro definition |
||
4163 | + *******************************************************************************/ |
||
4164 | +//#define NFI_SET_REG32(reg, value) (DRV_WriteReg32(reg, DRV_Reg32(reg) | (value))) |
||
4165 | +//#define NFI_SET_REG16(reg, value) (DRV_WriteReg16(reg, DRV_Reg16(reg) | (value))) |
||
4166 | +//#define NFI_CLN_REG32(reg, value) (DRV_WriteReg32(reg, DRV_Reg32(reg) & (~(value)))) |
||
4167 | +//#define NFI_CLN_REG16(reg, value) (DRV_WriteReg16(reg, DRV_Reg16(reg) & (~(value)))) |
||
4168 | + |
||
4169 | +#if defined (__KERNEL_NAND__) |
||
4170 | +#define NFI_SET_REG32(reg, value) \ |
||
4171 | +do { \ |
||
4172 | + g_value = (DRV_Reg32(reg) | (value));\ |
||
4173 | + DRV_WriteReg32(reg, g_value); \ |
||
4174 | +} while(0) |
||
4175 | + |
||
4176 | +#define NFI_SET_REG16(reg, value) \ |
||
4177 | +do { \ |
||
4178 | + g_value = (DRV_Reg16(reg) | (value));\ |
||
4179 | + DRV_WriteReg16(reg, g_value); \ |
||
4180 | +} while(0) |
||
4181 | + |
||
4182 | +#define NFI_CLN_REG32(reg, value) \ |
||
4183 | +do { \ |
||
4184 | + g_value = (DRV_Reg32(reg) & (~(value)));\ |
||
4185 | + DRV_WriteReg32(reg, g_value); \ |
||
4186 | +} while(0) |
||
4187 | + |
||
4188 | +#define NFI_CLN_REG16(reg, value) \ |
||
4189 | +do { \ |
||
4190 | + g_value = (DRV_Reg16(reg) & (~(value)));\ |
||
4191 | + DRV_WriteReg16(reg, g_value); \ |
||
4192 | +} while(0) |
||
4193 | +#endif |
||
4194 | + |
||
4195 | +#define NFI_WAIT_STATE_DONE(state) do{;}while (__raw_readl(NFI_STA_REG32) & state) |
||
4196 | +#define NFI_WAIT_TO_READY() do{;}while (!(__raw_readl(NFI_STA_REG32) & STA_BUSY2READY)) |
||
4197 | + |
||
4198 | + |
||
4199 | +#define NAND_SECTOR_SIZE (512) |
||
4200 | +#define OOB_PER_SECTOR (16) |
||
4201 | +#define OOB_AVAI_PER_SECTOR (8) |
||
4202 | + |
||
4203 | +#ifndef PART_SIZE_BMTPOOL |
||
4204 | +#define BMT_POOL_SIZE (80) |
||
4205 | +#else |
||
4206 | +#define BMT_POOL_SIZE (PART_SIZE_BMTPOOL) |
||
4207 | +#endif |
||
4208 | + |
||
4209 | +#define PMT_POOL_SIZE (2) |
||
4210 | + |
||
4211 | +#define TIMEOUT_1 0x1fff |
||
4212 | +#define TIMEOUT_2 0x8ff |
||
4213 | +#define TIMEOUT_3 0xffff |
||
4214 | +#define TIMEOUT_4 0xffff//5000 //PIO |
||
4215 | + |
||
4216 | + |
||
4217 | +/* temporarity definiation */ |
||
4218 | +#if !defined (__KERNEL_NAND__) |
||
4219 | +#define KERN_INFO |
||
4220 | +#define KERN_WARNING |
||
4221 | +#define KERN_ERR |
||
4222 | +#define PAGE_SIZE (4096) |
||
4223 | +#endif |
||
4224 | +#define AddStorageTrace //AddStorageTrace |
||
4225 | +#define STORAGE_LOGGER_MSG_NAND 0 |
||
4226 | +#define NFI_BASE RALINK_NAND_CTRL_BASE |
||
4227 | +#define NFIECC_BASE RALINK_NANDECC_CTRL_BASE |
||
4228 | + |
||
4229 | +#ifdef __INTERNAL_USE_AHB_MODE__ |
||
4230 | +#define MT65xx_POLARITY_LOW 0 |
||
4231 | +#define MT65XX_PDN_PERI_NFI 0 |
||
4232 | +#define MT65xx_EDGE_SENSITIVE 0 |
||
4233 | +#define MT6575_NFI_IRQ_ID (58) |
||
4234 | +#endif |
||
4235 | + |
||
4236 | +#if defined (__KERNEL_NAND__) |
||
4237 | +#define RALINK_REG(x) (*((volatile u32 *)(x))) |
||
4238 | +#define __virt_to_phys(x) virt_to_phys((volatile void*)x) |
||
4239 | +#else |
||
4240 | +#define CONFIG_MTD_NAND_VERIFY_WRITE (1) |
||
4241 | +#define printk printf |
||
4242 | +#define ra_dbg printf |
||
4243 | +#define BUG() //BUG() |
||
4244 | +#define BUG_ON(x) //BUG_ON() |
||
4245 | +#define NUM_PARTITIONS 1 |
||
4246 | +#endif |
||
4247 | + |
||
4248 | +#define NFI_DEFAULT_ACCESS_TIMING (0x30C77fff) //(0x44333) |
||
4249 | + |
||
4250 | +//uboot only support 1 cs |
||
4251 | +#define NFI_CS_NUM (1) |
||
4252 | +#define NFI_DEFAULT_CS (0) |
||
4253 | + |
||
4254 | +#include "mt6575_typedefs.h" |
||
4255 | + |
||
4256 | +#endif /* __NAND_DEF_H__ */ |
||
4257 | --- /dev/null |
||
4258 | +++ b/drivers/mtd/nand/nand_device_list.h |
||
4259 | @@ -0,0 +1,59 @@ |
||
4260 | +/* Copyright Statement: |
||
4261 | + * |
||
4262 | + * This software/firmware and related documentation ("MediaTek Software") are |
||
4263 | + * protected under relevant copyright laws. The information contained herein |
||
4264 | + * is confidential and proprietary to MediaTek Inc. and/or its licensors. |
||
4265 | + * Without the prior written permission of MediaTek inc. and/or its licensors, |
||
4266 | + * any reproduction, modification, use or disclosure of MediaTek Software, |
||
4267 | + * and information contained herein, in whole or in part, shall be strictly prohibited. |
||
4268 | + */ |
||
4269 | +/* MediaTek Inc. (C) 2010. All rights reserved. |
||
4270 | + * |
||
4271 | + * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES |
||
4272 | + * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE") |
||
4273 | + * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON |
||
4274 | + * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES, |
||
4275 | + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF |
||
4276 | + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT. |
||
4277 | + * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE |
||
4278 | + * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR |
||
4279 | + * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH |
||
4280 | + * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES |
||
4281 | + * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES |
||
4282 | + * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK |
||
4283 | + * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR |
||
4284 | + * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND |
||
4285 | + * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE, |
||
4286 | + * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE, |
||
4287 | + * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO |
||
4288 | + * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. |
||
4289 | + * |
||
4290 | + * The following software/firmware and/or related documentation ("MediaTek Software") |
||
4291 | + * have been modified by MediaTek Inc. All revisions are subject to any receiver's |
||
4292 | + * applicable license agreements with MediaTek Inc. |
||
4293 | + */ |
||
4294 | + |
||
4295 | +#ifndef __NAND_DEVICE_LIST_H__ |
||
4296 | +#define __NAND_DEVICE_LIST_H__ |
||
4297 | + |
||
4298 | +static const flashdev_info gen_FlashTable[]={ |
||
4299 | + {0x20BC, 0x105554, 5, 16, 512, 128, 2048, 64, 0x1123, "EHD013151MA_5", 0}, |
||
4300 | + {0xECBC, 0x005554, 5, 16, 512, 128, 2048, 64, 0x1123, "K524G2GACB_A0", 0}, |
||
4301 | + {0x2CBC, 0x905556, 5, 16, 512, 128, 2048, 64, 0x21044333, "MT29C4G96MAZA", 0}, |
||
4302 | + {0x2CDA, 0x909506, 5, 8, 256, 128, 2048, 64, 0x30C77fff, "MT29F2G08ABAE", 0}, |
||
4303 | + {0xADBC, 0x905554, 5, 16, 512, 128, 2048, 64, 0x10801011, "H9DA4GH4JJAMC", 0}, |
||
4304 | + {0x01F1, 0x801D01, 4, 8, 128, 128, 2048, 64, 0x30C77fff, "S34ML01G100TF", 0}, |
||
4305 | + {0x92F1, 0x8095FF, 4, 8, 128, 128, 2048, 64, 0x30C77fff, "F59L1G81A", 0}, |
||
4306 | + {0xC8D1, 0x809540, 4, 8, 128, 128, 2048, 64, 0x30C77fff, "F59L1G81MA", 0}, |
||
4307 | + {0xC8DA, 0x909544, 5, 8, 256, 128, 2048, 64, 0x30C77fff, "F59L2G81A", 0}, |
||
4308 | + {0xC8DC, 0x909554, 5, 8, 512, 128, 2048, 64, 0x30C77fff, "F59L4G81A", 0}, |
||
4309 | + {0xECD3, 0x519558, 5, 8, 1024, 128, 2048, 64, 0x44333, "K9K8G8000", 0}, |
||
4310 | + {0xC2F1, 0x801DC2, 4, 8, 128, 128, 2048, 64, 0x30C77fff, "MX30LF1G08AA", 0}, |
||
4311 | + {0x98D3, 0x902676, 5, 8, 1024, 256, 4096, 224, 0x00C25332, "TC58NVG3S0F", 0}, |
||
4312 | + {0x01DA, 0x909546, 5, 8, 256, 128, 2048, 128, 0x30C77fff, "S34ML02G200TF", 0}, |
||
4313 | + {0x01DC, 0x909556, 5, 8, 512, 128, 2048, 128, 0x30C77fff, "S34ML04G200TF", 0}, |
||
4314 | + {0x0000, 0x000000, 0, 0, 0, 0, 0, 0, 0, "xxxxxxxxxx", 0}, |
||
4315 | +}; |
||
4316 | + |
||
4317 | + |
||
4318 | +#endif |
||
4319 | --- /dev/null |
||
4320 | +++ b/drivers/mtd/nand/partition.h |
||
4321 | @@ -0,0 +1,115 @@ |
||
4322 | +/* Copyright Statement: |
||
4323 | + * |
||
4324 | + * This software/firmware and related documentation ("MediaTek Software") are |
||
4325 | + * protected under relevant copyright laws. The information contained herein |
||
4326 | + * is confidential and proprietary to MediaTek Inc. and/or its licensors. |
||
4327 | + * Without the prior written permission of MediaTek inc. and/or its licensors, |
||
4328 | + * any reproduction, modification, use or disclosure of MediaTek Software, |
||
4329 | + * and information contained herein, in whole or in part, shall be strictly prohibited. |
||
4330 | + */ |
||
4331 | +/* MediaTek Inc. (C) 2010. All rights reserved. |
||
4332 | + * |
||
4333 | + * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES |
||
4334 | + * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE") |
||
4335 | + * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON |
||
4336 | + * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES, |
||
4337 | + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF |
||
4338 | + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT. |
||
4339 | + * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE |
||
4340 | + * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR |
||
4341 | + * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH |
||
4342 | + * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES |
||
4343 | + * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES |
||
4344 | + * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK |
||
4345 | + * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR |
||
4346 | + * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND |
||
4347 | + * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE, |
||
4348 | + * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE, |
||
4349 | + * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO |
||
4350 | + * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. |
||
4351 | + * |
||
4352 | + * The following software/firmware and/or related documentation ("MediaTek Software") |
||
4353 | + * have been modified by MediaTek Inc. All revisions are subject to any receiver's |
||
4354 | + * applicable license agreements with MediaTek Inc. |
||
4355 | + */ |
||
4356 | + |
||
4357 | +#include <linux/mtd/mtd.h> |
||
4358 | +#include <linux/mtd/rawnand.h> |
||
4359 | +#include <linux/mtd/partitions.h> |
||
4360 | + |
||
4361 | +#define RECONFIG_PARTITION_SIZE 1 |
||
4362 | + |
||
4363 | +#define MTD_BOOT_PART_SIZE 0x80000 |
||
4364 | +#define MTD_CONFIG_PART_SIZE 0x20000 |
||
4365 | +#define MTD_FACTORY_PART_SIZE 0x20000 |
||
4366 | + |
||
4367 | +extern unsigned int CFG_BLOCKSIZE; |
||
4368 | +#define LARGE_MTD_BOOT_PART_SIZE (CFG_BLOCKSIZE<<2) |
||
4369 | +#define LARGE_MTD_CONFIG_PART_SIZE (CFG_BLOCKSIZE<<2) |
||
4370 | +#define LARGE_MTD_FACTORY_PART_SIZE (CFG_BLOCKSIZE<<1) |
||
4371 | + |
||
4372 | +/*=======================================================================*/ |
||
4373 | +/* NAND PARTITION Mapping */ |
||
4374 | +/*=======================================================================*/ |
||
4375 | +//#ifdef CONFIG_MTD_PARTITIONS |
||
4376 | +static struct mtd_partition g_pasStatic_Partition[] = { |
||
4377 | + { |
||
4378 | + name: "ALL", |
||
4379 | + size: MTDPART_SIZ_FULL, |
||
4380 | + offset: 0, |
||
4381 | + }, |
||
4382 | + /* Put your own partition definitions here */ |
||
4383 | + { |
||
4384 | + name: "Bootloader", |
||
4385 | + size: MTD_BOOT_PART_SIZE, |
||
4386 | + offset: 0, |
||
4387 | + }, { |
||
4388 | + name: "Config", |
||
4389 | + size: MTD_CONFIG_PART_SIZE, |
||
4390 | + offset: MTDPART_OFS_APPEND |
||
4391 | + }, { |
||
4392 | + name: "Factory", |
||
4393 | + size: MTD_FACTORY_PART_SIZE, |
||
4394 | + offset: MTDPART_OFS_APPEND |
||
4395 | +#ifdef CONFIG_RT2880_ROOTFS_IN_FLASH |
||
4396 | + }, { |
||
4397 | + name: "Kernel", |
||
4398 | + size: MTD_KERN_PART_SIZE, |
||
4399 | + offset: MTDPART_OFS_APPEND, |
||
4400 | + }, { |
||
4401 | + name: "RootFS", |
||
4402 | + size: MTD_ROOTFS_PART_SIZE, |
||
4403 | + offset: MTDPART_OFS_APPEND, |
||
4404 | +#ifdef CONFIG_ROOTFS_IN_FLASH_NO_PADDING |
||
4405 | + }, { |
||
4406 | + name: "Kernel_RootFS", |
||
4407 | + size: MTD_KERN_PART_SIZE + MTD_ROOTFS_PART_SIZE, |
||
4408 | + offset: MTD_BOOT_PART_SIZE + MTD_CONFIG_PART_SIZE + MTD_FACTORY_PART_SIZE, |
||
4409 | +#endif |
||
4410 | +#else //CONFIG_RT2880_ROOTFS_IN_RAM |
||
4411 | + }, { |
||
4412 | + name: "Kernel", |
||
4413 | + size: 0x10000, |
||
4414 | + offset: MTDPART_OFS_APPEND, |
||
4415 | +#endif |
||
4416 | +#ifdef CONFIG_DUAL_IMAGE |
||
4417 | + }, { |
||
4418 | + name: "Kernel2", |
||
4419 | + size: MTD_KERN2_PART_SIZE, |
||
4420 | + offset: MTD_KERN2_PART_OFFSET, |
||
4421 | +#ifdef CONFIG_RT2880_ROOTFS_IN_FLASH |
||
4422 | + }, { |
||
4423 | + name: "RootFS2", |
||
4424 | + size: MTD_ROOTFS2_PART_SIZE, |
||
4425 | + offset: MTD_ROOTFS2_PART_OFFSET, |
||
4426 | +#endif |
||
4427 | +#endif |
||
4428 | + } |
||
4429 | + |
||
4430 | +}; |
||
4431 | + |
||
4432 | +#define NUM_PARTITIONS ARRAY_SIZE(g_pasStatic_Partition) |
||
4433 | +extern int part_num; // = NUM_PARTITIONS; |
||
4434 | +//#endif |
||
4435 | +#undef RECONFIG_PARTITION_SIZE |
||
4436 | + |