usbboot/xburst_stage2/boothandler.c |
42 | 42 | void (*nand_enable) (unsigned int csn); |
43 | 43 | void (*nand_disable) (unsigned int csn); |
44 | 44 | |
45 | | struct hand Hand,*Hand_p; |
46 | | extern u32 Bulk_buf[BULK_BUF_SIZE]; |
| 45 | struct hand Hand; |
| 46 | extern u32 Bulk_out_buf[BULK_OUT_BUF_SIZE]; |
| 47 | extern u32 Bulk_in_buf[BULK_IN_BUF_SIZE]; |
47 | 48 | extern u16 handshake_PKT[4]; |
48 | 49 | extern udc_state; |
49 | 50 | extern void *memset(void *s, int c, size_t count); |
... | ... | |
54 | 55 | u32 ops_length; //number of operation unit ,in byte or sector |
55 | 56 | u32 ram_addr; |
56 | 57 | |
57 | | void config_flash_info() |
58 | | { |
59 | | } |
60 | | |
61 | 58 | void dump_data(unsigned int *p, int size) |
62 | 59 | { |
63 | 60 | int i; |
... | ... | |
65 | 62 | serial_put_hex(*p++); |
66 | 63 | } |
67 | 64 | |
68 | | void config_hand() |
| 65 | void config_flash_info() |
69 | 66 | { |
70 | | struct hand *hand_p; |
71 | | hand_p=(struct hand *)Bulk_buf; |
72 | | memcpy(&Hand, (unsigned char *)Bulk_buf, sizeof(struct hand)); |
73 | | |
74 | | #if 0 |
75 | | Hand.nand_bw=hand_p->nand_bw; |
76 | | Hand.nand_rc=hand_p->nand_rc; |
77 | | Hand.nand_ps=hand_p->nand_ps; |
78 | | Hand.nand_ppb=hand_p->nand_ppb; |
79 | | Hand.nand_force_erase=hand_p->nand_force_erase; |
80 | | Hand.nand_pn=hand_p->nand_pn; |
81 | | Hand.nand_os=hand_p->nand_os; |
| 67 | } |
82 | 68 | |
83 | | Hand.nand_eccpos=hand_p->nand_eccpos; |
84 | | Hand.nand_bbpos=hand_p->nand_bbpos; |
85 | | Hand.nand_bbpage=hand_p->nand_bbpage; |
86 | | serial_put_hex(Hand.fw_args.cpu_id); |
87 | | serial_put_hex(Hand.fw_args.ext_clk); |
88 | | #endif |
| 69 | void config_hand() |
| 70 | { |
| 71 | memcpy(&Hand, (unsigned char *)Bulk_out_buf, sizeof(struct hand)); |
89 | 72 | } |
90 | 73 | |
91 | 74 | int GET_CUP_INFO_Handle() |
92 | 75 | { |
93 | | char temp1[8]="Boot4740",temp2[8]="Boot4750"; |
94 | 76 | dprintf("\n GET_CPU_INFO:\t"); |
95 | 77 | serial_put_hex(Hand.fw_args.cpu_id); |
96 | | if (Hand.fw_args.cpu_id == 0x4740) |
97 | | HW_SendPKT(0, temp1, 8); |
98 | | else |
99 | | HW_SendPKT(0, temp2, 8); |
| 78 | switch (Hand.fw_args.cpu_id) { |
| 79 | case 0x4760: |
| 80 | HW_SendPKT(0, "Boot4760", 8); |
| 81 | break; |
| 82 | case 0x4740: |
| 83 | HW_SendPKT(0, "Boot4740", 8); |
| 84 | break; |
| 85 | default: |
| 86 | HW_SendPKT(0, " UNKNOW ", 8); |
| 87 | break; |
| 88 | } |
100 | 89 | udc_state = IDLE; |
101 | 90 | return ERR_OK; |
102 | 91 | } |
... | ... | |
165 | 154 | { |
166 | 155 | case NAND_QUERY: |
167 | 156 | dprintf("\n Request : NAND_QUERY!"); |
168 | | nand_query((u8 *)Bulk_buf); |
169 | | HW_SendPKT(1, Bulk_buf, 8); |
| 157 | nand_query((u8 *)Bulk_in_buf); |
| 158 | HW_SendPKT(1, Bulk_in_buf, 8); |
170 | 159 | handshake_PKT[3]=(u16)ERR_OK; |
171 | 160 | udc_state = BULK_IN; |
172 | 161 | break; |
... | ... | |
185 | 174 | break; |
186 | 175 | case NAND_READ_OOB: |
187 | 176 | dprintf("\n Request : NAND_READ_OOB!"); |
188 | | memset(Bulk_buf,0,ops_length*Hand.nand_ps); |
189 | | ret_dat = nand_read_oob(Bulk_buf,start_addr,ops_length); |
| 177 | memset(Bulk_in_buf,0,ops_length*Hand.nand_ps); |
| 178 | ret_dat = nand_read_oob(Bulk_in_buf,start_addr,ops_length); |
190 | 179 | handshake_PKT[0] = (u16) ret_dat; |
191 | 180 | handshake_PKT[1] = (u16) (ret_dat>>16); |
192 | | HW_SendPKT(1,(u8 *)Bulk_buf,ops_length*Hand.nand_ps); |
| 181 | HW_SendPKT(1,(u8 *)Bulk_in_buf,ops_length*Hand.nand_ps); |
193 | 182 | udc_state = BULK_IN; |
194 | 183 | break; |
195 | 184 | case NAND_READ_RAW: |
... | ... | |
197 | 186 | switch (option) |
198 | 187 | { |
199 | 188 | case OOB_ECC: |
200 | | nand_read_raw(Bulk_buf,start_addr,ops_length,option); |
201 | | HW_SendPKT(1,(u8 *)Bulk_buf,ops_length*(Hand.nand_ps + Hand.nand_os)); |
| 189 | nand_read_raw(Bulk_in_buf,start_addr,ops_length,option); |
| 190 | HW_SendPKT(1,(u8 *)Bulk_in_buf,ops_length*(Hand.nand_ps + Hand.nand_os)); |
202 | 191 | handshake_PKT[0] = (u16) ret_dat; |
203 | 192 | handshake_PKT[1] = (u16) (ret_dat>>16); |
204 | 193 | udc_state = BULK_IN; |
205 | 194 | break; |
206 | 195 | default: |
207 | | nand_read_raw(Bulk_buf,start_addr,ops_length,option); |
208 | | HW_SendPKT(1,(u8 *)Bulk_buf,ops_length*Hand.nand_ps); |
| 196 | nand_read_raw(Bulk_in_buf,start_addr,ops_length,option); |
| 197 | HW_SendPKT(1,(u8 *)Bulk_in_buf,ops_length*Hand.nand_ps); |
209 | 198 | handshake_PKT[0] = (u16) ret_dat; |
210 | 199 | handshake_PKT[1] = (u16) (ret_dat>>16); |
211 | 200 | udc_state = BULK_IN; |
... | ... | |
226 | 215 | dprintf("\n Request : NAND_READ!"); |
227 | 216 | switch (option) { |
228 | 217 | case OOB_ECC: |
229 | | ret_dat = nand_read(Bulk_buf,start_addr,ops_length,OOB_ECC); |
| 218 | ret_dat = nand_read(Bulk_in_buf,start_addr,ops_length,OOB_ECC); |
230 | 219 | handshake_PKT[0] = (u16) ret_dat; |
231 | 220 | handshake_PKT[1] = (u16) (ret_dat>>16); |
232 | | HW_SendPKT(1,(u8 *)Bulk_buf,ops_length*(Hand.nand_ps + Hand.nand_os )); |
| 221 | HW_SendPKT(1,(u8 *)Bulk_in_buf,ops_length*(Hand.nand_ps + Hand.nand_os )); |
233 | 222 | udc_state = BULK_IN; |
234 | 223 | break; |
235 | 224 | case OOB_NO_ECC: |
236 | | ret_dat = nand_read(Bulk_buf,start_addr,ops_length,OOB_NO_ECC); |
| 225 | ret_dat = nand_read(Bulk_in_buf,start_addr,ops_length,OOB_NO_ECC); |
237 | 226 | handshake_PKT[0] = (u16) ret_dat; |
238 | 227 | handshake_PKT[1] = (u16) (ret_dat>>16); |
239 | | HW_SendPKT(1,(u8 *)Bulk_buf,ops_length*(Hand.nand_ps + Hand.nand_os)); |
| 228 | HW_SendPKT(1,(u8 *)Bulk_in_buf,ops_length*(Hand.nand_ps + Hand.nand_os)); |
240 | 229 | udc_state = BULK_IN; |
241 | 230 | break; |
242 | 231 | case NO_OOB: |
243 | | ret_dat = nand_read(Bulk_buf,start_addr,ops_length,NO_OOB); |
| 232 | ret_dat = nand_read(Bulk_in_buf,start_addr,ops_length,NO_OOB); |
244 | 233 | handshake_PKT[0] = (u16) ret_dat; |
245 | 234 | handshake_PKT[1] = (u16) (ret_dat>>16); |
246 | | HW_SendPKT(1,(u8 *)Bulk_buf,ops_length*Hand.nand_ps); |
| 235 | HW_SendPKT(1,(u8 *)Bulk_in_buf,ops_length*Hand.nand_ps); |
247 | 236 | udc_state = BULK_IN; |
248 | 237 | break; |
249 | 238 | } |
... | ... | |
251 | 240 | break; |
252 | 241 | case NAND_PROGRAM: |
253 | 242 | dprintf("\n Request : NAND_PROGRAM!"); |
254 | | ret_dat = nand_program((void *)Bulk_buf, |
| 243 | ret_dat = nand_program((void *)Bulk_out_buf, |
255 | 244 | start_addr,ops_length,option); |
256 | 245 | handshake_PKT[0] = (u16) ret_dat; |
257 | 246 | handshake_PKT[1] = (u16) (ret_dat>>16); |
... | ... | |
285 | 274 | { |
286 | 275 | case SDRAM_LOAD: |
287 | 276 | //dprintf("\n Request : SDRAM_LOAD!"); |
288 | | ret_dat = (u32)memcpy((u8 *)start_addr,Bulk_buf,ops_length); |
| 277 | ret_dat = (u32)memcpy((u8 *)start_addr,Bulk_out_buf,ops_length); |
289 | 278 | handshake_PKT[0] = (u16) ret_dat; |
290 | 279 | handshake_PKT[1] = (u16) (ret_dat>>16); |
291 | 280 | HW_SendPKT(1,handshake_PKT,sizeof(handshake_PKT)); |
... | ... | |
316 | 305 | nand_enable = nand_enable_4740; |
317 | 306 | nand_disable = nand_disable_4740; |
318 | 307 | nand_mark_bad = nand_mark_bad_4740; |
319 | | break; |
320 | | case 0x4750: |
| 308 | break; |
| 309 | case 0x4760: |
321 | 310 | //Init nand flash |
322 | | nand_init_4750(Hand.nand_bw, Hand.nand_rc, Hand.nand_ps, |
| 311 | nand_init_4760(Hand.nand_bw, Hand.nand_rc, Hand.nand_ps, |
323 | 312 | Hand.nand_ppb, Hand.nand_bchbit, Hand.nand_eccpos, |
324 | 313 | Hand.nand_bbpos, Hand.nand_bbpage, Hand.nand_force_erase); |
325 | 314 | |
326 | | nand_program = nand_program_4750; |
327 | | nand_erase = nand_erase_4750; |
328 | | nand_read = nand_read_4750; |
329 | | nand_read_oob = nand_read_oob_4750; |
330 | | nand_read_raw = nand_read_raw_4750; |
331 | | nand_query = nand_query_4750; |
332 | | nand_enable = nand_enable_4750; |
333 | | nand_disable = nand_disable_4750; |
334 | | nand_mark_bad = nand_mark_bad_4750; |
335 | | break; |
| 315 | nand_program=nand_program_4760; |
| 316 | nand_erase =nand_erase_4760; |
| 317 | nand_read =nand_read_4760; |
| 318 | nand_read_oob=nand_read_oob_4760; |
| 319 | nand_read_raw=nand_read_raw_4760; |
| 320 | nand_query = nand_query_4760; |
| 321 | nand_enable = nand_enable_4760; |
| 322 | nand_disable= nand_disable_4760; |
| 323 | nand_mark_bad = nand_mark_bad_4760; |
| 324 | break; |
336 | 325 | default: |
337 | | serial_puts("Not support CPU ID!"); |
| 326 | serial_puts("\n Not support CPU ID!"); |
338 | 327 | } |
339 | 328 | } |
340 | 329 | |
usbboot/xburst_stage2/nandflash_4750.c |
1 | | /* |
2 | | * Copyright (C) 2009 Qi Hardware Inc., |
3 | | * Author: Xiangfu Liu <xiangfu@qi-hardware.com> |
4 | | * |
5 | | * This program is free software; you can redistribute it and/or |
6 | | * modify it under the terms of the GNU General Public License |
7 | | * version 3 as published by the Free Software Foundation. |
8 | | * |
9 | | * This program is distributed in the hope that it will be useful, |
10 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 | | * GNU General Public License for more details. |
13 | | * |
14 | | * You should have received a copy of the GNU General Public License |
15 | | * along with this program; if not, write to the Free Software |
16 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, |
17 | | * Boston, MA 02110-1301, USA |
18 | | */ |
19 | | #include "target/jz4750.h" |
20 | | #include "target/nandflash.h" |
21 | | #include "target/usb_boot.h" |
22 | | #include "usb_boot_defines.h" |
23 | | |
24 | | #define dprintf(n...) |
25 | | |
26 | | #define __nand_enable() (REG_EMC_NFCSR |= EMC_NFCSR_NFE1 | EMC_NFCSR_NFCE1) |
27 | | #define __nand_disable() (REG_EMC_NFCSR &= ~(EMC_NFCSR_NFCE1)) |
28 | | #define __nand_ready() ((REG_GPIO_PXPIN(2) & 0x08000000) ? 1 : 0) |
29 | | #define __nand_cmd(n) (REG8(cmdport) = (n)) |
30 | | #define __nand_addr(n) (REG8(addrport) = (n)) |
31 | | #define __nand_data8() REG8(dataport) |
32 | | #define __nand_data16() REG16(dataport) |
33 | | |
34 | | #define CMD_READA 0x00 |
35 | | #define CMD_READB 0x01 |
36 | | #define CMD_READC 0x50 |
37 | | #define CMD_ERASE_SETUP 0x60 |
38 | | #define CMD_ERASE 0xD0 |
39 | | #define CMD_READ_STATUS 0x70 |
40 | | #define CMD_CONFIRM 0x30 |
41 | | #define CMD_SEQIN 0x80 |
42 | | #define CMD_PGPROG 0x10 |
43 | | #define CMD_READID 0x90 |
44 | | |
45 | | #define ECC_BLOCK 512 |
46 | | |
47 | | static volatile unsigned char *gpio_base = (volatile unsigned char *)0xb0010000; |
48 | | static volatile unsigned char *emc_base = (volatile unsigned char *)0xb3010000; |
49 | | static volatile unsigned char *addrport = (volatile unsigned char *)0xb8010000; |
50 | | static volatile unsigned char *dataport = (volatile unsigned char *)0xb8000000; |
51 | | static volatile unsigned char *cmdport = (volatile unsigned char *)0xb8008000; |
52 | | |
53 | | static int bus = 8, row = 2, pagesize = 512, oobsize = 16, ppb = 32; |
54 | | static int eccpos = 3, bchbit = 8, par_size = 13, forceerase = 1, wp_pin; |
55 | | static int oobfs = 0; /* 1:store file system information in oob, 0:don't store */ |
56 | | static int oobecc = 0; /* Whether the oob data of the binary contains ECC data? */ |
57 | | static int bad_block_page = 127; /* Specify the page number of badblock flag inside a block */ |
58 | | static u32 bad_block_pos = 0; /* Specify the badblock flag offset inside the oob */ |
59 | | static u8 oob_buf[256] = {0}; |
60 | | extern struct hand Hand; |
61 | | extern u16 handshake_PKT[4]; |
62 | | |
63 | | static inline void __nand_sync(void) |
64 | | { |
65 | | unsigned int timeout = 10000; |
66 | | while ((REG_GPIO_PXPIN(2) & 0x08000000) && timeout--); |
67 | | while (!(REG_GPIO_PXPIN(2) & 0x08000000)); |
68 | | } |
69 | | |
70 | | static int read_oob(void *buf, u32 size, u32 pg); |
71 | | static int nand_data_write8(char *buf, int count); |
72 | | static int nand_data_write16(char *buf, int count); |
73 | | static int nand_data_read8(char *buf, int count); |
74 | | static int nand_data_read16(char *buf, int count); |
75 | | |
76 | | static int (*write_proc)(char *, int) = NULL; |
77 | | static int (*read_proc)(char *, int) = NULL; |
78 | | |
79 | | inline void nand_enable_4750(unsigned int csn) |
80 | | { |
81 | | //modify this fun to a specifical borad |
82 | | //this fun to enable the chip select pin csn |
83 | | //the choosn chip can work after this fun |
84 | | //dprintf("\n Enable chip select :%d",csn); |
85 | | __nand_enable(); |
86 | | } |
87 | | |
88 | | inline void nand_disable_4750(unsigned int csn) |
89 | | { |
90 | | //modify this fun to a specifical borad |
91 | | //this fun to enable the chip select pin csn |
92 | | //the choosn chip can not work after this fun |
93 | | //dprintf("\n Disable chip select :%d",csn); |
94 | | __nand_disable(); |
95 | | } |
96 | | |
97 | | unsigned int nand_query_4750(u8 *id) |
98 | | { |
99 | | __nand_sync(); |
100 | | __nand_cmd(CMD_READID); |
101 | | __nand_addr(0); |
102 | | |
103 | | id[0] = __nand_data8(); //VID |
104 | | id[1] = __nand_data8(); //PID |
105 | | id[2] = __nand_data8(); //CHIP ID |
106 | | id[3] = __nand_data8(); //PAGE ID |
107 | | id[4] = __nand_data8(); //PLANE ID |
108 | | |
109 | | return 0; |
110 | | } |
111 | | |
112 | | int nand_init_4750(int bus_width, int row_cycle, int page_size, int page_per_block, |
113 | | int bch_bit, int ecc_pos, int bad_pos, int bad_page, int force) |
114 | | { |
115 | | bus = bus_width; |
116 | | row = row_cycle; |
117 | | pagesize = page_size; |
118 | | oobsize = pagesize / 32; |
119 | | ppb = page_per_block; |
120 | | bchbit = bch_bit; |
121 | | forceerase = force; |
122 | | eccpos = ecc_pos; |
123 | | bad_block_pos = bad_pos; |
124 | | bad_block_page = bad_page; |
125 | | wp_pin = Hand.nand_wppin; |
126 | | |
127 | | if (bchbit == 8) |
128 | | par_size = 13; |
129 | | else |
130 | | par_size = 7; |
131 | | |
132 | | |
133 | | #if 0 |
134 | | gpio_base = (u8 *)gbase; |
135 | | emc_base = (u8 *)ebase; |
136 | | addrport = (u8 *)aport; |
137 | | dataport = (u8 *)dport; |
138 | | cmdport = (u8 *)cport; |
139 | | #endif |
140 | | /* Initialize NAND Flash Pins */ |
141 | | if (bus == 8) { |
142 | | __gpio_as_nand_8bit(); |
143 | | } |
144 | | |
145 | | if (wp_pin) |
146 | | { |
147 | | __gpio_as_output(wp_pin); |
148 | | __gpio_disable_pull(wp_pin); |
149 | | } |
150 | | __nand_enable(); |
151 | | |
152 | | // REG_EMC_SMCR1 = 0x0fff7700; //slow speed |
153 | | REG_EMC_SMCR1 = 0x04444400; //normal speed |
154 | | // REG_EMC_SMCR1 = 0x0d221200; //fast speed |
155 | | |
156 | | /* If ECCPOS isn't configured in config file, the initial value is 0 */ |
157 | | if (eccpos == 0) { |
158 | | eccpos = 3; |
159 | | } |
160 | | |
161 | | if (bus == 8) { |
162 | | write_proc = nand_data_write8; |
163 | | read_proc = nand_data_read8; |
164 | | } else { |
165 | | write_proc = nand_data_write16; |
166 | | read_proc = nand_data_read16; |
167 | | } |
168 | | return 0; |
169 | | } |
170 | | |
171 | | int nand_fini_4750(void) |
172 | | { |
173 | | __nand_disable(); |
174 | | return 0; |
175 | | } |
176 | | |
177 | | /* |
178 | | * Read oob <pagenum> pages from <startpage> page. |
179 | | * Don't skip bad block. |
180 | | * Don't use HW ECC. |
181 | | */ |
182 | | u32 nand_read_oob_4750(void *buf, u32 startpage, u32 pagenum) |
183 | | { |
184 | | u32 cnt, cur_page; |
185 | | u8 *tmpbuf; |
186 | | |
187 | | tmpbuf = (u8 *)buf; |
188 | | |
189 | | cur_page = startpage; |
190 | | cnt = 0; |
191 | | |
192 | | while (cnt < pagenum) { |
193 | | read_oob((void *)tmpbuf, oobsize, cur_page); |
194 | | tmpbuf += oobsize; |
195 | | cur_page++; |
196 | | cnt++; |
197 | | } |
198 | | |
199 | | return cur_page; |
200 | | } |
201 | | |
202 | | static int nand_check_block(u32 block) |
203 | | { |
204 | | u32 pg,i; |
205 | | |
206 | | if ( bad_block_page >= ppb ) //do absolute bad block detect! |
207 | | { |
208 | | pg = block * ppb + 0; |
209 | | read_oob(oob_buf, oobsize, pg); |
210 | | if ( oob_buf[0] != 0xff || oob_buf[1] != 0xff ) |
211 | | { |
212 | | serial_puts("Absolute skip a bad block\n"); |
213 | | serial_put_hex(block); |
214 | | return 1; |
215 | | } |
216 | | |
217 | | pg = block * ppb + 1; |
218 | | read_oob(oob_buf, oobsize, pg); |
219 | | if ( oob_buf[0] != 0xff || oob_buf[1] != 0xff ) |
220 | | { |
221 | | serial_puts("Absolute skip a bad block\n"); |
222 | | serial_put_hex(block); |
223 | | return 1; |
224 | | } |
225 | | |
226 | | pg = block * ppb + ppb - 2 ; |
227 | | read_oob(oob_buf, oobsize, pg); |
228 | | if ( oob_buf[0] != 0xff || oob_buf[1] != 0xff ) |
229 | | { |
230 | | serial_puts("Absolute skip a bad block\n"); |
231 | | serial_put_hex(block); |
232 | | return 1; |
233 | | } |
234 | | |
235 | | pg = block * ppb + ppb - 1 ; |
236 | | read_oob(oob_buf, oobsize, pg); |
237 | | if ( oob_buf[0] != 0xff || oob_buf[1] != 0xff ) |
238 | | { |
239 | | serial_puts("Absolute skip a bad block\n"); |
240 | | serial_put_hex(block); |
241 | | return 1; |
242 | | } |
243 | | |
244 | | } |
245 | | else |
246 | | { |
247 | | pg = block * ppb + bad_block_page; |
248 | | read_oob(oob_buf, oobsize, pg); |
249 | | if (oob_buf[bad_block_pos] != 0xff) |
250 | | { |
251 | | serial_puts("Skip a bad block at"); |
252 | | serial_put_hex(block); |
253 | | return 1; |
254 | | } |
255 | | |
256 | | } |
257 | | return 0; |
258 | | } |
259 | | |
260 | | |
261 | | /* |
262 | | * Read data <pagenum> pages from <startpage> page. |
263 | | * Don't skip bad block. |
264 | | * Don't use HW ECC. |
265 | | */ |
266 | | u32 nand_read_raw_4750(void *buf, u32 startpage, u32 pagenum, int option) |
267 | | { |
268 | | u32 cnt, j; |
269 | | u32 cur_page, rowaddr; |
270 | | u8 *tmpbuf; |
271 | | |
272 | | tmpbuf = (u8 *)buf; |
273 | | |
274 | | cur_page = startpage; |
275 | | cnt = 0; |
276 | | while (cnt < pagenum) { |
277 | | if ((cur_page % ppb) == 0) { |
278 | | if (nand_check_block(cur_page / ppb)) { |
279 | | cur_page += ppb; // Bad block, set to next block |
280 | | continue; |
281 | | } |
282 | | } |
283 | | |
284 | | __nand_cmd(CMD_READA); |
285 | | __nand_addr(0); |
286 | | if (pagesize != 512) |
287 | | __nand_addr(0); |
288 | | |
289 | | rowaddr = cur_page; |
290 | | for (j = 0; j < row; j++) { |
291 | | __nand_addr(rowaddr & 0xff); |
292 | | rowaddr >>= 8; |
293 | | } |
294 | | |
295 | | if (pagesize != 512) |
296 | | __nand_cmd(CMD_CONFIRM); |
297 | | |
298 | | __nand_sync(); |
299 | | read_proc(tmpbuf, pagesize); |
300 | | |
301 | | tmpbuf += pagesize; |
302 | | if (option != NO_OOB) |
303 | | { |
304 | | read_oob(tmpbuf, oobsize, cur_page); |
305 | | tmpbuf += oobsize; |
306 | | } |
307 | | |
308 | | cur_page++; |
309 | | cnt++; |
310 | | } |
311 | | |
312 | | return cur_page; |
313 | | } |
314 | | |
315 | | |
316 | | u32 nand_erase_4750(int blk_num, int sblk, int force) |
317 | | { |
318 | | int i, j; |
319 | | u32 cur, rowaddr; |
320 | | |
321 | | if (wp_pin) |
322 | | __gpio_set_pin(wp_pin); |
323 | | cur = sblk * ppb; |
324 | | for (i = 0; i < blk_num; i++) { |
325 | | rowaddr = cur; |
326 | | |
327 | | if (!force) /* if set, erase anything */ |
328 | | if (nand_check_block(cur/ppb)) |
329 | | { |
330 | | cur += ppb; |
331 | | blk_num += Hand.nand_plane; |
332 | | continue; |
333 | | } |
334 | | |
335 | | __nand_cmd(CMD_ERASE_SETUP); |
336 | | |
337 | | for (j = 0; j < row; j++) { |
338 | | __nand_addr(rowaddr & 0xff); |
339 | | rowaddr >>= 8; |
340 | | } |
341 | | __nand_cmd(CMD_ERASE); |
342 | | __nand_sync(); |
343 | | __nand_cmd(CMD_READ_STATUS); |
344 | | |
345 | | if (__nand_data8() & 0x01) |
346 | | { |
347 | | serial_puts("Erase fail at "); |
348 | | serial_put_hex(cur / ppb); |
349 | | nand_mark_bad_4750(cur / ppb); |
350 | | cur += ppb; |
351 | | blk_num += Hand.nand_plane; |
352 | | continue; |
353 | | } |
354 | | cur += ppb; |
355 | | } |
356 | | |
357 | | if (wp_pin) |
358 | | __gpio_clear_pin(wp_pin); |
359 | | return cur; |
360 | | } |
361 | | |
362 | | static int read_oob(void *buf, u32 size, u32 pg) |
363 | | { |
364 | | u32 i, coladdr, rowaddr; |
365 | | |
366 | | if (pagesize == 512) |
367 | | coladdr = 0; |
368 | | else |
369 | | coladdr = pagesize; |
370 | | |
371 | | if (pagesize == 512) |
372 | | /* Send READOOB command */ |
373 | | __nand_cmd(CMD_READC); |
374 | | else |
375 | | /* Send READ0 command */ |
376 | | __nand_cmd(CMD_READA); |
377 | | |
378 | | /* Send column address */ |
379 | | __nand_addr(coladdr & 0xff); |
380 | | if (pagesize != 512) |
381 | | __nand_addr(coladdr >> 8); |
382 | | |
383 | | /* Send page address */ |
384 | | rowaddr = pg; |
385 | | for (i = 0; i < row; i++) { |
386 | | __nand_addr(rowaddr & 0xff); |
387 | | rowaddr >>= 8; |
388 | | } |
389 | | |
390 | | /* Send READSTART command for 2048 or 4096 ps NAND */ |
391 | | if (pagesize != 512) |
392 | | __nand_cmd(CMD_CONFIRM); |
393 | | |
394 | | /* Wait for device ready */ |
395 | | __nand_sync(); |
396 | | |
397 | | /* Read oob data */ |
398 | | read_proc(buf, size); |
399 | | |
400 | | if (pagesize == 512) |
401 | | __nand_sync(); |
402 | | |
403 | | return 0; |
404 | | } |
405 | | |
406 | | static void bch_correct(unsigned char *dat, int idx) |
407 | | { |
408 | | int i, bit; // the 'bit' of i byte is error |
409 | | i = (idx - 1) >> 3; |
410 | | bit = (idx - 1) & 0x7; |
411 | | dat[i] ^= (1 << bit); |
412 | | } |
413 | | |
414 | | /* |
415 | | * Read data <pagenum> pages from <startpage> page. |
416 | | * Skip bad block if detected. |
417 | | * HW ECC is used. |
418 | | */ |
419 | | u32 nand_read_4750(void *buf, u32 startpage, u32 pagenum, int option) |
420 | | { |
421 | | u32 j, k; |
422 | | u32 cur_page, cur_blk, cnt, rowaddr, ecccnt; |
423 | | u8 *tmpbuf, *p, flag = 0; |
424 | | u32 oob_per_eccsize; |
425 | | |
426 | | ecccnt = pagesize / ECC_BLOCK; |
427 | | oob_per_eccsize = eccpos / ecccnt; |
428 | | |
429 | | cur_page = startpage; |
430 | | cnt = 0; |
431 | | |
432 | | tmpbuf = buf; |
433 | | |
434 | | while (cnt < pagenum) { |
435 | | /* If this is the first page of the block, check for bad. */ |
436 | | if ((cur_page % ppb) == 0) { |
437 | | cur_blk = cur_page / ppb; |
438 | | if (nand_check_block(cur_blk)) { |
439 | | cur_page += ppb; // Bad block, set to next block |
440 | | continue; |
441 | | } |
442 | | } |
443 | | __nand_cmd(CMD_READA); |
444 | | |
445 | | __nand_addr(0); |
446 | | if (pagesize != 512) |
447 | | __nand_addr(0); |
448 | | |
449 | | rowaddr = cur_page; |
450 | | for (j = 0; j < row; j++) { |
451 | | __nand_addr(rowaddr & 0xff); |
452 | | rowaddr >>= 8; |
453 | | } |
454 | | |
455 | | if (pagesize != 512) |
456 | | __nand_cmd(CMD_CONFIRM); |
457 | | |
458 | | __nand_sync(); |
459 | | |
460 | | /* Read data */ |
461 | | read_proc((char *)tmpbuf, pagesize); |
462 | | |
463 | | /* read oob first */ |
464 | | read_proc((char *)oob_buf, oobsize); |
465 | | |
466 | | for (j = 0; j < ecccnt; j++) { |
467 | | u32 stat; |
468 | | flag = 0; |
469 | | REG_BCH_INTS = 0xffffffff; |
470 | | |
471 | | if (cur_page >= 16384 / pagesize) |
472 | | { |
473 | | if (bchbit == 8) |
474 | | { |
475 | | __ecc_decoding_8bit(); |
476 | | par_size = 13; |
477 | | } |
478 | | else |
479 | | { |
480 | | __ecc_decoding_4bit(); |
481 | | par_size = 7; |
482 | | } |
483 | | } |
484 | | else |
485 | | { |
486 | | __ecc_decoding_8bit(); |
487 | | par_size = 13; |
488 | | } |
489 | | |
490 | | if (option != NO_OOB) |
491 | | __ecc_cnt_dec(ECC_BLOCK + oob_per_eccsize + par_size); |
492 | | else |
493 | | __ecc_cnt_dec(ECC_BLOCK + par_size); |
494 | | |
495 | | for (k = 0; k < ECC_BLOCK; k++) { |
496 | | REG_BCH_DR = tmpbuf[k]; |
497 | | } |
498 | | |
499 | | if (option != NO_OOB) { |
500 | | for (k = 0; k < oob_per_eccsize; k++) { |
501 | | REG_BCH_DR = oob_buf[oob_per_eccsize * j + k]; |
502 | | } |
503 | | } |
504 | | |
505 | | for (k = 0; k < par_size; k++) { |
506 | | REG_BCH_DR = oob_buf[eccpos + j*par_size + k]; |
507 | | if (oob_buf[eccpos + j*par_size + k] != 0xff) |
508 | | flag = 1; |
509 | | } |
510 | | |
511 | | /* Wait for completion */ |
512 | | __ecc_decode_sync(); |
513 | | __ecc_disable(); |
514 | | /* Check decoding */ |
515 | | stat = REG_BCH_INTS; |
516 | | |
517 | | if (stat & BCH_INTS_ERR) { |
518 | | if (stat & BCH_INTS_UNCOR) { |
519 | | if (flag) |
520 | | { |
521 | | dprintf("Uncorrectable ECC error occurred\n"); |
522 | | handshake_PKT[3] = 1; |
523 | | } |
524 | | } |
525 | | else { |
526 | | handshake_PKT[3] = 0; |
527 | | unsigned int errcnt = (stat & BCH_INTS_ERRC_MASK) >> BCH_INTS_ERRC_BIT; |
528 | | switch (errcnt) { |
529 | | case 8: |
530 | | dprintf("correct 8th error\n"); |
531 | | bch_correct(tmpbuf, (REG_BCH_ERR3 & BCH_ERR_INDEX_ODD_MASK) >> BCH_ERR_INDEX_ODD_BIT); |
532 | | case 7: |
533 | | dprintf("correct 7th error\n"); |
534 | | bch_correct(tmpbuf, (REG_BCH_ERR3 & BCH_ERR_INDEX_EVEN_MASK) >> BCH_ERR_INDEX_EVEN_BIT); |
535 | | case 6: |
536 | | dprintf("correct 6th error\n"); |
537 | | bch_correct(tmpbuf, (REG_BCH_ERR2 & BCH_ERR_INDEX_ODD_MASK) >> BCH_ERR_INDEX_ODD_BIT); |
538 | | case 5: |
539 | | dprintf("correct 5th error\n"); |
540 | | bch_correct(tmpbuf, (REG_BCH_ERR2 & BCH_ERR_INDEX_EVEN_MASK) >> BCH_ERR_INDEX_EVEN_BIT); |
541 | | case 4: |
542 | | dprintf("correct 4th error\n"); |
543 | | bch_correct(tmpbuf, (REG_BCH_ERR1 & BCH_ERR_INDEX_ODD_MASK) >> BCH_ERR_INDEX_ODD_BIT); |
544 | | case 3: |
545 | | dprintf("correct 3th error\n"); |
546 | | bch_correct(tmpbuf, (REG_BCH_ERR1 & BCH_ERR_INDEX_EVEN_MASK) >> BCH_ERR_INDEX_EVEN_BIT); |
547 | | case 2: |
548 | | dprintf("correct 2th error\n"); |
549 | | bch_correct(tmpbuf, (REG_BCH_ERR0 & BCH_ERR_INDEX_ODD_MASK) >> BCH_ERR_INDEX_ODD_BIT); |
550 | | case 1: |
551 | | dprintf("correct 1th error\n"); |
552 | | bch_correct(tmpbuf, (REG_BCH_ERR0 & BCH_ERR_INDEX_EVEN_MASK) >> BCH_ERR_INDEX_EVEN_BIT); |
553 | | break; |
554 | | default: |
555 | | dprintf("no error\n"); |
556 | | break; |
557 | | } |
558 | | } |
559 | | } |
560 | | /* increment pointer */ |
561 | | tmpbuf += ECC_BLOCK; |
562 | | } |
563 | | |
564 | | switch (option) |
565 | | { |
566 | | case OOB_ECC: |
567 | | for (j = 0; j < oobsize; j++) |
568 | | tmpbuf[j] = oob_buf[j]; |
569 | | tmpbuf += oobsize; |
570 | | break; |
571 | | case OOB_NO_ECC: |
572 | | for (j = 0; j < par_size * ecccnt; j++) |
573 | | oob_buf[eccpos + j] = 0xff; |
574 | | for (j = 0; j < oobsize; j++) |
575 | | tmpbuf[j] = oob_buf[j]; |
576 | | tmpbuf += oobsize; |
577 | | break; |
578 | | case NO_OOB: |
579 | | break; |
580 | | } |
581 | | |
582 | | cur_page++; |
583 | | cnt++; |
584 | | } |
585 | | return cur_page; |
586 | | } |
587 | | |
588 | | u32 nand_program_4750(void *context, int spage, int pages, int option) |
589 | | { |
590 | | u32 i, j, cur_page, cur_blk, rowaddr; |
591 | | u8 *tmpbuf; |
592 | | u32 ecccnt; |
593 | | u8 ecc_buf[256]; |
594 | | u32 oob_per_eccsize; |
595 | | int eccpos_sav = eccpos, bchbit_sav = bchbit, par_size_sav = par_size; |
596 | | int spl_size = 16 * 1024 / pagesize; |
597 | | |
598 | | if (wp_pin) |
599 | | __gpio_set_pin(wp_pin); |
600 | | restart: |
601 | | tmpbuf = (u8 *)context; |
602 | | ecccnt = pagesize / ECC_BLOCK; |
603 | | oob_per_eccsize = eccpos / ecccnt; |
604 | | |
605 | | i = 0; |
606 | | cur_page = spage; |
607 | | |
608 | | while (i < pages) { |
609 | | if (cur_page < spl_size) { |
610 | | bchbit = 8; |
611 | | eccpos = 3; |
612 | | par_size = 13; |
613 | | } else if (cur_page >= spl_size) { |
614 | | bchbit = bchbit_sav; |
615 | | eccpos = eccpos_sav; |
616 | | par_size = par_size_sav; |
617 | | } |
618 | | |
619 | | if ((cur_page % ppb) == 0) { /* First page of block, test BAD. */ |
620 | | if (nand_check_block(cur_page / ppb)) { |
621 | | cur_page += ppb; /* Bad block, set to next block */ |
622 | | continue; |
623 | | } |
624 | | } |
625 | | |
626 | | if ( option != NO_OOB ) //if NO_OOB do not perform vaild check! |
627 | | { |
628 | | for ( j = 0 ; j < pagesize + oobsize; j ++) |
629 | | { |
630 | | if (tmpbuf[j] != 0xff) |
631 | | break; |
632 | | } |
633 | | if ( j == oobsize + pagesize ) |
634 | | { |
635 | | tmpbuf += ( pagesize + oobsize ) ; |
636 | | i ++; |
637 | | cur_page ++; |
638 | | continue; |
639 | | } |
640 | | } |
641 | | |
642 | | if (pagesize == 512) |
643 | | __nand_cmd(CMD_READA); |
644 | | |
645 | | __nand_cmd(CMD_SEQIN); |
646 | | __nand_addr(0); |
647 | | |
648 | | if (pagesize != 512) |
649 | | __nand_addr(0); |
650 | | |
651 | | rowaddr = cur_page; |
652 | | for (j = 0; j < row; j++) { |
653 | | __nand_addr(rowaddr & 0xff); |
654 | | rowaddr >>= 8; |
655 | | } |
656 | | |
657 | | /* write out data */ |
658 | | for (j = 0; j < ecccnt; j++) { |
659 | | volatile u8 *paraddr; |
660 | | int k; |
661 | | |
662 | | paraddr = (volatile u8 *)BCH_PAR0; |
663 | | |
664 | | REG_BCH_INTS = 0xffffffff; |
665 | | |
666 | | if (bchbit == 8) |
667 | | __ecc_encoding_8bit(); |
668 | | else |
669 | | __ecc_encoding_4bit(); |
670 | | |
671 | | /* Set BCHCNT.DEC_COUNT to data block size in bytes */ |
672 | | if (option != NO_OOB) |
673 | | __ecc_cnt_enc(ECC_BLOCK + oob_per_eccsize); |
674 | | else |
675 | | __ecc_cnt_enc(ECC_BLOCK); |
676 | | |
677 | | /* Write data in data area to BCH */ |
678 | | for (k = 0; k < ECC_BLOCK; k++) { |
679 | | REG_BCH_DR = tmpbuf[ECC_BLOCK * j + k]; |
680 | | } |
681 | | |
682 | | /* Write file system information in oob area to BCH */ |
683 | | if (option != NO_OOB) |
684 | | { |
685 | | for (k = 0; k < oob_per_eccsize; k++) { |
686 | | REG_BCH_DR = tmpbuf[pagesize + oob_per_eccsize * j + k]; |
687 | | } |
688 | | } |
689 | | |
690 | | __ecc_encode_sync(); |
691 | | __ecc_disable(); |
692 | | |
693 | | /* Read PAR values */ |
694 | | for (k = 0; k < par_size; k++) { |
695 | | ecc_buf[j * par_size + k] = *paraddr++; |
696 | | } |
697 | | |
698 | | write_proc((char *)&tmpbuf[ECC_BLOCK * j], ECC_BLOCK); |
699 | | } |
700 | | |
701 | | switch (option) |
702 | | { |
703 | | case OOB_ECC: |
704 | | case OOB_NO_ECC: |
705 | | for (j = 0; j < eccpos; j++) { |
706 | | oob_buf[j] = tmpbuf[pagesize + j]; |
707 | | } |
708 | | for (j = 0; j < ecccnt * par_size; j++) { |
709 | | oob_buf[eccpos + j] = ecc_buf[j]; |
710 | | } |
711 | | tmpbuf += pagesize + oobsize; |
712 | | break; |
713 | | case NO_OOB: //bin image |
714 | | for (j = 0; j < ecccnt * par_size; j++) { |
715 | | oob_buf[eccpos + j] = ecc_buf[j]; |
716 | | } |
717 | | tmpbuf += pagesize; |
718 | | break; |
719 | | } |
720 | | |
721 | | /* write out oob buffer */ |
722 | | write_proc((u8 *)oob_buf, oobsize); |
723 | | |
724 | | /* send program confirm command */ |
725 | | __nand_cmd(CMD_PGPROG); |
726 | | __nand_sync(); |
727 | | |
728 | | __nand_cmd(CMD_READ_STATUS); |
729 | | |
730 | | if (__nand_data8() & 0x01) /* page program error */ |
731 | | { |
732 | | serial_puts("Skip a write fail block\n"); |
733 | | nand_erase_4750( 1, cur_page/ppb, 1); //force erase before |
734 | | nand_mark_bad_4750(cur_page/ppb); |
735 | | spage += ppb; |
736 | | goto restart; |
737 | | } |
738 | | |
739 | | i++; |
740 | | cur_page++; |
741 | | } |
742 | | |
743 | | if (wp_pin) |
744 | | __gpio_clear_pin(wp_pin); |
745 | | bchbit = bchbit_sav; |
746 | | eccpos = eccpos_sav; |
747 | | par_size = par_size_sav; |
748 | | |
749 | | return cur_page; |
750 | | } |
751 | | |
752 | | static u32 nand_mark_bad_page(u32 page) |
753 | | { |
754 | | u8 badbuf[4096 + 128]; |
755 | | u32 i; |
756 | | |
757 | | if (wp_pin) |
758 | | __gpio_set_pin(wp_pin); |
759 | | for (i = 0; i < pagesize + oobsize; i++) |
760 | | badbuf[i] = 0x00; |
761 | | //all set to 0x00 |
762 | | |
763 | | __nand_cmd(CMD_READA); |
764 | | __nand_cmd(CMD_SEQIN); |
765 | | |
766 | | __nand_addr(0); |
767 | | if (pagesize != 512) |
768 | | __nand_addr(0); |
769 | | for (i = 0; i < row; i++) { |
770 | | __nand_addr(page & 0xff); |
771 | | page >>= 8; |
772 | | } |
773 | | |
774 | | write_proc((char *)badbuf, pagesize + oobsize); |
775 | | __nand_cmd(CMD_PGPROG); |
776 | | __nand_sync(); |
777 | | |
778 | | if (wp_pin) |
779 | | __gpio_clear_pin(wp_pin); |
780 | | return page; |
781 | | } |
782 | | |
783 | | u32 nand_mark_bad_4750(int block) |
784 | | { |
785 | | u32 rowaddr; |
786 | | |
787 | | if ( bad_block_page >= ppb ) //absolute bad block mark! |
788 | | { //mark four page! |
789 | | rowaddr = block * ppb + 0; |
790 | | nand_mark_bad_page(rowaddr); |
791 | | |
792 | | rowaddr = block * ppb + 1; |
793 | | nand_mark_bad_page(rowaddr); |
794 | | |
795 | | rowaddr = block * ppb + ppb - 2; |
796 | | nand_mark_bad_page(rowaddr); |
797 | | |
798 | | rowaddr = block * ppb + ppb - 1; |
799 | | nand_mark_bad_page(rowaddr); |
800 | | } |
801 | | else //mark one page only |
802 | | { |
803 | | rowaddr = block * ppb + bad_block_page; |
804 | | nand_mark_bad_page(rowaddr); |
805 | | } |
806 | | |
807 | | return rowaddr; |
808 | | } |
809 | | |
810 | | static int nand_data_write8(char *buf, int count) |
811 | | { |
812 | | int i; |
813 | | u8 *p = (u8 *)buf; |
814 | | for (i=0;i<count;i++) |
815 | | __nand_data8() = *p++; |
816 | | return 0; |
817 | | } |
818 | | |
819 | | static int nand_data_write16(char *buf, int count) |
820 | | { |
821 | | int i; |
822 | | u16 *p = (u16 *)buf; |
823 | | for (i=0;i<count/2;i++) |
824 | | __nand_data16() = *p++; |
825 | | return 0; |
826 | | } |
827 | | |
828 | | static int nand_data_read8(char *buf, int count) |
829 | | { |
830 | | int i; |
831 | | u8 *p = (u8 *)buf; |
832 | | for (i=0;i<count;i++) |
833 | | *p++ = __nand_data8(); |
834 | | return 0; |
835 | | } |
836 | | |
837 | | static int nand_data_read16(char *buf, int count) |
838 | | { |
839 | | int i; |
840 | | u16 *p = (u16 *)buf; |
841 | | for (i=0;i<count/2;i++) |
842 | | *p++ = __nand_data16(); |
843 | | return 0; |
844 | | } |
usbboot/xburst_stage2/nandflash_4760.c |
| 1 | /* |
| 2 | * Copyright (C) 2007 Ingenic Semiconductor Inc. |
| 3 | * Author: Regen Huang <lhhuang@ingenic.cn> |
| 4 | * |
| 5 | * This program is free software; you can redistribute it and/or |
| 6 | * modify it under the terms of the GNU General Public License as |
| 7 | * published by the Free Software Foundation; either version 2 of |
| 8 | * the License, or (at your option) any later version. |
| 9 | * |
| 10 | * This program is distributed in the hope that it will be useful, |
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 13 | * GNU General Public License for more details. |
| 14 | * |
| 15 | * You should have received a copy of the GNU General Public License |
| 16 | * along with this program; if not, write to the Free Software |
| 17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, |
| 18 | * MA 02111-1307 USA |
| 19 | */ |
| 20 | |
| 21 | #include "target/jz4760.h" |
| 22 | #include "target/nandflash.h" |
| 23 | #include "target/usb_boot.h" |
| 24 | #include "usb_boot_defines.h" |
| 25 | |
| 26 | #define USE_BCH 1 |
| 27 | #define USE_PN 1 |
| 28 | #define NEMC_PNCR (NEMC_BASE + 0x100) |
| 29 | #define NEMC_PNDR (NEMC_BASE + 0x104) |
| 30 | #define REG_NEMC_PNCR REG32(NEMC_PNCR) |
| 31 | #define REG_NEMC_PNDR REG32(NEMC_PNDR) |
| 32 | |
| 33 | #define pn_enable() \ |
| 34 | do {\ |
| 35 | REG_NEMC_PNCR = 0x3;\ |
| 36 | }while(0) |
| 37 | #define pn_disable() \ |
| 38 | do {\ |
| 39 | REG_NEMC_PNCR = 0x0;\ |
| 40 | }while(0) |
| 41 | |
| 42 | #ifdef DEBUG |
| 43 | #define dprintf(n...) printf(n) |
| 44 | #else |
| 45 | #define dprintf(n...) |
| 46 | #endif |
| 47 | |
| 48 | /* for spl */ |
| 49 | #define ECC_BLOCK0 256 |
| 50 | #define PAR_SIZE_SPL 78 |
| 51 | #define PAR_SIZE_SPL1 ((PAR_SIZE_SPL+1)/2) |
| 52 | |
| 53 | /* |
| 54 | * NAND flash definitions |
| 55 | */ |
| 56 | #define NAND_DATAPORT 0x1A000000 |
| 57 | #define NAND_ADDRPORT 0x1A800000 |
| 58 | #define NAND_COMMPORT 0x1A400000 |
| 59 | |
| 60 | #define ECC_BLOCK 512 |
| 61 | static int par_size, par_size1; |
| 62 | |
| 63 | #define CMD_READA 0x00 |
| 64 | #define CMD_READB 0x01 |
| 65 | #define CMD_READC 0x50 |
| 66 | #define CMD_ERASE_SETUP 0x60 |
| 67 | #define CMD_ERASE 0xD0 |
| 68 | #define CMD_READ_STATUS 0x70 |
| 69 | #define CMD_CONFIRM 0x30 |
| 70 | #define CMD_SEQIN 0x80 |
| 71 | #define CMD_PGPROG 0x10 |
| 72 | #define CMD_READID 0x90 |
| 73 | |
| 74 | #define __nand_cmd(n) (REG8(NAND_COMMPORT) = (n)) |
| 75 | #define __nand_addr(n) (REG8(NAND_ADDRPORT) = (n)) |
| 76 | #define __nand_data8() REG8(NAND_DATAPORT) |
| 77 | #define __nand_data16() REG16(NAND_DATAPORT) |
| 78 | |
| 79 | #define __nand_enable() (REG_NEMC_NFCSR |= NEMC_NFCSR_NFE1 | NEMC_NFCSR_NFCE1) |
| 80 | #define __nand_disable() (REG_NEMC_NFCSR &= ~(NEMC_NFCSR_NFCE1)) |
| 81 | |
| 82 | static int bus = 8, row = 2, pagesize = 512, oobsize = 16, ppb = 32; |
| 83 | static int eccpos = 3, bchbit = 8, par_size = 26, par_size1 = 13, forceerase = 1, wp_pin = 0; |
| 84 | static int oobfs = 0; /* 1:store file system information in oob, 0:don't store */ |
| 85 | static int oobecc = 0; /* Whether the oob data of the binary contains ECC data? */ |
| 86 | static int bad_block_page = 127; /* Specify the page number of badblock flag inside a block */ |
| 87 | static u32 bad_block_pos = 0; /* Specify the badblock flag offset inside the oob */ |
| 88 | static u8 oob_buf[256] = {0}; |
| 89 | extern struct hand Hand; |
| 90 | extern u16 handshake_PKT[4]; |
| 91 | |
| 92 | static inline void __nand_sync(void) |
| 93 | { |
| 94 | unsigned int timeout = 1000; |
| 95 | while ((REG_GPIO_PXPIN(0) & 0x00100000) && timeout--); |
| 96 | while (!(REG_GPIO_PXPIN(0) & 0x00100000)); |
| 97 | } |
| 98 | |
| 99 | /* |
| 100 | * External routines |
| 101 | */ |
| 102 | extern void flush_cache_all(void); |
| 103 | extern int serial_init(void); |
| 104 | extern void serial_puts(const char *s); |
| 105 | extern void sdram_init(void); |
| 106 | extern void pll_init(void); |
| 107 | |
| 108 | static int read_oob(void *buf, u32 size, u32 pg); |
| 109 | static int nand_data_write8(char *buf, int count); |
| 110 | static int nand_data_write16(char *buf, int count); |
| 111 | static int nand_data_read8(char *buf, int count); |
| 112 | static int nand_data_read16(char *buf, int count); |
| 113 | |
| 114 | static int (*write_proc)(char *, int) = NULL; |
| 115 | static int (*read_proc)(char *, int) = NULL; |
| 116 | |
| 117 | int read_nand_spl_page(unsigned char *databuf, unsigned int pageaddr); |
| 118 | int program_nand_spl_page(unsigned char *databuf, unsigned int pageaddr); |
| 119 | |
| 120 | /* |
| 121 | * NAND flash routines |
| 122 | */ |
| 123 | |
| 124 | static inline void nand_read_buf16(void *buf, int count) |
| 125 | { |
| 126 | int i; |
| 127 | u16 *p = (u16 *)buf; |
| 128 | |
| 129 | for (i = 0; i < count; i += 2) |
| 130 | *p++ = __nand_data16(); |
| 131 | } |
| 132 | |
| 133 | static inline void nand_read_buf8(void *buf, int count) |
| 134 | { |
| 135 | int i; |
| 136 | u8 *p = (u8 *)buf; |
| 137 | |
| 138 | for (i = 0; i < count; i++) |
| 139 | *p++ = __nand_data8(); |
| 140 | } |
| 141 | |
| 142 | static inline void nand_read_buf(void *buf, int count, int bw) |
| 143 | { |
| 144 | if (bw == 8) |
| 145 | nand_read_buf8(buf, count); |
| 146 | else |
| 147 | nand_read_buf16(buf, count); |
| 148 | } |
| 149 | |
| 150 | inline void nand_enable_4760(unsigned int csn) |
| 151 | { |
| 152 | //modify this fun to a specifical borad |
| 153 | //this fun to enable the chip select pin csn |
| 154 | //the choosn chip can work after this fun |
| 155 | //dprintf("\n Enable chip select :%d",csn); |
| 156 | __nand_enable(); |
| 157 | __gpio_as_nand_8bit(1); |
| 158 | } |
| 159 | |
| 160 | inline void nand_disable_4760(unsigned int csn) |
| 161 | { |
| 162 | //modify this fun to a specifical borad |
| 163 | //this fun to enable the chip select pin csn |
| 164 | //the choosn chip can not work after this fun |
| 165 | //dprintf("\n Disable chip select :%d",csn); |
| 166 | __nand_disable(); |
| 167 | } |
| 168 | |
| 169 | void udelay(unsigned long usec) |
| 170 | { |
| 171 | volatile int i, j; |
| 172 | |
| 173 | for (i = 0; i < usec; i++) { |
| 174 | for (j = 0; j < 100; j++) { |
| 175 | ; |
| 176 | } |
| 177 | } |
| 178 | } |
| 179 | |
| 180 | unsigned int nand_query_4760(u8 *id) |
| 181 | { |
| 182 | u8 i, vid=0, did=0; |
| 183 | __nand_disable(); |
| 184 | __nand_enable(); |
| 185 | #if 1 |
| 186 | __nand_cmd(0xff); |
| 187 | __nand_sync(); |
| 188 | #endif |
| 189 | __nand_cmd(CMD_READID); |
| 190 | __nand_addr(0); |
| 191 | |
| 192 | udelay(1000); |
| 193 | #if 1 |
| 194 | id[0] = __nand_data8(); //VID |
| 195 | id[1] = __nand_data8(); //PID |
| 196 | id[2] = __nand_data8(); //CHIP ID |
| 197 | id[3] = __nand_data8(); //PAGE ID |
| 198 | id[4] = __nand_data8(); //PLANE ID |
| 199 | |
| 200 | serial_put_hex(id[0]); |
| 201 | serial_put_hex(id[1]); |
| 202 | serial_put_hex(id[2]); |
| 203 | serial_put_hex(id[3]); |
| 204 | serial_put_hex(id[4]); |
| 205 | |
| 206 | #endif |
| 207 | |
| 208 | __nand_disable(); |
| 209 | return 0; |
| 210 | } |
| 211 | |
| 212 | int nand_init_4760(int bus_width, int row_cycle, int page_size, int page_per_block, |
| 213 | int bch_bit, int ecc_pos, int bad_pos, int bad_page, int force) |
| 214 | { |
| 215 | bus = bus_width; |
| 216 | row = row_cycle; |
| 217 | pagesize = page_size; |
| 218 | oobsize = pagesize / 32; |
| 219 | ppb = page_per_block; |
| 220 | bchbit = bch_bit; |
| 221 | forceerase = force; |
| 222 | eccpos = ecc_pos; |
| 223 | bad_block_pos = bad_pos; |
| 224 | bad_block_page = bad_page; |
| 225 | wp_pin = Hand.nand_wppin; |
| 226 | |
| 227 | if(bchbit == 4) |
| 228 | par_size = 13; |
| 229 | else if(bchbit == 8) |
| 230 | par_size = 26; |
| 231 | else if(bchbit == 12) |
| 232 | par_size =39; |
| 233 | else if(bchbit == 16) |
| 234 | par_size =52; |
| 235 | else if(bchbit == 20) |
| 236 | par_size = 65; |
| 237 | else |
| 238 | par_size ==78; |
| 239 | |
| 240 | par_size1 = (par_size + 1)/2; |
| 241 | |
| 242 | /* Initialize NAND Flash Pins */ |
| 243 | if (bus == 8) { |
| 244 | REG_NEMC_SMCR1 = 0x0d444400; |
| 245 | // REG_NEMC_SMCR1 = 0x0fff7700; /* slower */ |
| 246 | __gpio_as_nand_8bit(1); |
| 247 | write_proc = nand_data_write8; |
| 248 | read_proc = nand_data_read8; |
| 249 | } else { |
| 250 | REG_NEMC_SMCR1 = 0x0d444400 | 0x40; |
| 251 | __gpio_as_nand_16bit(1); |
| 252 | write_proc = nand_data_write16; |
| 253 | read_proc = nand_data_read16; |
| 254 | } |
| 255 | |
| 256 | if (wp_pin) |
| 257 | { |
| 258 | __gpio_as_output(wp_pin); |
| 259 | __gpio_disable_pull(wp_pin); |
| 260 | } |
| 261 | __nand_enable(); |
| 262 | |
| 263 | /* If ECCPOS isn't configured in config file, the initial value is 0 */ |
| 264 | if (eccpos == 0) { |
| 265 | eccpos = 3; |
| 266 | } |
| 267 | |
| 268 | #ifdef USE_BCH |
| 269 | serial_puts("Use bch.\n"); |
| 270 | #else |
| 271 | serial_puts("Not use bch.\n"); |
| 272 | #endif |
| 273 | #ifdef USE_PN |
| 274 | serial_puts("Use PN.\n"); |
| 275 | #else |
| 276 | serial_puts("Not use PN.\n"); |
| 277 | #endif |
| 278 | return 0; |
| 279 | } |
| 280 | |
| 281 | /* |
| 282 | * Correct the error bit in ECC_BLOCK bytes data |
| 283 | */ |
| 284 | static void bch_correct(unsigned char *dat, int idx) |
| 285 | { |
| 286 | int i, bit; // the 'bit' of i byte is error |
| 287 | i = (idx - 1) >> 3; |
| 288 | bit = (idx - 1) & 0x7; |
| 289 | if (i < ECC_BLOCK) |
| 290 | dat[i] ^= (1 << bit); |
| 291 | } |
| 292 | |
| 293 | u32 nand_read_oob_4760(void *buf, u32 startpage, u32 pagenum) |
| 294 | { |
| 295 | u32 cnt, cur_page; |
| 296 | u8 *tmpbuf; |
| 297 | |
| 298 | tmpbuf = (u8 *)buf; |
| 299 | |
| 300 | cur_page = startpage; |
| 301 | cnt = 0; |
| 302 | |
| 303 | while (cnt < pagenum) { |
| 304 | read_oob((void *)tmpbuf, oobsize, cur_page); |
| 305 | tmpbuf += oobsize; |
| 306 | cur_page++; |
| 307 | cnt++; |
| 308 | } |
| 309 | |
| 310 | return cur_page; |
| 311 | } |
| 312 | |
| 313 | static int nand_check_block(u32 block) |
| 314 | { |
| 315 | u32 pg,i; |
| 316 | |
| 317 | if ( bad_block_page >= ppb ) //do absolute bad block detect! |
| 318 | { |
| 319 | pg = block * ppb + 0; |
| 320 | read_oob(oob_buf, oobsize, pg); |
| 321 | if ( oob_buf[0] != 0xff || oob_buf[1] != 0xff ) |
| 322 | { |
| 323 | serial_puts("Absolute skip a bad block\n"); |
| 324 | serial_put_hex(block); |
| 325 | return 1; |
| 326 | } |
| 327 | |
| 328 | pg = block * ppb + 1; |
| 329 | read_oob(oob_buf, oobsize, pg); |
| 330 | if ( oob_buf[0] != 0xff || oob_buf[1] != 0xff ) |
| 331 | { |
| 332 | serial_puts("Absolute skip a bad block\n"); |
| 333 | serial_put_hex(block); |
| 334 | return 1; |
| 335 | } |
| 336 | |
| 337 | pg = block * ppb + ppb - 2 ; |
| 338 | read_oob(oob_buf, oobsize, pg); |
| 339 | if ( oob_buf[0] != 0xff || oob_buf[1] != 0xff ) |
| 340 | { |
| 341 | serial_puts("Absolute skip a bad block\n"); |
| 342 | serial_put_hex(block); |
| 343 | return 1; |
| 344 | } |
| 345 | |
| 346 | pg = block * ppb + ppb - 1 ; |
| 347 | read_oob(oob_buf, oobsize, pg); |
| 348 | if ( oob_buf[0] != 0xff || oob_buf[1] != 0xff ) |
| 349 | { |
| 350 | serial_puts("Absolute skip a bad block\n"); |
| 351 | serial_put_hex(block); |
| 352 | return 1; |
| 353 | } |
| 354 | |
| 355 | } |
| 356 | else |
| 357 | { |
| 358 | pg = block * ppb + bad_block_page; |
| 359 | read_oob(oob_buf, oobsize, pg); |
| 360 | if (oob_buf[bad_block_pos] != 0xff) |
| 361 | { |
| 362 | serial_put_hex(oob_buf[bad_block_pos]); |
| 363 | serial_puts("Skip a bad block at"); |
| 364 | serial_put_hex(block); |
| 365 | return 1; |
| 366 | } |
| 367 | |
| 368 | } |
| 369 | return 0; |
| 370 | } |
| 371 | |
| 372 | u32 nand_erase_4760(int blk_num, int sblk, int force) |
| 373 | { |
| 374 | int i, j; |
| 375 | u32 cur, rowaddr; |
| 376 | |
| 377 | __nand_enable(); |
| 378 | |
| 379 | if (wp_pin) |
| 380 | __gpio_set_pin(wp_pin); |
| 381 | cur = sblk * ppb; |
| 382 | for (i = 0; i < blk_num; i++) { |
| 383 | rowaddr = cur; |
| 384 | |
| 385 | if (!force) /* if set, erase anything */ |
| 386 | if (nand_check_block(cur/ppb)) |
| 387 | { |
| 388 | cur += ppb; |
| 389 | blk_num += Hand.nand_plane; |
| 390 | continue; |
| 391 | } |
| 392 | |
| 393 | __nand_cmd(CMD_ERASE_SETUP); |
| 394 | |
| 395 | for (j = 0; j < row; j++) { |
| 396 | __nand_addr(rowaddr & 0xff); |
| 397 | rowaddr >>= 8; |
| 398 | } |
| 399 | __nand_cmd(CMD_ERASE); |
| 400 | __nand_sync(); |
| 401 | __nand_cmd(CMD_READ_STATUS); |
| 402 | |
| 403 | if (__nand_data8() & 0x01) |
| 404 | { |
| 405 | serial_puts("Erase fail at "); |
| 406 | serial_put_hex(cur / ppb); |
| 407 | nand_mark_bad_4760(cur / ppb); |
| 408 | cur += ppb; |
| 409 | blk_num += Hand.nand_plane; |
| 410 | continue; |
| 411 | } |
| 412 | cur += ppb; |
| 413 | } |
| 414 | |
| 415 | if (wp_pin) |
| 416 | __gpio_clear_pin(wp_pin); |
| 417 | |
| 418 | __nand_disable(); |
| 419 | return cur; |
| 420 | } |
| 421 | |
| 422 | /* |
| 423 | * Read oob |
| 424 | */ |
| 425 | static int read_oob(void *buf, unsigned int size, unsigned int pg) |
| 426 | { |
| 427 | unsigned int i, coladdr, rowaddr; |
| 428 | |
| 429 | __nand_enable(); |
| 430 | |
| 431 | if (pagesize == 512) |
| 432 | coladdr = 0; |
| 433 | else { |
| 434 | if (bus == 8) |
| 435 | coladdr = pagesize; |
| 436 | else |
| 437 | coladdr = pagesize / 2; |
| 438 | } |
| 439 | |
| 440 | if (pagesize == 512) |
| 441 | /* Send READOOB command */ |
| 442 | __nand_cmd(CMD_READC); |
| 443 | else |
| 444 | /* Send READ0 command */ |
| 445 | __nand_cmd(CMD_READA); |
| 446 | |
| 447 | /* Send column address */ |
| 448 | __nand_addr(coladdr & 0xff); |
| 449 | if (pagesize != 512) |
| 450 | __nand_addr(coladdr >> 8); |
| 451 | |
| 452 | /* Send page address */ |
| 453 | rowaddr = pg; |
| 454 | for (i = 0; i < row; i++) { |
| 455 | __nand_addr(rowaddr & 0xff); |
| 456 | rowaddr >>= 8; |
| 457 | } |
| 458 | |
| 459 | /* Send READSTART command for 2048 ps NAND */ |
| 460 | if (pagesize != 512) |
| 461 | __nand_cmd(CMD_CONFIRM); |
| 462 | |
| 463 | /* Wait for device ready */ |
| 464 | __nand_sync(); |
| 465 | |
| 466 | /* Read oob data */ |
| 467 | read_proc(buf, size); |
| 468 | |
| 469 | if (pagesize == 512) |
| 470 | __nand_sync(); |
| 471 | |
| 472 | __nand_disable(); |
| 473 | return 0; |
| 474 | } |
| 475 | |
| 476 | /* |
| 477 | * Read data <pagenum> pages from <startpage> page. |
| 478 | * Don't skip bad block. |
| 479 | * Don't use HW ECC. |
| 480 | */ |
| 481 | u32 nand_read_raw_4760(void *buf, u32 startpage, u32 pagenum, int option) |
| 482 | { |
| 483 | u32 cnt, j; |
| 484 | u32 cur_page, rowaddr; |
| 485 | u8 *tmpbuf; |
| 486 | |
| 487 | tmpbuf = (u8 *)buf; |
| 488 | |
| 489 | cur_page = startpage; |
| 490 | cnt = 0; |
| 491 | while (cnt < pagenum) { |
| 492 | if ((cur_page % ppb) == 0) { |
| 493 | if (nand_check_block(cur_page / ppb)) { |
| 494 | cur_page += ppb; // Bad block, set to next block |
| 495 | continue; |
| 496 | } |
| 497 | } |
| 498 | |
| 499 | __nand_cmd(CMD_READA); |
| 500 | __nand_addr(0); |
| 501 | if (pagesize != 512) |
| 502 | __nand_addr(0); |
| 503 | |
| 504 | rowaddr = cur_page; |
| 505 | for (j = 0; j < row; j++) { |
| 506 | __nand_addr(rowaddr & 0xff); |
| 507 | rowaddr >>= 8; |
| 508 | } |
| 509 | |
| 510 | if (pagesize != 512) |
| 511 | __nand_cmd(CMD_CONFIRM); |
| 512 | |
| 513 | __nand_sync(); |
| 514 | #ifdef USE_PN |
| 515 | pn_enable(); |
| 516 | #endif |
| 517 | |
| 518 | read_proc(tmpbuf, pagesize); |
| 519 | |
| 520 | tmpbuf += pagesize; |
| 521 | if (option != NO_OOB) |
| 522 | { |
| 523 | read_oob(tmpbuf, oobsize, cur_page); |
| 524 | tmpbuf += oobsize; |
| 525 | } |
| 526 | #ifdef USE_PN |
| 527 | pn_disable(); |
| 528 | #endif |
| 529 | cur_page++; |
| 530 | cnt++; |
| 531 | } |
| 532 | |
| 533 | return cur_page; |
| 534 | } |
| 535 | |
| 536 | #ifndef CFG_NAND_BADBLOCK_PAGE |
| 537 | #define CFG_NAND_BADBLOCK_PAGE 0 /* NAND bad block was marked at this page in a block, starting from 0 */ |
| 538 | #endif |
| 539 | |
| 540 | /* |
| 541 | * Read data <pagenum> pages from <startpage> page. |
| 542 | * Skip bad block if detected. |
| 543 | * HW ECC is used. |
| 544 | */ |
| 545 | u32 nand_read_4760(void *buf, u32 startpage, u32 pagenum, int option) |
| 546 | { |
| 547 | u32 j, k; |
| 548 | u32 cur_page, cur_blk, cnt, rowaddr, ecccnt; |
| 549 | u8 *tmpbuf, *p, flag = 0; |
| 550 | u32 oob_per_eccsize; |
| 551 | u32 spl_size = 8 * 1024 / pagesize; |
| 552 | ecccnt = pagesize / ECC_BLOCK; |
| 553 | oob_per_eccsize = eccpos / ecccnt; |
| 554 | |
| 555 | cur_page = startpage; |
| 556 | cnt = 0; |
| 557 | |
| 558 | if(startpage >= 0 && startpage < spl_size * 2) |
| 559 | tmpbuf = buf + 8 * 1024; |
| 560 | else |
| 561 | tmpbuf = buf; |
| 562 | |
| 563 | __nand_enable(); |
| 564 | while (cnt < pagenum) { |
| 565 | if (cur_page < spl_size * 2) { |
| 566 | u32 m; |
| 567 | for (m=0; (m < pagenum) && (m < spl_size); m++) |
| 568 | read_nand_spl_page(buf + pagesize * m, m * 2); |
| 569 | |
| 570 | cur_page = ppb * 2; |
| 571 | cnt = spl_size; |
| 572 | continue; |
| 573 | } |
| 574 | |
| 575 | /* If this is the first page of the block, check for bad. */ |
| 576 | if ((cur_page % ppb) == 0) { |
| 577 | cur_blk = cur_page / ppb; |
| 578 | if (nand_check_block(cur_blk)) { |
| 579 | cur_page += ppb; // Bad block, set to next block |
| 580 | continue; |
| 581 | } |
| 582 | } |
| 583 | __nand_cmd(CMD_READA); |
| 584 | |
| 585 | __nand_addr(0); |
| 586 | if (pagesize != 512) |
| 587 | __nand_addr(0); |
| 588 | |
| 589 | rowaddr = cur_page; |
| 590 | for (j = 0; j < row; j++) { |
| 591 | __nand_addr(rowaddr & 0xff); |
| 592 | rowaddr >>= 8; |
| 593 | } |
| 594 | |
| 595 | if (pagesize != 512) |
| 596 | __nand_cmd(CMD_CONFIRM); |
| 597 | |
| 598 | __nand_sync(); |
| 599 | |
| 600 | #ifdef USE_PN |
| 601 | // pn_enable(); |
| 602 | #endif |
| 603 | /* Read data */ |
| 604 | read_proc((char *)tmpbuf, pagesize); |
| 605 | |
| 606 | /* read oob first */ |
| 607 | read_proc((char *)oob_buf, oobsize); |
| 608 | #ifdef USE_PN |
| 609 | // pn_disable(); |
| 610 | #endif |
| 611 | |
| 612 | for (j = 0; j < ecccnt; j++) { |
| 613 | u32 stat; |
| 614 | flag = 0; |
| 615 | REG_BCH_INTS = 0xffffffff; |
| 616 | |
| 617 | if (cur_page >= 16384 / pagesize) |
| 618 | { |
| 619 | if(bchbit == 4) |
| 620 | __ecc_decoding_4bit(); |
| 621 | else if(bchbit == 8) |
| 622 | __ecc_decoding_8bit(); |
| 623 | else if(bchbit == 12) |
| 624 | __ecc_decoding_12bit(); |
| 625 | else if(bchbit == 16) |
| 626 | __ecc_decoding_16bit(); |
| 627 | else if(bchbit == 20) |
| 628 | __ecc_decoding_20bit(); |
| 629 | else |
| 630 | __ecc_decoding_24bit(); |
| 631 | } |
| 632 | else |
| 633 | { |
| 634 | __ecc_decoding_24bit(); |
| 635 | } |
| 636 | |
| 637 | if (option != NO_OOB) |
| 638 | __ecc_cnt_dec(ECC_BLOCK*2 + oob_per_eccsize*2 + par_size); |
| 639 | else |
| 640 | __ecc_cnt_dec(ECC_BLOCK*2 + par_size); |
| 641 | |
| 642 | for (k = 0; k < ECC_BLOCK; k++) { |
| 643 | REG_BCH_DR = tmpbuf[k]; |
| 644 | } |
| 645 | |
| 646 | if (option != NO_OOB) { |
| 647 | for (k = 0; k < oob_per_eccsize; k++) { |
| 648 | REG_BCH_DR = oob_buf[oob_per_eccsize * j + k]; |
| 649 | } |
| 650 | } |
| 651 | |
| 652 | for (k = 0; k < par_size1; k++) { |
| 653 | REG_BCH_DR = oob_buf[eccpos + j * par_size1 + k]; |
| 654 | if (oob_buf[eccpos + j * par_size1 + k] != 0xff) //why? |
| 655 | flag = 1; |
| 656 | } |
| 657 | |
| 658 | /* Wait for completion */ |
| 659 | __ecc_decode_sync(); |
| 660 | __ecc_disable(); |
| 661 | /* Check decoding */ |
| 662 | stat = REG_BCH_INTS; |
| 663 | |
| 664 | if (stat & BCH_INTS_ERR) { |
| 665 | if (stat & BCH_INTS_UNCOR) { |
| 666 | if (flag) |
| 667 | { |
| 668 | dprintf("Uncorrectable ECC error occurred\n"); |
| 669 | handshake_PKT[3] = 1; |
| 670 | } |
| 671 | } |
| 672 | else { |
| 673 | handshake_PKT[3] = 0; |
| 674 | unsigned int errcnt = (stat & BCH_INTS_ERRC_MASK) >> BCH_INTS_ERRC_BIT; |
| 675 | switch (errcnt) { |
| 676 | case 24: |
| 677 | dprintf("correct 24th error\n"); |
| 678 | bch_correct(tmpbuf, (REG_BCH_ERR11 & BCH_ERR_INDEX_ODD_MASK) >> BCH_ERR_INDEX_ODD_BIT); |
| 679 | case 23: |
| 680 | bch_correct(tmpbuf, (REG_BCH_ERR11 & BCH_ERR_INDEX_EVEN_MASK) >> BCH_ERR_INDEX_EVEN_BIT); |
| 681 | case 22: |
| 682 | bch_correct(tmpbuf, (REG_BCH_ERR10 & BCH_ERR_INDEX_ODD_MASK) >> BCH_ERR_INDEX_ODD_BIT); |
| 683 | case 21: |
| 684 | bch_correct(tmpbuf, (REG_BCH_ERR10 & BCH_ERR_INDEX_EVEN_MASK) >> BCH_ERR_INDEX_EVEN_BIT); |
| 685 | case 20: |
| 686 | bch_correct(tmpbuf, (REG_BCH_ERR9 & BCH_ERR_INDEX_ODD_MASK) >> BCH_ERR_INDEX_ODD_BIT); |
| 687 | case 19: |
| 688 | bch_correct(tmpbuf, (REG_BCH_ERR9 & BCH_ERR_INDEX_EVEN_MASK) >> BCH_ERR_INDEX_EVEN_BIT); |
| 689 | case 18: |
| 690 | bch_correct(tmpbuf, (REG_BCH_ERR8 & BCH_ERR_INDEX_ODD_MASK) >> BCH_ERR_INDEX_ODD_BIT); |
| 691 | case 17: |
| 692 | bch_correct(tmpbuf, (REG_BCH_ERR8 & BCH_ERR_INDEX_EVEN_MASK) >> BCH_ERR_INDEX_EVEN_BIT); |
| 693 | case 16: |
| 694 | bch_correct(tmpbuf, (REG_BCH_ERR7 & BCH_ERR_INDEX_ODD_MASK) >> BCH_ERR_INDEX_ODD_BIT); |
| 695 | case 15: |
| 696 | bch_correct(tmpbuf, (REG_BCH_ERR7 & BCH_ERR_INDEX_EVEN_MASK) >> BCH_ERR_INDEX_EVEN_BIT); |
| 697 | case 14: |
| 698 | bch_correct(tmpbuf, (REG_BCH_ERR6 & BCH_ERR_INDEX_ODD_MASK) >> BCH_ERR_INDEX_ODD_BIT); |
| 699 | case 13: |
| 700 | bch_correct(tmpbuf, (REG_BCH_ERR6 & BCH_ERR_INDEX_EVEN_MASK) >> BCH_ERR_INDEX_EVEN_BIT); |
| 701 | case 12: |
| 702 | bch_correct(tmpbuf, (REG_BCH_ERR5 & BCH_ERR_INDEX_ODD_MASK) >> BCH_ERR_INDEX_ODD_BIT); |
| 703 | case 11: |
| 704 | bch_correct(tmpbuf, (REG_BCH_ERR5 & BCH_ERR_INDEX_EVEN_MASK) >> BCH_ERR_INDEX_EVEN_BIT); |
| 705 | case 10: |
| 706 | bch_correct(tmpbuf, (REG_BCH_ERR4 & BCH_ERR_INDEX_ODD_MASK) >> BCH_ERR_INDEX_ODD_BIT); |
| 707 | case 9: |
| 708 | bch_correct(tmpbuf, (REG_BCH_ERR4 & BCH_ERR_INDEX_EVEN_MASK) >> BCH_ERR_INDEX_EVEN_BIT); |
| 709 | case 8: |
| 710 | dprintf("correct 8th error\n"); |
| 711 | bch_correct(tmpbuf, (REG_BCH_ERR3 & BCH_ERR_INDEX_ODD_MASK) >> BCH_ERR_INDEX_ODD_BIT); |
| 712 | case 7: |
| 713 | dprintf("correct 7th error\n"); |
| 714 | bch_correct(tmpbuf, (REG_BCH_ERR3 & BCH_ERR_INDEX_EVEN_MASK) >> BCH_ERR_INDEX_EVEN_BIT); |
| 715 | case 6: |
| 716 | dprintf("correct 6th error\n"); |
| 717 | bch_correct(tmpbuf, (REG_BCH_ERR2 & BCH_ERR_INDEX_ODD_MASK) >> BCH_ERR_INDEX_ODD_BIT); |
| 718 | case 5: |
| 719 | dprintf("correct 5th error\n"); |
| 720 | bch_correct(tmpbuf, (REG_BCH_ERR2 & BCH_ERR_INDEX_EVEN_MASK) >> BCH_ERR_INDEX_EVEN_BIT); |
| 721 | case 4: |
| 722 | dprintf("correct 4th error\n"); |
| 723 | bch_correct(tmpbuf, (REG_BCH_ERR1 & BCH_ERR_INDEX_ODD_MASK) >> BCH_ERR_INDEX_ODD_BIT); |
| 724 | case 3: |
| 725 | dprintf("correct 3th error\n"); |
| 726 | bch_correct(tmpbuf, (REG_BCH_ERR1 & BCH_ERR_INDEX_EVEN_MASK) >> BCH_ERR_INDEX_EVEN_BIT); |
| 727 | case 2: |
| 728 | dprintf("correct 2th error\n"); |
| 729 | bch_correct(tmpbuf, (REG_BCH_ERR0 & BCH_ERR_INDEX_ODD_MASK) >> BCH_ERR_INDEX_ODD_BIT); |
| 730 | case 1: |
| 731 | dprintf("correct 1th error\n"); |
| 732 | bch_correct(tmpbuf, (REG_BCH_ERR0 & BCH_ERR_INDEX_EVEN_MASK) >> BCH_ERR_INDEX_EVEN_BIT); |
| 733 | break; |
| 734 | default: |
| 735 | dprintf("no error\n"); |
| 736 | break; |
| 737 | } |
| 738 | } |
| 739 | } |
| 740 | /* increment pointer */ |
| 741 | tmpbuf += ECC_BLOCK; |
| 742 | } |
| 743 | |
| 744 | switch (option) |
| 745 | { |
| 746 | case OOB_ECC: |
| 747 | for (j = 0; j < oobsize; j++) |
| 748 | tmpbuf[j] = oob_buf[j]; |
| 749 | tmpbuf += oobsize; |
| 750 | break; |
| 751 | case OOB_NO_ECC: |
| 752 | for (j = 0; j < par_size1 * ecccnt; j++) |
| 753 | oob_buf[eccpos + j] = 0xff; |
| 754 | for (j = 0; j < oobsize; j++) |
| 755 | tmpbuf[j] = oob_buf[j]; |
| 756 | tmpbuf += oobsize; |
| 757 | break; |
| 758 | case NO_OOB: |
| 759 | break; |
| 760 | } |
| 761 | |
| 762 | cur_page++; |
| 763 | cnt++; |
| 764 | } |
| 765 | |
| 766 | __nand_disable(); |
| 767 | |
| 768 | return cur_page; |
| 769 | } |
| 770 | |
| 771 | int read_nand_spl_page(unsigned char *databuf, unsigned int pageaddr) |
| 772 | { |
| 773 | unsigned int i, j; |
| 774 | unsigned int rowaddr, ecccnt; |
| 775 | u8 *tmpbuf; |
| 776 | char eccbuf[1024]; |
| 777 | |
| 778 | for(i=0; i<1024; i++) |
| 779 | eccbuf[i] = 0xff; |
| 780 | |
| 781 | /* read oob first */ |
| 782 | __nand_enable(); |
| 783 | |
| 784 | ecccnt = pagesize / ECC_BLOCK0; |
| 785 | __nand_cmd(CMD_READA); |
| 786 | |
| 787 | __nand_addr(0); |
| 788 | if (pagesize != 512) |
| 789 | __nand_addr(0); |
| 790 | |
| 791 | rowaddr = pageaddr+1; //?? |
| 792 | |
| 793 | for (i = 0; i < row; i++) { |
| 794 | __nand_addr(rowaddr & 0xff); |
| 795 | rowaddr >>= 8; |
| 796 | } |
| 797 | |
| 798 | if (pagesize != 512) |
| 799 | __nand_cmd(CMD_CONFIRM); |
| 800 | |
| 801 | __nand_sync(); |
| 802 | |
| 803 | #ifdef USE_PN |
| 804 | pn_enable(); |
| 805 | #endif |
| 806 | /* Read ecc */ |
| 807 | read_proc(eccbuf, pagesize/ECC_BLOCK0*PAR_SIZE_SPL1); |
| 808 | |
| 809 | #ifdef USE_PN |
| 810 | pn_disable(); |
| 811 | #endif |
| 812 | |
| 813 | __nand_disable(); |
| 814 | |
| 815 | /* read data */ |
| 816 | __nand_enable(); |
| 817 | |
| 818 | ecccnt = pagesize / ECC_BLOCK0; |
| 819 | |
| 820 | __nand_cmd(CMD_READA); |
| 821 | |
| 822 | __nand_addr(0); |
| 823 | if (pagesize != 512) |
| 824 | __nand_addr(0); |
| 825 | |
| 826 | rowaddr = pageaddr; |
| 827 | |
| 828 | for (i = 0; i < row; i++) { |
| 829 | __nand_addr(rowaddr & 0xff); |
| 830 | rowaddr >>= 8; |
| 831 | } |
| 832 | |
| 833 | if (pagesize != 512) |
| 834 | __nand_cmd(CMD_CONFIRM); |
| 835 | |
| 836 | __nand_sync(); |
| 837 | |
| 838 | #ifdef USE_EFNAND |
| 839 | __nand_cmd(CMD_READ_STATUS); |
| 840 | |
| 841 | if (__nand_data8() & 0x01) { /* page program error */ |
| 842 | __nand_disable(); |
| 843 | |
| 844 | return 1; |
| 845 | } |
| 846 | __nand_cmd(CMD_READA); |
| 847 | #endif |
| 848 | |
| 849 | tmpbuf = (u8 *)databuf; |
| 850 | for(i=0; i<pagesize; i++) |
| 851 | tmpbuf[i] = 0xff; |
| 852 | |
| 853 | for (i = 0; i < ecccnt; i++) { |
| 854 | unsigned int stat; |
| 855 | |
| 856 | #ifdef USE_PN |
| 857 | if (!(((pageaddr % 64) == 0) && (i == 0))) |
| 858 | pn_enable(); |
| 859 | else |
| 860 | dprintf("don't use pn. pageaddr=%d ecccnt=%d\n", pageaddr,i); |
| 861 | #endif |
| 862 | /* Read data */ |
| 863 | read_proc((char *)tmpbuf, ECC_BLOCK0); |
| 864 | #ifdef USE_PN |
| 865 | pn_disable(); |
| 866 | #endif |
| 867 | |
| 868 | #ifdef USE_BCH |
| 869 | REG_BCH_INTS = 0xffffffff; |
| 870 | |
| 871 | __ecc_decoding_24bit(); |
| 872 | |
| 873 | __ecc_cnt_dec(2 * ECC_BLOCK0 + PAR_SIZE_SPL); |
| 874 | |
| 875 | for (j = 0; j < ECC_BLOCK0; j++) {//if(i==1)serial_put_hex(tmpbuf[j]); |
| 876 | REG_BCH_DR = tmpbuf[j]; |
| 877 | } |
| 878 | |
| 879 | /* assume parities be wrote to data register not parity register */ |
| 880 | for (j = 0; j < PAR_SIZE_SPL1; j++) { |
| 881 | REG_BCH_DR = eccbuf[i*PAR_SIZE_SPL1 + j]; |
| 882 | } |
| 883 | |
| 884 | /* Wait for completion */ |
| 885 | __ecc_decode_sync(); |
| 886 | |
| 887 | __ecc_disable(); |
| 888 | |
| 889 | /* Check decoding */ |
| 890 | stat = REG_BCH_INTS; |
| 891 | |
| 892 | if (stat & BCH_INTS_ERR) { |
| 893 | if (stat & BCH_INTS_UNCOR) { |
| 894 | serial_puts("ecc Uncorrectable ECC error occurred __spl__\n"); |
| 895 | serial_put_hex(i); |
| 896 | } |
| 897 | else { |
| 898 | unsigned int errcnt = (stat & BCH_INTS_ERRC_MASK) >> BCH_INTS_ERRC_BIT; |
| 899 | switch (errcnt) { |
| 900 | case 24: |
| 901 | dprintf("correct 24th error\n"); |
| 902 | bch_correct(tmpbuf, (REG_BCH_ERR11 & BCH_ERR_INDEX_ODD_MASK) >> BCH_ERR_INDEX_ODD_BIT); |
| 903 | case 23: |
| 904 | bch_correct(tmpbuf, (REG_BCH_ERR11 & BCH_ERR_INDEX_EVEN_MASK) >> BCH_ERR_INDEX_EVEN_BIT); |
| 905 | case 22: |
| 906 | bch_correct(tmpbuf, (REG_BCH_ERR10 & BCH_ERR_INDEX_ODD_MASK) >> BCH_ERR_INDEX_ODD_BIT); |
| 907 | case 21: |
| 908 | bch_correct(tmpbuf, (REG_BCH_ERR10 & BCH_ERR_INDEX_EVEN_MASK) >> BCH_ERR_INDEX_EVEN_BIT); |
| 909 | case 20: |
| 910 | bch_correct(tmpbuf, (REG_BCH_ERR9 & BCH_ERR_INDEX_ODD_MASK) >> BCH_ERR_INDEX_ODD_BIT); |
| 911 | case 19: |
| 912 | bch_correct(tmpbuf, (REG_BCH_ERR9 & BCH_ERR_INDEX_EVEN_MASK) >> BCH_ERR_INDEX_EVEN_BIT); |
| 913 | case 18: |
| 914 | bch_correct(tmpbuf, (REG_BCH_ERR8 & BCH_ERR_INDEX_ODD_MASK) >> BCH_ERR_INDEX_ODD_BIT); |
| 915 | case 17: |
| 916 | bch_correct(tmpbuf, (REG_BCH_ERR8 & BCH_ERR_INDEX_EVEN_MASK) >> BCH_ERR_INDEX_EVEN_BIT); |
| 917 | case 16: |
| 918 | bch_correct(tmpbuf, (REG_BCH_ERR7 & BCH_ERR_INDEX_ODD_MASK) >> BCH_ERR_INDEX_ODD_BIT); |
| 919 | case 15: |
| 920 | bch_correct(tmpbuf, (REG_BCH_ERR7 & BCH_ERR_INDEX_EVEN_MASK) >> BCH_ERR_INDEX_EVEN_BIT); |
| 921 | case 14: |
| 922 | bch_correct(tmpbuf, (REG_BCH_ERR6 & BCH_ERR_INDEX_ODD_MASK) >> BCH_ERR_INDEX_ODD_BIT); |
| 923 | case 13: |
| 924 | bch_correct(tmpbuf, (REG_BCH_ERR6 & BCH_ERR_INDEX_EVEN_MASK) >> BCH_ERR_INDEX_EVEN_BIT); |
| 925 | case 12: |
| 926 | bch_correct(tmpbuf, (REG_BCH_ERR5 & BCH_ERR_INDEX_ODD_MASK) >> BCH_ERR_INDEX_ODD_BIT); |
| 927 | case 11: |
| 928 | bch_correct(tmpbuf, (REG_BCH_ERR5 & BCH_ERR_INDEX_EVEN_MASK) >> BCH_ERR_INDEX_EVEN_BIT); |
| 929 | case 10: |
| 930 | bch_correct(tmpbuf, (REG_BCH_ERR4 & BCH_ERR_INDEX_ODD_MASK) >> BCH_ERR_INDEX_ODD_BIT); |
| 931 | case 9: |
| 932 | bch_correct(tmpbuf, (REG_BCH_ERR4 & BCH_ERR_INDEX_EVEN_MASK) >> BCH_ERR_INDEX_EVEN_BIT); |
| 933 | case 8: |
| 934 | dprintf("correct 8th error\n"); |
| 935 | bch_correct(tmpbuf, (REG_BCH_ERR3 & BCH_ERR_INDEX_ODD_MASK) >> BCH_ERR_INDEX_ODD_BIT); |
| 936 | case 7: |
| 937 | dprintf("correct 7th error\n"); |
| 938 | bch_correct(tmpbuf, (REG_BCH_ERR3 & BCH_ERR_INDEX_EVEN_MASK) >> BCH_ERR_INDEX_EVEN_BIT); |
| 939 | case 6: |
| 940 | dprintf("correct 6th error\n"); |
| 941 | bch_correct(tmpbuf, (REG_BCH_ERR2 & BCH_ERR_INDEX_ODD_MASK) >> BCH_ERR_INDEX_ODD_BIT); |
| 942 | case 5: |
| 943 | dprintf("correct 5th error\n"); |
| 944 | bch_correct(tmpbuf, (REG_BCH_ERR2 & BCH_ERR_INDEX_EVEN_MASK) >> BCH_ERR_INDEX_EVEN_BIT); |
| 945 | case 4: |
| 946 | dprintf("correct 4th error\n"); |
| 947 | bch_correct(tmpbuf, (REG_BCH_ERR1 & BCH_ERR_INDEX_ODD_MASK) >> BCH_ERR_INDEX_ODD_BIT); |
| 948 | case 3: |
| 949 | dprintf("correct 3th error\n"); |
| 950 | bch_correct(tmpbuf, (REG_BCH_ERR1 & BCH_ERR_INDEX_EVEN_MASK) >> BCH_ERR_INDEX_EVEN_BIT); |
| 951 | case 2: |
| 952 | dprintf("correct 2th error\n"); |
| 953 | bch_correct(tmpbuf, (REG_BCH_ERR0 & BCH_ERR_INDEX_ODD_MASK) >> BCH_ERR_INDEX_ODD_BIT); |
| 954 | case 1: |
| 955 | dprintf("correct 1th error\n"); |
| 956 | bch_correct(tmpbuf, (REG_BCH_ERR0 & BCH_ERR_INDEX_EVEN_MASK) >> BCH_ERR_INDEX_EVEN_BIT); |
| 957 | break; |
| 958 | default: |
| 959 | dprintf("no error\n"); |
| 960 | break; |
| 961 | } |
| 962 | } |
| 963 | } |
| 964 | #endif |
| 965 | /* increment pointer */ |
| 966 | tmpbuf += ECC_BLOCK0; |
| 967 | } |
| 968 | |
| 969 | __nand_disable(); |
| 970 | |
| 971 | return 0; |
| 972 | } |
| 973 | |
| 974 | u32 nand_program_4760(void *context, int spage, int pages, int option) |
| 975 | { |
| 976 | u32 i, j, cur_page, cur_blk, rowaddr; |
| 977 | u8 *tmpbuf; |
| 978 | u32 ecccnt; |
| 979 | u8 ecc_buf[1024], oob_buf[512]; |
| 980 | u32 oob_per_eccsize; |
| 981 | int spl_size = 8 * 1024 / pagesize; |
| 982 | |
| 983 | if (wp_pin) |
| 984 | __gpio_set_pin(wp_pin); |
| 985 | restart: |
| 986 | tmpbuf = (u8 *)context; |
| 987 | ecccnt = pagesize / ECC_BLOCK; |
| 988 | oob_per_eccsize = eccpos / ecccnt; |
| 989 | |
| 990 | i = 0; |
| 991 | cur_page = spage; |
| 992 | |
| 993 | while (i < pages) { |
| 994 | if (cur_page == 0) { |
| 995 | int k; |
| 996 | for(k = 0; k < spl_size; k++) { |
| 997 | program_nand_spl_page(context + pagesize * k, k * 2); |
| 998 | } |
| 999 | #if 0 |
| 1000 | for(k = 0; k < spl_size; k++) { |
| 1001 | program_nand_spl_page(context + pagesize * k, k * 2 + ppb ); |
| 1002 | } |
| 1003 | #endif |
| 1004 | tmpbuf += pagesize * spl_size; |
| 1005 | cur_page = 2 * ppb; |
| 1006 | i += spl_size; |
| 1007 | continue; |
| 1008 | } |
| 1009 | |
| 1010 | if ((cur_page % ppb) == 0) { /* First page of block, test BAD. */ |
| 1011 | if (nand_check_block(cur_page / ppb)) { |
| 1012 | cur_page += ppb; /* Bad block, set to next block */ |
| 1013 | continue; |
| 1014 | } |
| 1015 | } |
| 1016 | |
| 1017 | if ( option != NO_OOB ) //if NO_OOB do not perform vaild check! |
| 1018 | { |
| 1019 | for ( j = 0 ; j < pagesize + oobsize; j++) |
| 1020 | { |
| 1021 | if (tmpbuf[j] != 0xff) |
| 1022 | break; |
| 1023 | } |
| 1024 | if ( j == oobsize + pagesize ) |
| 1025 | { |
| 1026 | tmpbuf += (pagesize + oobsize) ; |
| 1027 | i ++; |
| 1028 | cur_page ++; |
| 1029 | continue; |
| 1030 | } |
| 1031 | } |
| 1032 | |
| 1033 | __nand_enable(); |
| 1034 | __nand_sync(); |
| 1035 | |
| 1036 | if (pagesize == 512) |
| 1037 | __nand_cmd(CMD_READA); |
| 1038 | |
| 1039 | __nand_cmd(CMD_SEQIN); |
| 1040 | __nand_addr(0); |
| 1041 | |
| 1042 | if (pagesize != 512) |
| 1043 | __nand_addr(0); |
| 1044 | |
| 1045 | rowaddr = cur_page; |
| 1046 | for (j = 0; j < row; j++) { |
| 1047 | __nand_addr(rowaddr & 0xff); |
| 1048 | rowaddr >>= 8; |
| 1049 | } |
| 1050 | |
| 1051 | /* write out data */ |
| 1052 | for (j = 0; j < ecccnt; j++) { |
| 1053 | volatile u8 *paraddr; |
| 1054 | int k; |
| 1055 | |
| 1056 | paraddr = (volatile u8 *)BCH_PAR0; |
| 1057 | |
| 1058 | REG_BCH_INTS = 0xffffffff; |
| 1059 | if(bchbit == 4) |
| 1060 | __ecc_encoding_4bit(); |
| 1061 | else if(bchbit == 8) |
| 1062 | __ecc_encoding_8bit(); |
| 1063 | else if(bchbit == 12) |
| 1064 | __ecc_encoding_12bit(); |
| 1065 | else if(bchbit == 16) |
| 1066 | __ecc_encoding_16bit(); |
| 1067 | else if(bchbit == 20) |
| 1068 | __ecc_encoding_20bit(); |
| 1069 | else |
| 1070 | __ecc_encoding_24bit(); |
| 1071 | |
| 1072 | /* Set BCHCNT.DEC_COUNT to data block size in bytes */ |
| 1073 | if (option != NO_OOB) |
| 1074 | __ecc_cnt_enc((ECC_BLOCK + oob_per_eccsize) * 2); |
| 1075 | else |
| 1076 | __ecc_cnt_enc(ECC_BLOCK * 2); |
| 1077 | |
| 1078 | /* Write data in data area to BCH */ |
| 1079 | for (k = 0; k < ECC_BLOCK; k++) { |
| 1080 | REG_BCH_DR = tmpbuf[ECC_BLOCK * j + k]; |
| 1081 | } |
| 1082 | |
| 1083 | /* Write file system information in oob area to BCH */ |
| 1084 | if (option != NO_OOB) |
| 1085 | { |
| 1086 | if(j == 0){ |
| 1087 | REG_BCH_DR = 0xff; |
| 1088 | REG_BCH_DR = 0xff; |
| 1089 | for(k = 2; k < oob_per_eccsize; k++) |
| 1090 | REG_BCH_DR = tmpbuf[pagesize + k]; |
| 1091 | } else { |
| 1092 | for (k = 0; k < oob_per_eccsize; k++) { |
| 1093 | REG_BCH_DR = tmpbuf[pagesize + oob_per_eccsize * j + k]; |
| 1094 | } |
| 1095 | } |
| 1096 | } |
| 1097 | |
| 1098 | __ecc_encode_sync(); |
| 1099 | __ecc_disable(); |
| 1100 | |
| 1101 | /* Read PAR values */ |
| 1102 | for (k = 0; k < par_size1; k++) { |
| 1103 | ecc_buf[j * par_size1 + k] = *paraddr++; |
| 1104 | } |
| 1105 | #ifdef USE_PN |
| 1106 | // pn_enable(); |
| 1107 | #endif |
| 1108 | write_proc((char *)&tmpbuf[ECC_BLOCK * j], ECC_BLOCK); |
| 1109 | #ifdef USE_PN |
| 1110 | // pn_disable(); |
| 1111 | #endif |
| 1112 | } |
| 1113 | |
| 1114 | for(j=0; j<oobsize; j++) |
| 1115 | oob_buf[j] = 0xff; |
| 1116 | switch (option) |
| 1117 | { |
| 1118 | case OOB_ECC: |
| 1119 | case OOB_NO_ECC: |
| 1120 | for (j = 2; j < eccpos; j++) { |
| 1121 | oob_buf[j] = tmpbuf[pagesize + j]; |
| 1122 | } |
| 1123 | for (j = 0; j < ecccnt * par_size1; j++) { |
| 1124 | oob_buf[eccpos + j] = ecc_buf[j]; |
| 1125 | } |
| 1126 | tmpbuf += pagesize + oobsize; |
| 1127 | break; |
| 1128 | case NO_OOB: //bin image |
| 1129 | for (j = 0; j < ecccnt * par_size1; j++) { |
| 1130 | oob_buf[eccpos + j] = ecc_buf[j]; |
| 1131 | } |
| 1132 | tmpbuf += pagesize; |
| 1133 | break; |
| 1134 | } |
| 1135 | |
| 1136 | #ifdef USE_PN |
| 1137 | // pn_enable(); |
| 1138 | #endif |
| 1139 | /* write out oob buffer */ |
| 1140 | write_proc((u8 *)oob_buf, oobsize); |
| 1141 | |
| 1142 | #ifdef USE_PN |
| 1143 | #ifndef USE_STATUS_PORT |
| 1144 | // pn_disable(); |
| 1145 | #endif |
| 1146 | #endif |
| 1147 | /* send program confirm command */ |
| 1148 | __nand_cmd(CMD_PGPROG); |
| 1149 | __nand_sync(); |
| 1150 | |
| 1151 | __nand_cmd(CMD_READ_STATUS); |
| 1152 | __nand_sync(); |
| 1153 | |
| 1154 | if (__nand_data8() & 0x01) /* page program error */ |
| 1155 | { |
| 1156 | serial_puts("Skip a write fail block\n"); |
| 1157 | nand_erase_4760( 1, cur_page/ppb, 1); //force erase before |
| 1158 | nand_mark_bad_4760(cur_page/ppb); |
| 1159 | spage += ppb; |
| 1160 | goto restart; |
| 1161 | } |
| 1162 | __nand_disable(); |
| 1163 | |
| 1164 | i++; |
| 1165 | cur_page++; |
| 1166 | } |
| 1167 | |
| 1168 | if (wp_pin) |
| 1169 | __gpio_clear_pin(wp_pin); |
| 1170 | |
| 1171 | return cur_page; |
| 1172 | } |
| 1173 | |
| 1174 | int program_nand_spl_page(unsigned char *databuf, unsigned int pageaddr) |
| 1175 | { |
| 1176 | int i, j, ecccnt; |
| 1177 | char *tmpbuf; |
| 1178 | char ecc_buf[1024]; // need 39*16 bytes at least for 24bit BCH |
| 1179 | unsigned int rowaddr; |
| 1180 | |
| 1181 | for(i=0; i<1024; i++) |
| 1182 | ecc_buf[i] = 0xff; |
| 1183 | |
| 1184 | __nand_enable(); |
| 1185 | |
| 1186 | tmpbuf = (char *)databuf; |
| 1187 | |
| 1188 | ecccnt = pagesize / ECC_BLOCK0; |
| 1189 | |
| 1190 | if (pagesize == 512) |
| 1191 | __nand_cmd(CMD_READA); |
| 1192 | |
| 1193 | __nand_cmd(CMD_SEQIN); |
| 1194 | |
| 1195 | /* write out col addr */ |
| 1196 | __nand_addr(0); |
| 1197 | if (pagesize != 512) |
| 1198 | __nand_addr(0); |
| 1199 | |
| 1200 | rowaddr = pageaddr; |
| 1201 | /* write out row addr */ |
| 1202 | for (i = 0; i < row; i++) { |
| 1203 | __nand_addr(rowaddr & 0xff); |
| 1204 | rowaddr >>= 8; |
| 1205 | } |
| 1206 | |
| 1207 | /* write out data */ |
| 1208 | |
| 1209 | for (i = 0; i < ecccnt; i++) { |
| 1210 | #ifdef USE_BCH |
| 1211 | volatile char *paraddr = (volatile char *)BCH_PAR0; |
| 1212 | |
| 1213 | REG_BCH_INTS = 0xffffffff; |
| 1214 | |
| 1215 | __ecc_encoding_24bit(); |
| 1216 | |
| 1217 | /* Set BCHCNT.DEC_COUNT to data block size in bytes */ |
| 1218 | __ecc_cnt_enc(2 * ECC_BLOCK0); |
| 1219 | |
| 1220 | for (j = 0; j < ECC_BLOCK0; j++) { |
| 1221 | REG_BCH_DR = tmpbuf[j]; |
| 1222 | } |
| 1223 | |
| 1224 | __ecc_encode_sync(); |
| 1225 | __ecc_disable(); |
| 1226 | |
| 1227 | /* Read PAR values for 256 bytes from BCH_PARn to ecc_buf */ |
| 1228 | for (j=0;j<PAR_SIZE_SPL1;j++) { |
| 1229 | ecc_buf[j + PAR_SIZE_SPL1 * i] = *paraddr++; |
| 1230 | } |
| 1231 | #endif |
| 1232 | #ifdef MAKE_ERROR |
| 1233 | char tmpbuf0[ECC_BLOCK0]; |
| 1234 | u8 k, n_err; |
| 1235 | u16 err_bit; |
| 1236 | |
| 1237 | memcpy(tmpbuf0, tmpbuf, ECC_BLOCK0); |
| 1238 | n_err = 1 + random() % 24; // 1 ~ 24 |
| 1239 | dprintf("generate %d error bits.\n",n_err); |
| 1240 | /* generate n_err error bits */ |
| 1241 | for(k = 0; k < n_err; k++) { |
| 1242 | err_bit = random() % (256*8); |
| 1243 | dprintf("err_bit=%04x in databuf[%03d]=0x%x \n",err_bit,err_bit / 8,tmpbuf0[(err_bit / 8)]); |
| 1244 | tmpbuf0[(err_bit / 8)] ^= 1 << (err_bit % 8); |
| 1245 | dprintf(" error databuf[%03d]= 0x%x \n",err_bit / 8,databuf[(err_bit / 8)]); |
| 1246 | } |
| 1247 | #endif |
| 1248 | |
| 1249 | #ifdef USE_PN |
| 1250 | if (!(((pageaddr % 64) == 0) && (i == 0))) |
| 1251 | pn_enable(); |
| 1252 | else |
| 1253 | dprintf("don't use pn. pageaddr=%d ecccnt=%d\n", pageaddr,i); |
| 1254 | #endif |
| 1255 | |
| 1256 | /* write ECC_BLOCK0 bytes to nand */ |
| 1257 | #ifdef MAKE_ERROR |
| 1258 | write_proc((char *)tmpbuf0, ECC_BLOCK0); |
| 1259 | #else |
| 1260 | write_proc((char *)tmpbuf, ECC_BLOCK0); |
| 1261 | #endif |
| 1262 | |
| 1263 | #ifdef USE_PN |
| 1264 | #ifndef USE_STATUS_PORT |
| 1265 | pn_disable(); |
| 1266 | #endif |
| 1267 | #endif |
| 1268 | tmpbuf += ECC_BLOCK0; |
| 1269 | } |
| 1270 | |
| 1271 | /* send program confirm command */ |
| 1272 | __nand_cmd(CMD_PGPROG); |
| 1273 | dprintf("%s %d \n", __FUNCTION__, __LINE__); |
| 1274 | __nand_sync(); |
| 1275 | dprintf("%s %d \n", __FUNCTION__, __LINE__); |
| 1276 | |
| 1277 | #if 1 |
| 1278 | __nand_cmd(CMD_READ_STATUS); |
| 1279 | dprintf("%s %d \n", __FUNCTION__, __LINE__); |
| 1280 | u8 status; |
| 1281 | #ifdef USE_STATUS_PORT |
| 1282 | status = __nand_status(); |
| 1283 | #else |
| 1284 | status = __nand_data8(); |
| 1285 | #endif |
| 1286 | if (status & 0x01) { |
| 1287 | __nand_disable(); |
| 1288 | return 1; |
| 1289 | } |
| 1290 | else { |
| 1291 | __nand_disable(); |
| 1292 | } |
| 1293 | dprintf("%s %d \n", __FUNCTION__, __LINE__); |
| 1294 | /* -----program ecc----- */ |
| 1295 | __nand_enable(); |
| 1296 | #endif |
| 1297 | if (pagesize == 512) |
| 1298 | __nand_cmd(CMD_READA); |
| 1299 | |
| 1300 | __nand_cmd(CMD_SEQIN); |
| 1301 | |
| 1302 | /* write out col addr */ |
| 1303 | __nand_addr(0); |
| 1304 | if (pagesize != 512) |
| 1305 | __nand_addr(0); |
| 1306 | |
| 1307 | rowaddr = pageaddr + 1; |
| 1308 | /* write out row addr */ |
| 1309 | for (i = 0; i < row; i++) { |
| 1310 | __nand_addr(rowaddr & 0xff); |
| 1311 | rowaddr >>= 8; |
| 1312 | } |
| 1313 | |
| 1314 | #ifdef USE_PN |
| 1315 | #ifdef PN_ADD_DELAY |
| 1316 | udelay(1000); |
| 1317 | dprintf("delay should be add for pn.\n"); |
| 1318 | #endif |
| 1319 | #endif |
| 1320 | |
| 1321 | #ifdef USE_PN |
| 1322 | pn_enable(); |
| 1323 | #endif |
| 1324 | dprintf("%s %d \n", __FUNCTION__, __LINE__); |
| 1325 | write_proc(ecc_buf, pagesize/ECC_BLOCK0*PAR_SIZE_SPL1); |
| 1326 | |
| 1327 | #ifdef USE_PN |
| 1328 | pn_disable(); |
| 1329 | #endif |
| 1330 | |
| 1331 | /* send program confirm command */ |
| 1332 | __nand_cmd(CMD_PGPROG); |
| 1333 | dprintf("%s %d \n", __FUNCTION__, __LINE__); |
| 1334 | __nand_sync(); |
| 1335 | dprintf("%s %d \n", __FUNCTION__, __LINE__); |
| 1336 | __nand_cmd(CMD_READ_STATUS); |
| 1337 | |
| 1338 | if (__nand_data8() & 0x01) { /* page program error */ |
| 1339 | __nand_disable(); |
| 1340 | return 1; |
| 1341 | } |
| 1342 | else { |
| 1343 | __nand_disable(); |
| 1344 | return 0; |
| 1345 | } |
| 1346 | } |
| 1347 | |
| 1348 | // be careful |
| 1349 | static u32 nand_mark_bad_page(u32 page) |
| 1350 | { |
| 1351 | #if 1 |
| 1352 | u8 badbuf[4096 + 128]; |
| 1353 | u32 i; |
| 1354 | |
| 1355 | if (wp_pin) |
| 1356 | __gpio_set_pin(wp_pin); |
| 1357 | for (i = 0; i < pagesize + oobsize; i++) |
| 1358 | badbuf[i] = 0x00; |
| 1359 | //all set to 0x00 |
| 1360 | |
| 1361 | __nand_cmd(CMD_READA); |
| 1362 | __nand_cmd(CMD_SEQIN); |
| 1363 | |
| 1364 | __nand_addr(0); |
| 1365 | if (pagesize != 512) |
| 1366 | __nand_addr(0); |
| 1367 | for (i = 0; i < row; i++) { |
| 1368 | __nand_addr(page & 0xff); |
| 1369 | page >>= 8; |
| 1370 | } |
| 1371 | |
| 1372 | write_proc((char *)badbuf, pagesize + oobsize); |
| 1373 | __nand_cmd(CMD_PGPROG); |
| 1374 | __nand_sync(); |
| 1375 | |
| 1376 | if (wp_pin) |
| 1377 | __gpio_clear_pin(wp_pin); |
| 1378 | return page; |
| 1379 | #endif |
| 1380 | } |
| 1381 | |
| 1382 | u32 nand_mark_bad_4760(int block) |
| 1383 | { |
| 1384 | u32 rowaddr; |
| 1385 | |
| 1386 | if ( bad_block_page >= ppb ) //absolute bad block mark! |
| 1387 | { //mark four page! |
| 1388 | rowaddr = block * ppb + 0; |
| 1389 | nand_mark_bad_page(rowaddr); |
| 1390 | |
| 1391 | rowaddr = block * ppb + 1; |
| 1392 | nand_mark_bad_page(rowaddr); |
| 1393 | |
| 1394 | rowaddr = block * ppb + ppb - 2; |
| 1395 | nand_mark_bad_page(rowaddr); |
| 1396 | |
| 1397 | rowaddr = block * ppb + ppb - 1; |
| 1398 | nand_mark_bad_page(rowaddr); |
| 1399 | } |
| 1400 | else //mark one page only |
| 1401 | { |
| 1402 | rowaddr = block * ppb + bad_block_page; |
| 1403 | nand_mark_bad_page(rowaddr); |
| 1404 | } |
| 1405 | |
| 1406 | return rowaddr; |
| 1407 | } |
| 1408 | |
| 1409 | static int nand_data_write8(char *buf, int count) |
| 1410 | { |
| 1411 | int i; |
| 1412 | u8 *p = (u8 *)buf; |
| 1413 | for (i=0;i<count;i++) |
| 1414 | __nand_data8() = *p++; |
| 1415 | return 0; |
| 1416 | } |
| 1417 | |
| 1418 | static int nand_data_write16(char *buf, int count) |
| 1419 | { |
| 1420 | int i; |
| 1421 | u16 *p = (u16 *)buf; |
| 1422 | for (i=0;i<count/2;i++) |
| 1423 | __nand_data16() = *p++; |
| 1424 | return 0; |
| 1425 | } |
| 1426 | |
| 1427 | static int nand_data_read8(char *buf, int count) |
| 1428 | { |
| 1429 | int i; |
| 1430 | u8 *p = (u8 *)buf; |
| 1431 | for (i=0;i<count;i++) |
| 1432 | *p++ = __nand_data8(); |
| 1433 | return 0; |
| 1434 | } |
| 1435 | |
| 1436 | static int nand_data_read16(char *buf, int count) |
| 1437 | { |
| 1438 | int i; |
| 1439 | u16 *p = (u16 *)buf; |
| 1440 | for (i=0;i<count/2;i++) |
| 1441 | *p++ = __nand_data16(); |
| 1442 | return 0; |
| 1443 | } |