tizen 2.4 release
[kernel/u-boot-tm1.git] / drivers / mtd / nand / tiger_nand.c
1 /* linux/drivers/mtd/nand/tiger_nand.c\r
2  *\r
3  * Copyright (c) 2012 Spreadtrun.\r
4  *\r
5  * Spreadtrun NAND driver\r
6 \r
7  * This program is free software; you can redistribute it and/or modify\r
8  * it under the terms of the GNU General Public License as published by\r
9  * the Free Software Foundation; either version 2 of the License, or\r
10  * (at your option) any later version.\r
11  *\r
12  * This program is distributed in the hope that it will be useful,\r
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
15  * GNU General Public License for more details.\r
16  *\r
17  * You should have received a copy of the GNU General Public License\r
18  * along with this program; if not, write to the Free Software\r
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
20 */\r
21 #include <common.h>\r
22 #include <config.h>\r
23 #include <asm/arch/bits.h>\r
24 //#include <asm/arch/chip_drv_config_extern.h>\r
25 #include <asm/arch/sprd_nfc_reg_v2.h>\r
26 #include <asm/arch/regs_cpc.h>\r
27 #include <nand.h>\r
28 #include <asm/io.h>\r
29 #include <linux/mtd/nand.h>\r
30 #include <asm/arch/pin_reg_v3.h>\r
31 //#define NAND_DBG\r
32 #ifdef CONFIG_NAND_SPL\r
33 #define printf(arg...) do{}while(0)\r
34 #endif\r
35 #ifdef NAND_DBG\r
36 #define printf(arg...) do{}while(0)\r
37 #endif\r
38 \r
39 /* 2 bit correct, sc8810 support 1, 2, 4, 8, 12,14, 24 */\r
40 #define CONFIG_SYS_NAND_ECC_MODE        2\r
41 /* Number of ECC bytes per OOB - S3C6400 calculates 4 bytes ECC in 1-bit mode */\r
42 #define CONFIG_SYS_NAND_ECCBYTES        4\r
43 /* Size of the block protected by one OOB (Spare Area in Samsung terminology) */\r
44 #define CONFIG_SYS_NAND_ECCSIZE 512\r
45 \r
46 #define CONFIG_SYS_NAND_5_ADDR_CYCLE    5\r
47 \r
48 \r
49 #define NFC_MC_ICMD_ID  (0xCD)\r
50 #define NFC_MC_ADDR_ID  (0x0A)\r
51 #define NFC_MC_WRB0_ID  (0xB0)\r
52 #define NFC_MC_WRB1_ID  (0xB1)\r
53 #define NFC_MC_MRDT_ID  (0xD0)\r
54 #define NFC_MC_MWDT_ID  (0xD1)\r
55 #define NFC_MC_SRDT_ID  (0xD2)\r
56 #define NFC_MC_SWDT_ID  (0xD3)\r
57 #define NFC_MC_IDST_ID  (0xDD)\r
58 #define NFC_MC_CSEN_ID  (0xCE)\r
59 #define NFC_MC_NOP_ID   (0xF0)\r
60 #define NFC_MC_DONE_ID  (0xFF)\r
61 #define NFC_MAX_CHIP    1\r
62 #define NFC_TIMEOUT_VAL         0x1000000\r
63 \r
64 #define NAND_MC_CMD(x)  (uint16_t)(((x & 0xff) << 8) | NFC_MC_ICMD_ID)\r
65 #define NAND_MC_ADDR(x) (uint16_t)(((x & 0xff) << 8) | (NFC_MC_ADDR_ID << 4))\r
66 #define NAND_MC_WRB0(x) (uint16_t)(NFC_MC_WRB0_ID)\r
67 #define NAND_MC_MRDT    (uint16_t)(NFC_MC_MRDT_ID)\r
68 #define NAND_MC_MWDT    (uint16_t)(NFC_MC_MWDT_ID)\r
69 #define NAND_MC_SRDT    (uint16_t)(NFC_MC_SRDT_ID)\r
70 #define NAND_MC_SWDT    (uint16_t)(NFC_MC_SWDT_ID)\r
71 #define NAND_MC_IDST(x) (uint16_t)((NFC_MC_IDST_ID) | ((x -1) << 8))\r
72 #define NAND_MC_NOP(x)  (uint16_t)(((x & 0xff) << 8) | NFC_MC_NOP_ID)\r
73 \r
74 #define NAND_MC_BUFFER_SIZE (24)\r
75 \r
76 static int mtderasesize = 0;\r
77 static int mtdwritesize = 0;\r
78 static int mtdoobsize = 0;\r
79 \r
80 #define mtd_to_tiger(m) (&g_tiger)\r
81 struct sprd_tiger_nand_param {\r
82         uint8_t id[5];\r
83         uint8_t bus_width;\r
84         uint8_t a_cycles;\r
85         uint8_t sct_pg; //sector per page\r
86         uint8_t oob_size; /* oob size per sector*/\r
87         uint8_t ecc_pos; /* oob size per sector*/\r
88         uint8_t info_pos; /* oob size per sector*/\r
89         uint8_t info_size; /* oob size per sector*/\r
90         uint8_t eccbit; /* ecc level per eccsize */\r
91         uint16_t eccsize; /*bytes per sector for ecc calcuate once time */\r
92         uint8_t ace_ns; /* ALE, CLE end of delay timing, unit: ns */\r
93         uint8_t rwl_ns; /* WE, RE, IO, pulse  timing, unit: ns */\r
94         uint8_t rwh_ns; /* WE, RE, IO, high hold  timing, unit: ns */\r
95 };\r
96 struct sprd_tiger_nand_info {\r
97         struct mtd_info *mtd;\r
98         struct nand_chip *nand;\r
99         struct device *pdev;\r
100         struct sprd_tiger_nand_param *param;\r
101         uint32_t chip; //chip index\r
102         uint32_t page; //page address\r
103         uint16_t column; //column address\r
104         uint16_t oob_size;\r
105         uint16_t m_size; //main part size per sector\r
106         uint16_t s_size; //oob size per sector\r
107         uint8_t a_cycles;//address cycles, 3, 4, 5\r
108         uint8_t sct_pg; //sector per page\r
109         uint8_t info_pos;\r
110         uint8_t info_size;\r
111         uint8_t ecc_mode;//0-1bit, 1-2bit, 2-4bit, 3-8bit,4-12bit,5-16bit,6-24bit\r
112         uint8_t ecc_pos; // ecc postion\r
113         uint8_t wp_en; //write protect enable\r
114         uint16_t write_size;\r
115         uint16_t page_per_bl;//page per block\r
116         uint16_t  buf_head;\r
117         uint16_t _buf_tail;\r
118         uint8_t ins_num;//instruction number\r
119         uint32_t ins[NAND_MC_BUFFER_SIZE >> 1]; \r
120 };\r
121 static void sprd_tiger_nand_read_id(struct sprd_tiger_nand_info *tiger, uint32 *buf);\r
122 static void sprd_tiger_nand_reset(struct sprd_tiger_nand_info *tiger);\r
123 static int sprd_tiger_nand_wait_finish(struct sprd_tiger_nand_info *tiger);\r
124 //gloable variable \r
125 static struct nand_ecclayout sprd_tiger_nand_oob_default = {\r
126         .eccbytes = 0,\r
127         .eccpos = {0},\r
128         .oobfree = {\r
129                 {.offset = 2,\r
130                  .length = 46}}\r
131 };\r
132 struct sprd_tiger_nand_info g_tiger = {0};\r
133 //save the data read by read_byte and read_word api interface functon\r
134 static __attribute__((aligned(4))) uint8_t  s_oob_data[NAND_MAX_OOBSIZE]; \r
135 static uint32_t sprd_tiger_reg_read(uint32_t addr)\r
136 {\r
137         return readl(addr);\r
138 }\r
139 static void sprd_tiger_reg_write(uint32_t addr, uint32_t val)\r
140 {\r
141         writel(val, addr);\r
142 }\r
143 static void sprd_tiger_reg_or(uint32_t addr, uint32_t val)\r
144 {\r
145         sprd_tiger_reg_write(addr, sprd_tiger_reg_read(addr) | val);\r
146 }\r
147 static void sprd_tiger_reg_and(uint32_t addr, uint32_t mask)\r
148 {\r
149         sprd_tiger_reg_write(addr, sprd_tiger_reg_read(addr) & mask);\r
150 }\r
151 static void sprd_tiger_nand_int_clr(uint32_t bit_clear)\r
152 {\r
153         sprd_tiger_reg_write(NFC_INT_REG, bit_clear);\r
154 }\r
155 unsigned int ecc_mode_convert(uint32_t mode)\r
156 {\r
157         uint32_t mode_m;\r
158         switch(mode)\r
159         {\r
160         case 1:\r
161                 mode_m = 0;\r
162                 break;\r
163         case 2:\r
164                 mode_m = 1;\r
165                 break;\r
166         case 4:\r
167                 mode_m = 2;\r
168                 break;\r
169         case 8:\r
170                 mode_m = 3;\r
171                 break;\r
172         case 12:\r
173                 mode_m = 4;\r
174                 break;\r
175         case 16:\r
176                 mode_m = 5;\r
177                 break;\r
178         case 24:\r
179                 mode_m = 6;\r
180                 break;\r
181         default:\r
182                 mode_m = 0;\r
183                 break;\r
184         }\r
185         return mode_m;\r
186 }\r
187 /*spare info must be align to ecc pos, info_pos + info_size = ecc_pos, \r
188  *the hardware must be config info_size and info_pos when ecc enable,and the ecc_info size can't be zero,\r
189  *to simplify the nand_param_tb, the info is align with ecc and ecc at the last postion in one sector\r
190 */\r
191 static struct sprd_tiger_nand_param sprd_tiger_nand_param_tb[] = {\r
192         {{0xec, 0xbc, 0x00,0x55, 0x54},         1,      5,      4,      16,     12,     11,     1,      2,      512, 5, 21, 10},\r
193         {{0xec, 0xbc, 0x00,0x6A, 0x56},         1,      5,      8,      16,     9,      8,      1,      4,      512, 5, 21, 10},\r
194         {{0xad, 0xbc, 0x90,0x55, 0x54},         1,      5,      4,      16,     12,     11,     1,      2,      512, 10, 25, 15},\r
195 };\r
196 \r
197 #ifndef CONFIG_NAND_SPL\r
198 static void tiger_set_timing_config(struct sprd_tiger_nand_info * tiger, uint32_t nfc_clk_MHz){\r
199         int index, array;\r
200         uint8_t id_buf[8];\r
201         uint32_t reg_val, temp_val;\r
202         struct sprd_tiger_nand_param * param;\r
203 \r
204         /* read id */\r
205         sprd_tiger_nand_read_id(tiger, (uint32 *)id_buf);\r
206 \r
207         /* get timing para */\r
208         array = ARRAY_SIZE(sprd_tiger_nand_param_tb);\r
209         for (index = 0; index < array; index ++) {\r
210                 param = sprd_tiger_nand_param_tb + index;\r
211                 if ((param->id[0] == id_buf[0])\r
212                         && (param->id[1] == id_buf[1])\r
213                         && (param->id[2] == id_buf[2])\r
214                         && (param->id[3] == id_buf[3])\r
215                         && (param->id[4] == id_buf[4]))\r
216                         break;\r
217         }\r
218 \r
219         if (index < array) {\r
220                 reg_val = 0;\r
221 \r
222                 /* get acs value : 0 ns */\r
223                 reg_val |= ((2 & 0x1F) << NFC_ACS_OFFSET);\r
224 \r
225                 /* get ace value + 6ns read delay time, and rwl added */\r
226                 temp_val = (param->ace_ns + 6)* nfc_clk_MHz / 1000;\r
227                 if (((param->ace_ns * nfc_clk_MHz) % 1000)  != 0) {\r
228                         temp_val++;\r
229                 }\r
230                 reg_val |= ((temp_val & 0x1F) << NFC_ACE_OFFSET);\r
231 \r
232                 /* get rws value : 20 ns */\r
233                 temp_val = 20 * nfc_clk_MHz / 1000;\r
234                 if (((param->ace_ns * nfc_clk_MHz) % 1000)  != 0) {\r
235                         temp_val++;\r
236                 }\r
237                 reg_val |= ((temp_val & 0x3F) << NFC_RWS_OFFSET);\r
238 \r
239                 /* get rws value : 0 ns */\r
240                 reg_val |= ((2 & 0x1F) << NFC_RWE_OFFSET);\r
241 \r
242                 /* get rwh value */\r
243                 temp_val = (param->rwh_ns + 6) * nfc_clk_MHz / 1000;\r
244                 if (((param->ace_ns * nfc_clk_MHz) % 1000)  != 0) {\r
245                         temp_val++;\r
246                 }\r
247                 reg_val |= ((temp_val & 0x1F) << NFC_RWH_OFFSET);\r
248 \r
249                 /* get rwl value, 6 is read delay time*/\r
250                 temp_val = (param->rwl_ns + 6) * nfc_clk_MHz / 1000;\r
251                 if (((param->ace_ns * nfc_clk_MHz) % 1000)  != 0) {\r
252                         temp_val++;\r
253                 }\r
254                 reg_val |= (temp_val & 0x3F);\r
255 \r
256                 printf("nand timing val: 0x%x\n\r", reg_val);\r
257 \r
258                 sprd_tiger_reg_write(NFC_TIMING_REG, reg_val);\r
259         }\r
260 }\r
261 #endif\r
262 \r
263 #ifdef CONFIG_NAND_SPL\r
264 struct sprd_tiger_boot_header_info {\r
265         uint32_t check_sum;\r
266         uint32_t sct_size; //\r
267         uint32_t acycle; // 3, 4, 5\r
268         uint32_t bus_width; //0 ,1\r
269         uint32_t spare_size; //spare part sise for one sector\r
270         uint32_t ecc_mode; //0--1bit, 1--2bit,2--4bit,3--8bit,4--12bit, 5--16bit, 6--24bit\r
271         uint32_t ecc_pos; // ecc postion at spare part\r
272         uint32_t sct_per_page; //sector per page\r
273         uint32_t info_pos;\r
274         uint32_t info_size;\r
275         uint32_t magic_num; //0xaa55a5a5        \r
276         uint32_t ecc_value[11];\r
277 };\r
278 void boad_nand_param_init(struct sprd_tiger_nand_info *tiger, struct nand_chip *chip, uint8 *id)\r
279 {\r
280         int extid;\r
281         uint32_t writesize;\r
282         uint32_t oobsize;\r
283         uint32_t erasesize;\r
284         uint32_t busw;\r
285         \r
286         /* The 4th id byte is the important one */\r
287         extid = id[3];\r
288         writesize = 1024 << (extid & 0x3);\r
289         extid >>= 2;\r
290         /* Calc oobsize */\r
291         oobsize = (8 << (extid & 0x01)) * (writesize >> 9);\r
292         extid >>= 2;\r
293         /* Calc blocksize. Blocksize is multiples of 64KiB */\r
294         erasesize = (64 * 1024) << (extid & 0x03);\r
295         extid >>= 2;\r
296         /* Get buswidth information */\r
297         busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0;\r
298         tiger->write_size = writesize;\r
299         tiger->m_size =CONFIG_SYS_NAND_ECCSIZE;\r
300         tiger->sct_pg = writesize / CONFIG_SYS_NAND_ECCSIZE;\r
301         tiger->s_size = oobsize / tiger->sct_pg;\r
302         tiger->ecc_mode = ecc_mode_convert(CONFIG_SYS_NAND_ECC_MODE);\r
303         tiger->ecc_pos = tiger->s_size - ((14 * CONFIG_SYS_NAND_ECC_MODE + 7) / 8);\r
304         tiger->info_pos = tiger->ecc_pos - 1;\r
305         tiger->info_size = 1;\r
306         tiger->page_per_bl = erasesize / tiger->write_size;\r
307         tiger->a_cycles = CONFIG_SYS_NAND_5_ADDR_CYCLE;\r
308         if(NAND_BUSWIDTH_16 == busw)\r
309         {\r
310                 chip->options |= NAND_BUSWIDTH_16;\r
311         }\r
312         else\r
313         {\r
314                 chip->options &= ~NAND_BUSWIDTH_16;\r
315         }\r
316 }\r
317 /*\r
318  * because the tiger firmware use the nand identify process\r
319  * and the data at the header of nand_spl is the nand param used at nand read and write,\r
320  * so in nand_spl, don't need read the id or use the onfi spec to calculate the nand param,\r
321  * just use the param at the nand_spl header instead of\r
322  */\r
323 void nand_hardware_config(struct mtd_info *mtd,struct nand_chip *chip)\r
324 {\r
325         struct sprd_tiger_nand_info *tiger = mtd_to_tiger(mtd);\r
326         struct sprd_tiger_boot_header_info *header;\r
327         int index;\r
328         int array;\r
329         struct sprd_tiger_nand_param * param;\r
330         uint8 *id;\r
331         sprd_tiger_nand_reset(tiger);\r
332         sprd_tiger_nand_read_id(tiger, (uint32 *)s_oob_data);\r
333         boad_nand_param_init(tiger, tiger->nand, s_oob_data);\r
334         id = s_oob_data;\r
335 #if 1\r
336         array = ARRAY_SIZE(sprd_tiger_nand_param_tb);\r
337         for (index = 0; index < array; index ++) {\r
338                 param = sprd_tiger_nand_param_tb + index;\r
339                 if ((param->id[0] == id[0]) \r
340                         && (param->id[1] == id[1]) \r
341                         && (param->id[2] == id[2]) \r
342                         && (param->id[3] == id[3]) \r
343                         && (param->id[4] == id[4]))\r
344                         break;\r
345         }\r
346         if (index < array) {\r
347                 tiger->ecc_mode = ecc_mode_convert(param->eccbit);\r
348                 tiger->m_size = param->eccsize;\r
349                 tiger->s_size = param->oob_size;\r
350                 tiger->a_cycles = param->a_cycles;\r
351                 tiger->sct_pg = param->sct_pg;\r
352                 tiger->info_pos = param->info_pos;\r
353                 tiger->info_size = param->info_size;\r
354                 tiger->write_size = tiger->m_size * tiger->sct_pg;\r
355                 tiger->ecc_pos = param->ecc_pos;\r
356                 if(param->bus_width)\r
357                 {\r
358                         chip->options |= NAND_BUSWIDTH_16;\r
359                 }\r
360                 else\r
361                 {\r
362                         chip->options &= ~NAND_BUSWIDTH_16;\r
363                 }\r
364                 mtd->writesize = tiger->write_size;\r
365                 mtd->oobsize = tiger->s_size * tiger->sct_pg;\r
366                 tiger->nand=chip;\r
367         }\r
368         mtd->writesize = tiger->write_size;\r
369         mtd->oobsize = tiger->s_size * tiger->sct_pg;\r
370         mtd->erasesize = tiger->page_per_bl * tiger->write_size;\r
371 #else   \r
372         header = (struct sprd_tiger_boot_header_info *)0x400000000;\r
373         tiger->ecc_mode = header->ecc_mode;\r
374         tiger->m_size = header->sct_size;\r
375         tiger->s_size = header->spare_size;\r
376         tiger->a_cycles = header->acycle;\r
377         tiger->sct_pg = header->sct_per_page;\r
378         tiger->info_pos = header->info_pos;\r
379         tiger->info_size = header->info_size;\r
380         tiger->write_size = tiger->m_size * tiger->sct_pg;\r
381         if(header->bus_width)\r
382         {\r
383                 chip->options |= NAND_BUSWIDTH_16;\r
384         }\r
385         else\r
386         {\r
387                 chip->options &= ~NAND_BUSWIDTH_16;\r
388         }\r
389         mtd->writesize = tiger->write_size;\r
390         mtd->oobsize = tiger->s_size * tiger->sct_pg;\r
391 #endif  \r
392 }\r
393 #else\r
394 static void sprd_tiger_nand_ecc_layout_gen(struct sprd_tiger_nand_info *tiger, struct sprd_tiger_nand_param *param, struct nand_ecclayout *layout)\r
395 {\r
396         uint32_t sct = 0;\r
397         uint32_t i = 0;\r
398         uint32_t offset;\r
399         uint32_t used_len ; //one sector ecc data size(byte)\r
400         uint32_t eccbytes = 0; //one page ecc data size(byte)\r
401         uint32_t oobfree_len = 0;\r
402         used_len = (14 * param->eccbit + 7) / 8 + param->info_size;\r
403         if(param->sct_pg > ARRAY_SIZE(layout->oobfree))\r
404         {\r
405                 while(1);\r
406         }\r
407         for(sct = 0; sct < param->sct_pg; sct++)\r
408         {\r
409                 //offset = (oob_size * sct) + ecc_pos;\r
410                 //for(i = 0; i < ecc_len; i++)\r
411                 offset = (param->oob_size * sct) + param->info_pos;\r
412                 for(i = 0; i < used_len; i++)\r
413                 {\r
414                         layout->eccpos[eccbytes++] = offset + i;\r
415                 }\r
416                 layout->oobfree[sct].offset = param->oob_size * sct;\r
417                 layout->oobfree[sct].length = param->oob_size - used_len ;\r
418                 oobfree_len += param->oob_size - used_len;\r
419         }\r
420         //for bad mark postion\r
421         layout->oobfree[0].offset = 2;\r
422         layout->oobfree[0].length = param->oob_size - used_len - 2;\r
423         oobfree_len -= 2;\r
424         layout->eccbytes = used_len * param->sct_pg;\r
425 }\r
426 void nand_hardware_config(struct mtd_info *mtd, struct nand_chip *chip, u8 id[5])\r
427 {\r
428         int index;\r
429         int array;\r
430         struct sprd_tiger_nand_param * param;\r
431         struct sprd_tiger_nand_info *tiger = mtd_to_tiger(mtd);\r
432         \r
433         array = ARRAY_SIZE(sprd_tiger_nand_param_tb);\r
434         for (index = 0; index < array; index ++) {\r
435                 param = sprd_tiger_nand_param_tb + index;\r
436                 if ((param->id[0] == id[0]) \r
437                         && (param->id[1] == id[1]) \r
438                         && (param->id[2] == id[2]) \r
439                         && (param->id[3] == id[3]) \r
440                         && (param->id[4] == id[4]))\r
441                         break;\r
442         }\r
443         if (index < array) {\r
444                 //save the param config\r
445                 tiger->ecc_mode = ecc_mode_convert(param->eccbit);\r
446                 tiger->m_size = param->eccsize;\r
447                 tiger->s_size = param->oob_size;\r
448                 tiger->a_cycles = param->a_cycles;\r
449                 tiger->sct_pg = param->sct_pg;\r
450                 tiger->info_pos = param->info_pos;\r
451                 tiger->info_size = param->info_size;\r
452                 tiger->write_size = tiger->m_size * tiger->sct_pg;\r
453                 tiger->ecc_pos = param->ecc_pos;\r
454                 chip->eccbitmode = param->eccbit;\r
455                 chip->ecc.bytes  = (param->eccbit*14+7)/8;\r
456                 //tiger->bus_width = param->bus_width;\r
457                 if(param->bus_width)\r
458                 {\r
459                         chip->options |= NAND_BUSWIDTH_16;\r
460                 }\r
461                 else\r
462                 {\r
463                         chip->options &= ~NAND_BUSWIDTH_16;\r
464                 }\r
465                 tiger->param = param;\r
466                 //update the mtd and nand default param after nand scan\r
467                 mtd->writesize = tiger->write_size;\r
468                 mtd->oobsize = tiger->s_size * tiger->sct_pg;\r
469                 /* Calculate the address shift from the page size */\r
470                 chip->page_shift = ffs(mtd->writesize) - 1;\r
471                 /* Convert chipsize to number of pages per chip -1. */\r
472                 chip->pagemask = (chip->chipsize >> chip->page_shift) - 1;\r
473                 sprd_tiger_nand_ecc_layout_gen(tiger, param, &sprd_tiger_nand_oob_default);\r
474                 chip->ecc.layout = &sprd_tiger_nand_oob_default;\r
475                 tiger->mtd = mtd;\r
476         }\r
477         else {\r
478                 int steps;\r
479                 struct sprd_tiger_nand_param  param1;\r
480                 \r
481                 //save the param config\r
482                 steps = mtd->writesize / CONFIG_SYS_NAND_ECCSIZE;\r
483                 tiger->ecc_mode = ecc_mode_convert(CONFIG_SYS_NAND_ECC_MODE);\r
484                 tiger->m_size = CONFIG_SYS_NAND_ECCSIZE;\r
485                 tiger->s_size = mtd->oobsize / steps;\r
486                 tiger->a_cycles = mtd->writesize / CONFIG_SYS_NAND_ECCSIZE;\r
487                 tiger->sct_pg = steps;\r
488                 tiger->info_pos = tiger->s_size - CONFIG_SYS_NAND_ECCBYTES - 1;\r
489                 tiger->info_size = 1;\r
490                 tiger->write_size = mtd->writesize;\r
491                 tiger->ecc_pos = tiger->s_size - CONFIG_SYS_NAND_ECCBYTES;\r
492                 param1.sct_pg = tiger->sct_pg;\r
493                 param1.info_pos = tiger->info_pos;\r
494                 param1.info_size = tiger->info_size;\r
495                 param1.oob_size = tiger->s_size;\r
496                 param1.eccbit = CONFIG_SYS_NAND_ECC_MODE;\r
497                 param1.eccsize = tiger->s_size;\r
498                 \r
499                 if(chip->chipsize > (128 << 20)) {\r
500                         tiger->a_cycles = 5;\r
501                 }\r
502                 else {\r
503                         tiger->a_cycles = 4;\r
504                 }\r
505                 sprd_tiger_nand_ecc_layout_gen(tiger, &param1, &sprd_tiger_nand_oob_default);\r
506                 chip->ecc.layout = &sprd_tiger_nand_oob_default;\r
507                 tiger->mtd = mtd;\r
508         }\r
509         tiger->mtd = mtd;\r
510 }\r
511 \r
512 typedef struct {\r
513         uint8_t *m_buf;\r
514         uint8_t *s_buf;\r
515         uint8_t m_sct;\r
516         uint8_t s_sct;\r
517         uint8_t dir; //if dir is 0, read dadta from NFC buffer, if 1, write data to NFC buffer\r
518         uint16_t m_size;\r
519         uint16_t s_size;\r
520 } sprd_tiger_nand_data_param;\r
521 static unsigned int sprd_tiger_data_trans(sprd_tiger_nand_data_param *param)\r
522 {\r
523         uint32_t cfg0 = 0;\r
524         uint32_t cfg1 = 0;\r
525         uint32_t cfg2 = 0;\r
526         cfg0 = NFC_ONLY_MST_MODE | MAIN_SPAR_APT | NFC_WPN;\r
527         if(param->dir)\r
528         {\r
529                 cfg0 |= NFC_RW;\r
530         }\r
531         if(param->m_sct != 0)\r
532         {\r
533                 cfg0 |= (param->m_sct - 1) << SECTOR_NUM_OFFSET;\r
534                 cfg0 |= MAIN_USE;\r
535                 cfg1 |= (param->m_size - 1);\r
536                 sprd_tiger_reg_write(NFC_MAIN_ADDR_REG, (uint32_t)param->m_buf);\r
537         }\r
538         if(param->s_sct != 0)\r
539         {\r
540                 cfg0 |= SPAR_USE;\r
541                 cfg1 |= (param->s_size - 1) << SPAR_SIZE_OFFSET;\r
542                 cfg2 |= (param->s_sct - 1) << SPAR_SECTOR_NUM_OFFSET;\r
543                 sprd_tiger_reg_write(NFC_SPAR_ADDR_REG, (uint32_t)param->s_buf);\r
544         }\r
545         sprd_tiger_reg_write(NFC_CFG0_REG, cfg0);\r
546         sprd_tiger_reg_write(NFC_CFG1_REG, cfg1);\r
547         sprd_tiger_reg_write(NFC_CFG2_REG, cfg2);\r
548         sprd_tiger_nand_int_clr(INT_STSMCH_CLR | INT_WP_CLR | INT_TO_CLR | INT_DONE_CLR);//clear all interrupt\r
549         sprd_tiger_reg_write(NFC_START_REG, NFC_START);\r
550         sprd_tiger_nand_wait_finish(&g_tiger);\r
551 }\r
552 void sprd_ecc_ctrl(struct sprd_ecc_param *param, uint32_t dir)\r
553 {\r
554         uint32_t cfg0 = 0;\r
555         uint32_t cfg1 = 0;\r
556         uint32_t cfg2 = 0;\r
557         cfg0 = NFC_ONLY_ECC_MODE | MAIN_SPAR_APT;\r
558         if(dir)\r
559         {\r
560                 cfg0 |= NFC_RW;\r
561         }\r
562         cfg1 |=(param->sinfo_size - 1) << SPAR_INFO_SIZE_OFFSET;\r
563         cfg1 |=(param->sp_size - 1) << SPAR_SIZE_OFFSET;\r
564         cfg1 |= (param->m_size - 1);\r
565         \r
566         cfg2 |= (param->sinfo_pos)<< SPAR_INFO_POS_OFFSET;\r
567         cfg2 |= ecc_mode_convert(param->mode) << ECC_MODE_OFFSET;\r
568         cfg2 |= param->ecc_pos;\r
569         sprd_tiger_reg_write(NFC_CFG0_REG, cfg0);\r
570         sprd_tiger_reg_write(NFC_CFG1_REG, cfg1);\r
571         sprd_tiger_reg_write(NFC_CFG2_REG, cfg2);\r
572         sprd_tiger_nand_int_clr(INT_STSMCH_CLR | INT_WP_CLR | INT_TO_CLR | INT_DONE_CLR);//clear all interrupt\r
573         sprd_tiger_reg_write(NFC_START_REG, NFC_START);\r
574         sprd_tiger_nand_wait_finish(&g_tiger);\r
575 }\r
576 unsigned int sprd_ecc_encode(struct sprd_ecc_param *param)\r
577 {\r
578         struct sprd_tiger_nand_info *tiger;\r
579         sprd_tiger_nand_data_param d_param;\r
580 \r
581         tiger = &g_tiger;\r
582         memset(&d_param, 0, sizeof(d_param));\r
583 \r
584         d_param.m_buf = param->p_mbuf;\r
585         d_param.s_buf = param->p_sbuf;\r
586         d_param.m_sct = param->ecc_num;\r
587         d_param.s_sct = param->ecc_num;\r
588         d_param.dir = 1;\r
589         d_param.m_size = param->m_size;\r
590         d_param.s_size = param->sp_size;\r
591 \r
592         Dcache_CleanRegion((unsigned int)d_param.m_buf, d_param.m_sct*d_param.m_size);\r
593         Dcache_CleanRegion((unsigned int)d_param.s_buf, d_param.s_sct*d_param.s_size);\r
594 \r
595         sprd_tiger_data_trans(&d_param);\r
596         sprd_ecc_ctrl(param, 1);\r
597         d_param.dir = 0;\r
598         d_param.m_sct = 0;\r
599 \r
600         Dcache_InvalRegion((unsigned int)d_param.m_buf , d_param.m_sct*d_param.m_size);\r
601         Dcache_InvalRegion((unsigned int)d_param.s_buf , d_param.s_sct*d_param.s_size);\r
602 \r
603         sprd_tiger_data_trans(&d_param); //read the ecc value from nfc buffer\r
604         return 0;\r
605 }\r
606 #endif\r
607 //add one macro instruction to nand controller\r
608 /*static */void sprd_tiger_nand_ins_init(struct sprd_tiger_nand_info *tiger)\r
609 {\r
610         tiger->ins_num = 0;\r
611 }\r
612 /*static */void sprd_tiger_nand_ins_add(uint16_t ins, struct sprd_tiger_nand_info *tiger)\r
613 {\r
614         uint16_t *buf = (uint16_t *)tiger->ins;\r
615         if(tiger->ins_num >= NAND_MC_BUFFER_SIZE)\r
616         {\r
617                 while(1);\r
618         }\r
619         *(buf + tiger->ins_num) = ins;\r
620         tiger->ins_num++;\r
621 }\r
622 /*static */void sprd_tiger_nand_ins_exec(struct sprd_tiger_nand_info *tiger)\r
623 {\r
624         uint32_t i;\r
625         uint32_t cfg0;\r
626         \r
627         for(i = 0; i < ((tiger->ins_num + 1) >> 1); i++)\r
628         {\r
629                 sprd_tiger_reg_write(NFC_INST0_REG + (i << 2), tiger->ins[i]);\r
630         }\r
631         cfg0 = sprd_tiger_reg_read(NFC_CFG0_REG);\r
632         if(tiger->wp_en)\r
633         {\r
634                 cfg0 &= ~NFC_WPN;\r
635         }\r
636         else\r
637         {\r
638                 cfg0 |= NFC_WPN;\r
639         }\r
640         if(tiger->chip)\r
641         {\r
642                 cfg0 |= CS_SEL;\r
643         }\r
644         else\r
645         {\r
646                 cfg0 &= ~CS_SEL;\r
647         }\r
648         sprd_tiger_nand_int_clr(INT_STSMCH_CLR | INT_WP_CLR | INT_TO_CLR | INT_DONE_CLR);//clear all interrupt\r
649         sprd_tiger_reg_write(NFC_CFG0_REG, cfg0);\r
650         sprd_tiger_reg_write(NFC_START_REG, NFC_START);\r
651 }\r
652 static int sprd_tiger_nand_wait_finish(struct sprd_tiger_nand_info *tiger)\r
653 {\r
654         unsigned int value;\r
655         unsigned int counter = 0;\r
656         while((counter < NFC_TIMEOUT_VAL/*time out*/))\r
657         {\r
658                 value = sprd_tiger_reg_read(NFC_INT_REG);\r
659                 if(value & INT_DONE_RAW)\r
660                 {\r
661                         break;\r
662                 }\r
663                 counter ++;\r
664         }\r
665         sprd_tiger_reg_write(NFC_INT_REG, 0xf00); //clear all interrupt status\r
666         if(counter > NFC_TIMEOUT_VAL)\r
667         {\r
668                 while (1);\r
669                 return -1;\r
670         }\r
671         return 0;\r
672 }\r
673 static void sprd_tiger_nand_wp_en(struct sprd_tiger_nand_info *tiger, int en)\r
674 {\r
675         if(en)\r
676         {\r
677                 tiger->wp_en = 1;\r
678         }\r
679         else\r
680         {\r
681                 tiger->wp_en = 0;\r
682         }\r
683 }\r
684 static void sprd_tiger_select_chip(struct mtd_info *mtd, int chip)\r
685 {\r
686         struct sprd_tiger_nand_info *tiger = mtd_to_tiger(mtd);\r
687         if(chip < 0) { //for release caller\r
688                 return;\r
689         }\r
690         //printf("sprd_tiger_select_chip, %x\r\n", chip);\r
691         tiger->chip = chip;\r
692 #ifdef CONFIG_NAND_SPL\r
693         nand_hardware_config(mtd,tiger->nand);\r
694 #endif\r
695 }\r
696 static void sprd_tiger_nand_read_status(struct sprd_tiger_nand_info *tiger)\r
697 {\r
698         uint32_t *buf;\r
699         //printf("sprd_tiger_nand_read_status\r\n");\r
700         sprd_tiger_nand_ins_init(tiger);\r
701         sprd_tiger_nand_ins_add(NAND_MC_CMD(NAND_CMD_STATUS), tiger);\r
702         sprd_tiger_nand_ins_add(NAND_MC_NOP(10), tiger);                // added nop.\r
703         sprd_tiger_nand_ins_add(NAND_MC_IDST(1), tiger);\r
704         sprd_tiger_nand_ins_add(NFC_MC_DONE_ID, tiger);\r
705         sprd_tiger_reg_write(NFC_CFG0_REG, NFC_ONLY_NAND_MODE);\r
706         sprd_tiger_nand_ins_exec(tiger);\r
707         sprd_tiger_nand_wait_finish(tiger);\r
708         buf = (uint32_t *)s_oob_data;\r
709         *buf = sprd_tiger_reg_read(NFC_STATUS0_REG);\r
710         tiger->buf_head = 0;\r
711         tiger->_buf_tail = 1;\r
712         //printf("--sprd_tiger_nand_read_status--\r\n");\r
713 }\r
714 static void sprd_tiger_nand_read_id(struct sprd_tiger_nand_info *tiger, uint32 *buf)\r
715 {\r
716         //printf("sprd_tiger_nand_read_id\r\n");\r
717         sprd_tiger_nand_ins_init(tiger);\r
718         sprd_tiger_nand_ins_add(NAND_MC_CMD(NAND_CMD_READID), tiger);\r
719         sprd_tiger_nand_ins_add(NAND_MC_ADDR(0), tiger);\r
720         sprd_tiger_nand_ins_add(NAND_MC_NOP(10), tiger);\r
721         sprd_tiger_nand_ins_add(NAND_MC_IDST(8), tiger);\r
722         sprd_tiger_nand_ins_add(NFC_MC_DONE_ID, tiger);\r
723         \r
724         sprd_tiger_reg_write(NFC_CFG0_REG, NFC_ONLY_NAND_MODE);\r
725         sprd_tiger_nand_ins_exec(tiger);\r
726         sprd_tiger_nand_wait_finish(tiger);\r
727         *buf = sprd_tiger_reg_read(NFC_STATUS0_REG);\r
728         *(buf + 1) = sprd_tiger_reg_read(NFC_STATUS1_REG);\r
729         tiger->buf_head = 0;\r
730         tiger->_buf_tail = 8;\r
731         //printf("--sprd_tiger_nand_read_id--\r\n");\r
732 }\r
733 static void sprd_tiger_nand_reset(struct sprd_tiger_nand_info *tiger)\r
734 {\r
735         //printf("sprd_tiger_nand_reset\r\n");\r
736         sprd_tiger_nand_ins_init(tiger);\r
737         sprd_tiger_nand_ins_add(NAND_MC_CMD(NAND_CMD_RESET), tiger);\r
738         sprd_tiger_nand_ins_add(NFC_MC_WRB0_ID, tiger); //wait rb\r
739         sprd_tiger_nand_ins_add(NFC_MC_DONE_ID, tiger);\r
740         //config register\r
741         sprd_tiger_reg_write(NFC_CFG0_REG, NFC_ONLY_NAND_MODE);\r
742         sprd_tiger_nand_ins_exec(tiger);\r
743         sprd_tiger_nand_wait_finish(tiger);\r
744         //printf("--sprd_tiger_nand_reset--\r\n");\r
745 }\r
746 static u32 sprd_tiger_get_decode_sts(u32 index)\r
747 {\r
748         uint32_t err;\r
749         uint32_t shift;\r
750         uint32_t reg_addr;\r
751         reg_addr = NFC_STATUS0_REG + (index & 0xfffffffc);\r
752         shift = (index & 0x3) >> 3;\r
753         err = sprd_tiger_reg_read(reg_addr);\r
754         err >>= shift;\r
755         if((err & ECC_ALL_FF))\r
756         {\r
757                 err = 0;\r
758         }\r
759         else\r
760         {\r
761                 err &= ERR_ERR_NUM0_MASK;\r
762         }\r
763         return err;\r
764 }\r
765 //read large page\r
766 static int sprd_tiger_nand_read_lp(struct mtd_info *mtd,uint8_t *mbuf, uint8_t *sbuf,uint32_t raw)\r
767 {\r
768         struct sprd_tiger_nand_info *tiger = mtd_to_tiger(mtd);\r
769         struct nand_chip *chip = tiger->nand;\r
770         uint32_t column;\r
771         uint32_t page_addr;\r
772         uint32_t cfg0;\r
773         uint32_t cfg1;\r
774         uint32_t cfg2;\r
775         uint32_t i;\r
776         uint32_t err;\r
777         page_addr = tiger->page;\r
778         \r
779         if(sbuf) {\r
780                 column = mtd->writesize;\r
781         }\r
782         else\r
783         {\r
784                 column = 0;\r
785         }\r
786         if(chip->options & NAND_BUSWIDTH_16)\r
787         {\r
788                 column >>= 1;\r
789         }\r
790         //printf("sprd_tiger_nand_read_lp,page_addr = %x,column = %x\r\n",page_addr, column);\r
791         sprd_tiger_nand_ins_init(tiger);\r
792         sprd_tiger_nand_ins_add(NAND_MC_CMD(NAND_CMD_READ0), tiger);\r
793         sprd_tiger_nand_ins_add(NAND_MC_ADDR(column & 0xff), tiger);\r
794         column >>= 8;\r
795         sprd_tiger_nand_ins_add(NAND_MC_ADDR(column & 0xff), tiger);\r
796 \r
797         sprd_tiger_nand_ins_add(NAND_MC_ADDR(page_addr & 0xff), tiger);\r
798         page_addr >>= 8;\r
799         sprd_tiger_nand_ins_add(NAND_MC_ADDR(page_addr & 0xff), tiger);\r
800         \r
801         if (5 == tiger->a_cycles)// five address cycles\r
802         {\r
803                 page_addr >>= 8;\r
804                 sprd_tiger_nand_ins_add(NAND_MC_ADDR(page_addr & 0xff), tiger);\r
805         }\r
806         sprd_tiger_nand_ins_add(NAND_MC_CMD(NAND_CMD_READSTART), tiger);\r
807         \r
808         sprd_tiger_nand_ins_add(NFC_MC_WRB0_ID, tiger); //wait rb\r
809         if(mbuf && sbuf)\r
810         {\r
811                 sprd_tiger_nand_ins_add(NAND_MC_SRDT, tiger);\r
812                 sprd_tiger_nand_ins_add(NAND_MC_NOP(10), tiger);\r
813                 //switch to main part\r
814                 sprd_tiger_nand_ins_add(NAND_MC_CMD(NAND_CMD_RNDOUT), tiger);\r
815                 sprd_tiger_nand_ins_add(NAND_MC_ADDR(0), tiger);\r
816                 sprd_tiger_nand_ins_add(NAND_MC_ADDR(0), tiger);\r
817                 sprd_tiger_nand_ins_add(NAND_MC_CMD(NAND_CMD_RNDOUTSTART), tiger);\r
818                 sprd_tiger_nand_ins_add(NAND_MC_NOP(10), tiger);\r
819                 sprd_tiger_nand_ins_add(NAND_MC_MRDT, tiger);\r
820         }\r
821         else\r
822         {\r
823                 sprd_tiger_nand_ins_add(NAND_MC_MRDT, tiger);\r
824         }\r
825         sprd_tiger_nand_ins_add(NFC_MC_DONE_ID, tiger);\r
826         //config registers \r
827         cfg0 = NFC_AUTO_MODE | MAIN_SPAR_APT | ((tiger->sct_pg - 1)<< SECTOR_NUM_OFFSET);\r
828         if((!raw) && mbuf && sbuf)\r
829         {\r
830                 cfg0 |= ECC_EN | DETECT_ALL_FF;\r
831         }\r
832         if(chip->options & NAND_BUSWIDTH_16)\r
833         {\r
834                 cfg0 |= BUS_WIDTH;\r
835         }\r
836         cfg1 = (tiger->info_size - 1) << SPAR_INFO_SIZE_OFFSET;\r
837         cfg2 = (tiger->ecc_mode << ECC_MODE_OFFSET) | (tiger->info_pos << SPAR_INFO_POS_OFFSET) | ((tiger->sct_pg - 1) << SPAR_SECTOR_NUM_OFFSET) | tiger->ecc_pos;\r
838 \r
839 #ifndef CONFIG_NAND_SPL\r
840         if (mbuf)\r
841         {\r
842                 Dcache_CleanRegion((unsigned int)mbuf, tiger->m_size*tiger->sct_pg);\r
843                 Dcache_InvalRegion((unsigned int)mbuf, tiger->m_size*tiger->sct_pg);\r
844         }\r
845 \r
846         if (sbuf)\r
847         {\r
848                 Dcache_CleanRegion((unsigned int)sbuf, tiger->s_size*tiger->sct_pg);\r
849                 Dcache_InvalRegion((unsigned int)sbuf, tiger->s_size*tiger->sct_pg);\r
850         }\r
851 #endif\r
852         if(mbuf && sbuf)\r
853         {\r
854                 cfg1 |= (tiger->m_size - 1) | ((tiger->s_size  - 1)<< SPAR_SIZE_OFFSET);\r
855                 sprd_tiger_reg_write(NFC_MAIN_ADDR_REG, (uint32_t)mbuf);\r
856                 sprd_tiger_reg_write(NFC_SPAR_ADDR_REG, (uint32_t)sbuf);\r
857                 cfg0 |= MAIN_USE | SPAR_USE;\r
858         }\r
859         else\r
860         {\r
861                 if(mbuf)\r
862                 {\r
863                         cfg1 |= (tiger->m_size - 1);\r
864                         sprd_tiger_reg_write(NFC_MAIN_ADDR_REG, (uint32_t)mbuf);\r
865                 }\r
866                 if(sbuf)\r
867                 {\r
868                         cfg1 |= (tiger->s_size - 1);\r
869                         sprd_tiger_reg_write(NFC_MAIN_ADDR_REG, (uint32_t)sbuf);\r
870                 }\r
871                 cfg0 |= MAIN_USE;\r
872         }       \r
873         sprd_tiger_reg_write(NFC_CFG0_REG, cfg0);\r
874         sprd_tiger_reg_write(NFC_CFG1_REG, cfg1);\r
875         sprd_tiger_reg_write(NFC_CFG2_REG, cfg2);\r
876         \r
877         sprd_tiger_nand_ins_exec(tiger);\r
878         sprd_tiger_nand_wait_finish(tiger);\r
879         if(!raw) {\r
880                 for(i = 0; i < tiger->sct_pg; i++) {\r
881                         err = sprd_tiger_get_decode_sts(i);\r
882                         if(err == ERR_ERR_NUM0_MASK) {\r
883                                 mtd->ecc_stats.failed++;\r
884                         }\r
885                         else {\r
886                                 mtd->ecc_stats.corrected += err;\r
887                         }\r
888                 }\r
889         }\r
890         \r
891         return 0;\r
892 }\r
893 static int sprd_tiger_nand_read_sp(struct mtd_info *mtd,uint8_t *mbuf, uint8_t *sbuf,uint32_t raw)\r
894 {\r
895         return 0;\r
896 }\r
897 #ifndef CONFIG_NAND_SPL\r
898 static int sprd_tiger_nand_write_lp(struct mtd_info *mtd,const uint8_t *mbuf, uint8_t *sbuf,uint32_t raw)\r
899 {\r
900         struct sprd_tiger_nand_info *tiger = mtd_to_tiger(mtd);\r
901         struct nand_chip *chip = tiger->nand;\r
902         uint32_t column;\r
903         uint32_t page_addr;\r
904         uint32_t cfg0;\r
905         uint32_t cfg1;\r
906         uint32_t cfg2;\r
907         page_addr = tiger->page;\r
908         if(mbuf) {\r
909                 column = 0;\r
910         }\r
911         else {\r
912                 column = mtd->writesize;\r
913         }       \r
914         if(chip->options & NAND_BUSWIDTH_16)\r
915         {\r
916                 column >>= 1;\r
917         }\r
918         sprd_tiger_nand_ins_init(tiger);\r
919         sprd_tiger_nand_ins_add(NAND_MC_CMD(NAND_CMD_SEQIN), tiger);\r
920         sprd_tiger_nand_ins_add(NAND_MC_ADDR(column & 0xff), tiger);\r
921         column >>= 8;\r
922         sprd_tiger_nand_ins_add(NAND_MC_ADDR(column & 0xff), tiger);\r
923         sprd_tiger_nand_ins_add(NAND_MC_ADDR(page_addr & 0xff), tiger);\r
924         page_addr >>= 8;\r
925         sprd_tiger_nand_ins_add(NAND_MC_ADDR(page_addr & 0xff), tiger);\r
926         \r
927         if (5 == tiger->a_cycles)// five address cycles\r
928         {\r
929                 page_addr >>= 8;\r
930                 sprd_tiger_nand_ins_add(NAND_MC_ADDR(page_addr & 0xff), tiger);\r
931         }\r
932         sprd_tiger_nand_ins_add(NAND_MC_NOP(10), tiger);\r
933 \r
934         sprd_tiger_nand_ins_add(NAND_MC_MWDT, tiger);\r
935         if(mbuf && sbuf)\r
936         {\r
937                 sprd_tiger_nand_ins_add(NAND_MC_SWDT, tiger);\r
938         }\r
939         sprd_tiger_nand_ins_add(NAND_MC_CMD(NAND_CMD_PAGEPROG), tiger);\r
940         sprd_tiger_nand_ins_add(NFC_MC_WRB0_ID, tiger); //wait rb\r
941 \r
942         sprd_tiger_nand_ins_add(NFC_MC_DONE_ID, tiger);\r
943         //config registers \r
944         cfg0 = NFC_AUTO_MODE | NFC_RW |  NFC_WPN | MAIN_SPAR_APT | ((tiger->sct_pg - 1)<< SECTOR_NUM_OFFSET);\r
945         if((!raw) && mbuf && sbuf)\r
946         {\r
947                 cfg0 |= ECC_EN;\r
948         }\r
949         if(chip->options & NAND_BUSWIDTH_16)\r
950         {\r
951                 cfg0 |= BUS_WIDTH;\r
952         }\r
953         cfg1 = ((tiger->info_size - 1) << SPAR_INFO_SIZE_OFFSET);\r
954         cfg2 = (tiger->ecc_mode << ECC_MODE_OFFSET) | (tiger->info_pos << SPAR_INFO_POS_OFFSET) | ((tiger->sct_pg - 1) << SPAR_SECTOR_NUM_OFFSET) | tiger->ecc_pos;\r
955 \r
956         if (mbuf)\r
957         {\r
958                 Dcache_CleanRegion((unsigned int)mbuf, tiger->m_size*tiger->sct_pg);\r
959                 Dcache_InvalRegion((unsigned int)mbuf, tiger->m_size*tiger->sct_pg);\r
960         }\r
961 \r
962         if (sbuf)\r
963         {\r
964                 Dcache_CleanRegion((unsigned int)sbuf, tiger->s_size*tiger->sct_pg);\r
965                 Dcache_InvalRegion((unsigned int)sbuf, tiger->s_size*tiger->sct_pg);\r
966         }\r
967         if(mbuf && sbuf)\r
968         {\r
969                 cfg0 |= MAIN_USE | SPAR_USE;\r
970                 cfg1 = (tiger->m_size - 1) | ((tiger->s_size - 1) << SPAR_SIZE_OFFSET);\r
971                 sprd_tiger_reg_write(NFC_MAIN_ADDR_REG, (uint32_t)mbuf);\r
972                 sprd_tiger_reg_write(NFC_SPAR_ADDR_REG, (uint32_t)sbuf);\r
973         }\r
974         else\r
975         {\r
976                 cfg0 |= MAIN_USE;\r
977                 if(mbuf)\r
978                 {\r
979                         cfg1 |= tiger->m_size - 1;\r
980                         sprd_tiger_reg_write(NFC_MAIN_ADDR_REG, (uint32_t)mbuf);\r
981                 }\r
982                 else\r
983                 {\r
984                         cfg1 |= tiger->s_size - 1;\r
985                         sprd_tiger_reg_write(NFC_MAIN_ADDR_REG, (uint32_t)sbuf);\r
986                 }\r
987         }\r
988         sprd_tiger_reg_write(NFC_CFG0_REG, cfg0);\r
989         sprd_tiger_reg_write(NFC_CFG1_REG, cfg1);\r
990         sprd_tiger_reg_write(NFC_CFG2_REG, cfg2);\r
991         sprd_tiger_nand_ins_exec(tiger);\r
992         sprd_tiger_nand_wait_finish(tiger);\r
993         return 0;\r
994 }\r
995 static int sprd_tiger_nand_write_sp(struct mtd_info *mtd,const uint8_t *mbuf, uint8_t *sbuf,uint32_t raw)\r
996 {\r
997         return 0;\r
998 }\r
999 #endif\r
1000 static void sprd_tiger_erase(struct mtd_info *mtd, int page_addr)\r
1001 {\r
1002         struct sprd_tiger_nand_info *tiger = mtd_to_tiger(mtd);\r
1003         uint32_t cfg0 = 0;\r
1004         //printf("sprd_tiger_erase, %x\r\n", page_addr);\r
1005         sprd_tiger_nand_ins_init(tiger);\r
1006         sprd_tiger_nand_ins_add(NAND_MC_CMD(NAND_CMD_ERASE1), tiger);\r
1007         sprd_tiger_nand_ins_add(NAND_MC_ADDR(page_addr & 0xff), tiger);\r
1008         page_addr >>= 8;\r
1009         sprd_tiger_nand_ins_add(NAND_MC_ADDR(page_addr & 0xff), tiger);\r
1010         if((5 == tiger->a_cycles) || ((4 == tiger->a_cycles) && (512 == tiger->write_size)))\r
1011         {\r
1012                 page_addr >>= 8;\r
1013                 sprd_tiger_nand_ins_add(NAND_MC_ADDR(page_addr & 0xff), tiger);\r
1014         }\r
1015         sprd_tiger_nand_ins_add(NAND_MC_CMD(NAND_CMD_ERASE2), tiger);\r
1016         sprd_tiger_nand_ins_add(NFC_MC_WRB0_ID, tiger); //wait rb\r
1017 \r
1018         sprd_tiger_nand_ins_add(NFC_MC_DONE_ID, tiger);\r
1019         cfg0 = NFC_WPN | NFC_ONLY_NAND_MODE;\r
1020         sprd_tiger_reg_write(NFC_CFG0_REG, cfg0);\r
1021         sprd_tiger_nand_ins_exec(tiger);\r
1022         sprd_tiger_nand_wait_finish(tiger);\r
1023         //printf("--sprd_tiger_erase--\r\n");\r
1024 }\r
1025 static uint8_t sprd_tiger_read_byte(struct mtd_info *mtd)\r
1026 {\r
1027         uint8_t ch = 0xff;\r
1028         struct sprd_tiger_nand_info *tiger = mtd_to_tiger(mtd);\r
1029         if(tiger->buf_head < tiger->_buf_tail)\r
1030         {\r
1031                 ch = s_oob_data[tiger->buf_head ++];\r
1032         }\r
1033         return ch;\r
1034 }\r
1035 static uint16_t sprd_tiger_read_word(struct mtd_info *mtd)\r
1036 {\r
1037         uint16_t data = 0xffff;\r
1038         struct sprd_tiger_nand_info *tiger = mtd_to_tiger(mtd);\r
1039         if(tiger->buf_head < (tiger->_buf_tail - 1))\r
1040         {\r
1041                 data = s_oob_data[tiger->buf_head ++];\r
1042                 data |= ((uint16_t)s_oob_data[tiger->buf_head ++]) << 8;\r
1043         }\r
1044         return data;\r
1045 }\r
1046 static int sprd_tiger_waitfunc(struct mtd_info *mtd, struct nand_chip *chip)\r
1047 {\r
1048         return 0;\r
1049 }\r
1050 static int sprd_tiger_ecc_calculate(struct mtd_info *mtd, const uint8_t *data,\r
1051                                 uint8_t *ecc_code)\r
1052 {\r
1053         return 0;\r
1054 }\r
1055 static int sprd_tiger_ecc_correct(struct mtd_info *mtd, uint8_t *data,\r
1056                                 uint8_t *read_ecc, uint8_t *calc_ecc)\r
1057 {\r
1058         return 0;\r
1059 }\r
1060 static int sprd_tiger_read_page(struct mtd_info *mtd, struct nand_chip *chip,\r
1061                         uint8_t *buf, int page)\r
1062 {\r
1063         struct sprd_tiger_nand_info *tiger = mtd_to_tiger(mtd);\r
1064         tiger->page = page;\r
1065         if(512 == mtd->writesize)\r
1066         {\r
1067                 sprd_tiger_nand_read_sp(mtd, buf, chip->oob_poi, 0);\r
1068         }\r
1069         else\r
1070         {\r
1071                 sprd_tiger_nand_read_lp(mtd, buf, chip->oob_poi, 0);\r
1072         }\r
1073         return 0;\r
1074 }\r
1075 static int sprd_tiger_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,\r
1076                                 uint8_t *buf, int page)\r
1077 {\r
1078         struct sprd_tiger_nand_info *tiger = mtd_to_tiger(mtd);\r
1079         tiger->page = page;\r
1080         if(512 == mtd->writesize)\r
1081         {\r
1082                 sprd_tiger_nand_read_sp(mtd, buf, chip->oob_poi, 1);\r
1083         }\r
1084         else\r
1085         {\r
1086                 sprd_tiger_nand_read_lp(mtd, buf, chip->oob_poi, 1);\r
1087         }\r
1088         return 0;\r
1089 }\r
1090 static int sprd_tiger_read_oob(struct mtd_info *mtd, struct nand_chip *chip,\r
1091                            int page, int sndcmd)\r
1092 {\r
1093         struct sprd_tiger_nand_info *tiger = mtd_to_tiger(mtd);\r
1094         tiger->page = page;\r
1095         if(512 == mtd->writesize)\r
1096         {\r
1097                 sprd_tiger_nand_read_sp(mtd, 0, chip->oob_poi, 1);\r
1098         }\r
1099         else\r
1100         {\r
1101                 sprd_tiger_nand_read_lp(mtd, 0, chip->oob_poi, 1);\r
1102         }\r
1103         return 0;\r
1104 }\r
1105 #ifndef CONFIG_NAND_SPL\r
1106 static void sprd_tiger_write_page(struct mtd_info *mtd, struct nand_chip *chip,\r
1107                                 const uint8_t *buf)\r
1108 {\r
1109         if(512 == mtd->writesize)\r
1110         {\r
1111                 sprd_tiger_nand_write_sp(mtd, buf, chip->oob_poi, 0);   \r
1112         }\r
1113         else\r
1114         {\r
1115                 sprd_tiger_nand_write_lp(mtd, buf, chip->oob_poi, 0);   \r
1116         }\r
1117 \r
1118 }\r
1119 static void sprd_tiger_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,\r
1120                                         const uint8_t *buf)\r
1121 {\r
1122         if(512 == mtd->writesize)\r
1123         {\r
1124                 sprd_tiger_nand_write_sp(mtd, buf, chip->oob_poi, 1);   \r
1125         }\r
1126         else\r
1127         {\r
1128                 sprd_tiger_nand_write_lp(mtd, buf, chip->oob_poi, 1);   \r
1129         }\r
1130 }\r
1131 static int sprd_tiger_write_oob(struct mtd_info *mtd, struct nand_chip *chip,\r
1132                                 int page)\r
1133 {\r
1134         struct sprd_tiger_nand_info *tiger = mtd_to_tiger(mtd); \r
1135         tiger->page = page;\r
1136         if(512 == mtd->writesize)\r
1137         {\r
1138                 sprd_tiger_nand_write_sp(mtd, 0, chip->oob_poi, 1);\r
1139         }\r
1140         else\r
1141         {\r
1142                 sprd_tiger_nand_write_lp(mtd, 0, chip->oob_poi, 1);\r
1143         }\r
1144         return 0;\r
1145 }\r
1146 #endif\r
1147 /**\r
1148  * nand_block_bad - [DEFAULT] Read bad block marker from the chip\r
1149  * @mtd:        MTD device structure\r
1150  * @ofs:        offset from device start\r
1151  * @getchip:    0, if the chip is already selected\r
1152  *\r
1153  * Check, if the block is bad.\r
1154  */\r
1155 static int sprd_tiger_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)\r
1156 {\r
1157         int page, chipnr, res = 0;\r
1158         struct sprd_tiger_nand_info *tiger = mtd_to_tiger(mtd);\r
1159         struct nand_chip *chip = mtd->priv;\r
1160         uint16_t bad;\r
1161         uint16_t *buf;\r
1162 \r
1163         page = (int)(ofs >> chip->page_shift) & chip->pagemask;\r
1164 \r
1165         if (getchip) {\r
1166                 chipnr = (int)(ofs >> chip->chip_shift);\r
1167                 /* Select the NAND device */\r
1168                 chip->select_chip(mtd, chipnr);\r
1169         }\r
1170 \r
1171         chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);\r
1172         if(512 == tiger->write_size) {\r
1173                 sprd_tiger_nand_read_sp(mtd, 0, s_oob_data, 1);\r
1174         }\r
1175         else  {\r
1176                 sprd_tiger_nand_read_lp(mtd, 0, s_oob_data, 1);\r
1177         }\r
1178         tiger->buf_head = 0;\r
1179         tiger->_buf_tail = mtd->oobsize;\r
1180         buf = (uint16_t *)(s_oob_data + chip->badblockpos);\r
1181 \r
1182         if (chip->options & NAND_BUSWIDTH_16) {\r
1183                 bad = *(buf);\r
1184                 if ((bad & 0xFF) != 0xff) {\r
1185                         res = 1;\r
1186                 }\r
1187         } else {\r
1188                 bad = *(buf) & 0xff;\r
1189                 if (bad != 0xff){\r
1190                         res = 1;\r
1191                 }\r
1192         }\r
1193         return res;\r
1194 }\r
1195 static void sprd_tiger_nand_cmdfunc(struct mtd_info *mtd, unsigned int command,\r
1196                             int column, int page_addr)\r
1197 {\r
1198         struct sprd_tiger_nand_info *tiger = mtd_to_tiger(mtd);\r
1199         /* Emulate NAND_CMD_READOOB */\r
1200         if (command == NAND_CMD_READOOB) {\r
1201                 column += mtd->writesize;\r
1202                 command = NAND_CMD_READ0;\r
1203         }\r
1204         /*\r
1205          * program and erase have their own busy handlers\r
1206          * status, sequential in, and deplete1 need no delay\r
1207          */\r
1208         switch (command) {\r
1209         case NAND_CMD_STATUS:\r
1210                 sprd_tiger_nand_read_status(tiger);\r
1211                 break;\r
1212         case NAND_CMD_READID:\r
1213                 sprd_tiger_nand_read_id(tiger, (uint32 *)s_oob_data);\r
1214                 break;\r
1215         case NAND_CMD_RESET:\r
1216                 sprd_tiger_nand_reset(tiger);\r
1217                 break;\r
1218         case NAND_CMD_ERASE1:\r
1219                 sprd_tiger_erase(mtd, page_addr);\r
1220                 break;\r
1221         case NAND_CMD_READ0:\r
1222         case NAND_CMD_SEQIN:\r
1223                 tiger->column = column;\r
1224                 tiger->page = page_addr;\r
1225         default:\r
1226                 break;\r
1227         }\r
1228 }\r
1229 static void sprd_tiger_nand_hwecc_ctl(struct mtd_info *mtd, int mode)\r
1230 {\r
1231         return; //do nothing\r
1232 }\r
1233 static void sprd_tiger_nand_hw_init(struct sprd_tiger_nand_info *tiger)\r
1234 {\r
1235         int i = 0;\r
1236         uint32_t val;\r
1237         \r
1238         sprd_tiger_reg_or(0x20900200, BIT_8);\r
1239         \r
1240         val = sprd_tiger_reg_read(0x20900210);\r
1241         sprd_tiger_reg_or(0x20900210, BIT_5);\r
1242         for(i = 0; i < 0xffff; i++);\r
1243         sprd_tiger_reg_and(0x20900210, ~BIT_5);\r
1244         val |= (4)  | (4 << NFC_RWH_OFFSET) | (3 << NFC_RWE_OFFSET) | (3 << NFC_RWS_OFFSET) | (3 << NFC_ACE_OFFSET) | (3 << NFC_ACS_OFFSET);\r
1245         \r
1246         sprd_tiger_reg_write(NFC_TIMING_REG, val);\r
1247         sprd_tiger_reg_write(NFC_TIMEOUT_REG, 0x80400000);\r
1248         sprd_tiger_reg_or(PIN_NFRB_REG, BIT_7);   //set PIN_NFRB pull up\r
1249         sprd_tiger_reg_or(PIN_CTL2_REG, BIT_17);  //set PIN_NFRB pull up resiter 4.7k\r
1250         for (i=PIN_NFWPN_REG; i<=PIN_NFD15_REG; i+=4)\r
1251         {\r
1252                 sprd_tiger_reg_or( i, BIT_9);\r
1253                 sprd_tiger_reg_and(i, ~(BIT_8|BIT_10|BIT_6));\r
1254         }\r
1255         //close write protect\r
1256         sprd_tiger_nand_wp_en(tiger, 0);\r
1257 }\r
1258 int board_nand_init(struct nand_chip *chip)\r
1259 {\r
1260         printf("board_nand_init\r\n");\r
1261         sprd_tiger_nand_hw_init(&g_tiger);\r
1262         chip->select_chip = sprd_tiger_select_chip;\r
1263         chip->cmdfunc = sprd_tiger_nand_cmdfunc;\r
1264         chip->read_byte = sprd_tiger_read_byte;\r
1265         chip->read_word = sprd_tiger_read_word;\r
1266         chip->waitfunc = sprd_tiger_waitfunc;\r
1267         chip->ecc.mode = NAND_ECC_HW;\r
1268         chip->ecc.calculate = sprd_tiger_ecc_calculate;\r
1269         chip->ecc.hwctl = sprd_tiger_nand_hwecc_ctl;\r
1270         \r
1271         chip->ecc.correct = sprd_tiger_ecc_correct;\r
1272         chip->ecc.read_page = sprd_tiger_read_page;\r
1273         chip->ecc.read_page_raw = sprd_tiger_read_page_raw;\r
1274 #ifndef CONFIG_NAND_SPL\r
1275         chip->ecc.write_page = sprd_tiger_write_page;\r
1276         chip->ecc.write_page_raw = sprd_tiger_write_page_raw;\r
1277         chip->ecc.write_oob = sprd_tiger_write_oob;\r
1278 #endif\r
1279         chip->ecc.read_oob = sprd_tiger_read_oob;\r
1280         chip->erase_cmd = sprd_tiger_erase;\r
1281 \r
1282         chip->ecc.bytes = CONFIG_SYS_NAND_ECCBYTES;\r
1283         g_tiger.ecc_mode = CONFIG_SYS_NAND_ECC_MODE;\r
1284         g_tiger.nand = chip;\r
1285 #ifndef CONFIG_NAND_SPL\r
1286         tiger_set_timing_config(&g_tiger, 153);\r
1287 #endif\r
1288         chip->eccbitmode = g_tiger.ecc_mode;\r
1289         chip->ecc.size = CONFIG_SYS_NAND_ECCSIZE;\r
1290         \r
1291         chip->options |= NAND_BUSWIDTH_16;\r
1292 \r
1293         return 0;\r
1294 }\r
1295 \r
1296 static unsigned long nfc_read_status(void)\r
1297 {\r
1298         unsigned long status = 0;\r
1299 \r
1300         sprd_tiger_nand_read_status(&g_tiger);  \r
1301         status = s_oob_data[0];\r
1302 \r
1303         return status;\r
1304 }\r
1305 \r
1306 #ifndef CONFIG_NAND_SPL\r
1307 static int sprd_scan_one_block(int blk, int erasesize, int writesize)\r
1308 {\r
1309         int i, cmd;\r
1310         int status = 1, ii;\r
1311         u32 size = 0;\r
1312         int oobsize = mtdoobsize;\r
1313         int column, page_addr;\r
1314 \r
1315         page_addr = blk * (erasesize / writesize);\r
1316         for (ii = 0; ii < 2; ii ++) {\r
1317                 printf("please debug here : %s %d\n", __FUNCTION__, __LINE__);\r
1318                 sprd_tiger_nand_ins_init(&g_tiger);\r
1319                 sprd_tiger_nand_ins_add(NAND_MC_CMD(NAND_CMD_READ0), &g_tiger);\r
1320                 sprd_tiger_nand_ins_add(NAND_MC_CMD(NAND_CMD_READSTART), &g_tiger);\r
1321                 if ((s_oob_data[0] != 0xff) || (s_oob_data[1] != 0xff))\r
1322                         break;\r
1323         } //for (ii = 0; ii < 2; ii ++)\r
1324 \r
1325         if ((s_oob_data[0] == 0xff) && (s_oob_data[1] == 0xff))\r
1326                 status = 0; //good block\r
1327         else\r
1328                 status = 1; //bad block\r
1329 \r
1330         return status;\r
1331 }\r
1332 \r
1333 static unsigned long nand_ctl_erase_block(int blk, int erasesize, int writesize)\r
1334 {\r
1335         int cmd, status;\r
1336         int page_addr;\r
1337 \r
1338         page_addr = blk * (erasesize / writesize);\r
1339         sprd_tiger_erase(&g_tiger, page_addr);\r
1340         status = nfc_read_status();\r
1341 \r
1342         return status;\r
1343 }\r
1344 \r
1345 void nand_scan_patition(int blocks, int erasesize, int writesize)\r
1346 {\r
1347         int blk;\r
1348         int ret;\r
1349         int status;\r
1350 \r
1351         //read_chip_id();\r
1352         for (blk = 0; blk < blocks; blk ++) {\r
1353                 ret = sprd_scan_one_block(blk, erasesize, writesize);\r
1354                 if (ret != 0) {\r
1355                         printf("\n%d is bad, scrub to erase it, ", blk);\r
1356                         ret = nand_ctl_erase_block(blk, erasesize, writesize);\r
1357                         printf("0x%02x\n", ret);\r
1358                 } else {\r
1359                         ret = nand_ctl_erase_block(blk, erasesize, writesize);\r
1360                         printf("erasing block : %d    %d % \r", blk, (blk * 100 ) / blocks);\r
1361                 }\r
1362         }\r
1363 }\r
1364 int nand_scan_block(int block, int erasesize, int writesize){\r
1365         int ret = 0;\r
1366         ret = nand_ctl_erase_block(block, erasesize, writesize);\r
1367         ret = ret&1;\r
1368 \r
1369         return ret;\r
1370 }\r
1371 #endif\r