blob: 40b080c59c1277e327e5f0378229c7c4707157b4 [file] [log] [blame]
Dima Zavin03cf4312009-01-23 16:38:30 -08001/*
2 * Copyright (c) 2008, Google Inc.
3 * All rights reserved.
Shashank Mittal8e49dec2010-03-01 15:19:04 -08004 * Copyright (c) 2009-2010, Code Aurora Forum. All rights reserved.
Dima Zavin03cf4312009-01-23 16:38:30 -08005 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in
Shashank Mittalc20b5a12009-11-18 19:35:30 -080013 * the documentation and/or other materials provided with the
Dima Zavin03cf4312009-01-23 16:38:30 -080014 * distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
19 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
20 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
22 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
Shashank Mittalc20b5a12009-11-18 19:35:30 -080023 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
Dima Zavin03cf4312009-01-23 16:38:30 -080024 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
26 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30#include <debug.h>
31#include <reg.h>
32#include <stdlib.h>
33#include <string.h>
34#include <dev/flash.h>
35#include <lib/ptable.h>
Ajay Dudani168f6cb2009-12-07 19:04:02 -080036#include <nand.h>
Dima Zavin03cf4312009-01-23 16:38:30 -080037
38#include "dmov.h"
Dima Zavin03cf4312009-01-23 16:38:30 -080039
40#define VERBOSE 0
Dima Zavin5582c7d2009-03-03 15:17:59 -080041#define VERIFY_WRITE 0
42
43static void *flash_spare;
44static void *flash_data;
Dima Zavin03cf4312009-01-23 16:38:30 -080045
46typedef struct dmov_ch dmov_ch;
Shashank Mittalc20b5a12009-11-18 19:35:30 -080047struct dmov_ch
Dima Zavin03cf4312009-01-23 16:38:30 -080048{
49 volatile unsigned cmd;
50 volatile unsigned result;
51 volatile unsigned status;
52 volatile unsigned config;
53};
54
55static void dmov_prep_ch(dmov_ch *ch, unsigned id)
56{
57 ch->cmd = DMOV_CMD_PTR(id);
58 ch->result = DMOV_RSLT(id);
59 ch->status = DMOV_STATUS(id);
60 ch->config = DMOV_CONFIG(id);
61}
62
63#define SRC_CRCI_NAND_CMD CMD_SRC_CRCI(DMOV_NAND_CRCI_CMD)
64#define DST_CRCI_NAND_CMD CMD_DST_CRCI(DMOV_NAND_CRCI_CMD)
65#define SRC_CRCI_NAND_DATA CMD_SRC_CRCI(DMOV_NAND_CRCI_DATA)
66#define DST_CRCI_NAND_DATA CMD_DST_CRCI(DMOV_NAND_CRCI_DATA)
67
Shashank Mittalad3d05c2009-11-19 15:53:57 -080068#define NAND_CFG0_RAW 0xA80420C0
69#define NAND_CFG1_RAW 0x5045D
70
Dima Zavin03cf4312009-01-23 16:38:30 -080071static unsigned CFG0, CFG1;
Shashank Mittal8e49dec2010-03-01 15:19:04 -080072static unsigned CFG0_M, CFG1_M;
73static unsigned CFG0_A, CFG1_A;
Dima Zavin03cf4312009-01-23 16:38:30 -080074
75#define CFG1_WIDE_FLASH (1U << 1)
76
77#define paddr(n) ((unsigned) (n))
78
79static int dmov_exec_cmdptr(unsigned id, unsigned *ptr)
80{
81 dmov_ch ch;
82 unsigned n;
83
84 dmov_prep_ch(&ch, id);
85
86 writel(DMOV_CMD_PTR_LIST | DMOV_CMD_ADDR(paddr(ptr)), ch.cmd);
87
88 while(!(readl(ch.status) & DMOV_STATUS_RSLT_VALID)) ;
89
90 n = readl(ch.status);
91 while(DMOV_STATUS_RSLT_COUNT(n)) {
92 n = readl(ch.result);
93 if(n != 0x80000002) {
94 dprintf(CRITICAL, "ERROR: result: %x\n", n);
95 dprintf(CRITICAL, "ERROR: flush: %x %x %x %x\n",
96 readl(DMOV_FLUSH0(DMOV_NAND_CHAN)),
97 readl(DMOV_FLUSH1(DMOV_NAND_CHAN)),
98 readl(DMOV_FLUSH2(DMOV_NAND_CHAN)),
99 readl(DMOV_FLUSH3(DMOV_NAND_CHAN)));
100 }
101 n = readl(ch.status);
102 }
103
104 return 0;
105}
106
Dima Zavinca337f52009-03-02 16:41:44 -0800107static struct flash_info flash_info;
Shashank Mittaldcc2e352009-11-19 19:11:16 -0800108static unsigned flash_pagesize = 0;
Dima Zavin03cf4312009-01-23 16:38:30 -0800109
Shashank Mittal83d16d02009-11-18 16:54:42 -0800110struct flash_identification {
Shashank Mittalc20b5a12009-11-18 19:35:30 -0800111 unsigned flash_id;
112 unsigned mask;
113 unsigned density;
114 unsigned widebus;
115 unsigned pagesize;
116 unsigned blksize;
117 unsigned oobsize;
118 unsigned onenand;
Shashank Mittal83d16d02009-11-18 16:54:42 -0800119};
120
121static struct flash_identification supported_flash[] =
122{
Shashank Mittalc20b5a12009-11-18 19:35:30 -0800123 /* Flash ID ID Mask Density(MB) Wid Pgsz Blksz oobsz onenand Manuf */
124 {0x00000000, 0xFFFFFFFF, 0, 0, 0, 0, 0, 0}, /*ONFI*/
125 {0x1500aaec, 0xFF00FFFF, (256<<20), 0, 2048, (2048<<6), 64, 0}, /*Sams*/
126 {0x5500baec, 0xFF00FFFF, (256<<20), 1, 2048, (2048<<6), 64, 0}, /*Sams*/
127 {0x1500aa98, 0xFFFFFFFF, (256<<20), 0, 2048, (2048<<6), 64, 0}, /*Tosh*/
128 {0x5500ba98, 0xFFFFFFFF, (256<<20), 1, 2048, (2048<<6), 64, 0}, /*Tosh*/
Ajay Dudani86e1b422009-12-04 20:49:50 -0800129 {0xd580b12c, 0xFFFFFFFF, (256<<20), 1, 2048, (2048<<6), 64, 0}, /*Micr*/
130 {0x5590bc2c, 0xFFFFFFFF, (256<<20), 1, 2048, (2048<<6), 64, 0}, /*Micr*/
Chandan Uddaraju0ec234c2009-11-24 22:34:50 -0800131 {0x1580aa2c, 0xFFFFFFFF, (256<<20), 0, 2048, (2048<<6), 64, 0}, /*Micr*/
Shashank Mittalc20b5a12009-11-18 19:35:30 -0800132 {0x5580baad, 0xFFFFFFFF, (256<<20), 1, 2048, (2048<<6), 64, 0}, /*Hynx*/
133 {0x5510baad, 0xFFFFFFFF, (256<<20), 1, 2048, (2048<<6), 64, 0}, /*Hynx*/
134 {0x004000ec, 0xFFFFFFFF, (256<<20), 0, 2048, (2048<<6), 64, 1}, /*Sams*/
135 {0x005c00ec, 0xFFFFFFFF, (256<<20), 0, 2048, (2048<<6), 64, 1}, /*Sams*/
136 {0x005800ec, 0xFFFFFFFF, (256<<20), 0, 2048, (2048<<6), 64, 1}, /*Sams*/
Chandan Uddaraju9e5ab962010-01-21 15:36:37 -0800137 {0x6600bcec, 0xFF00FFFF, (512<<20), 1, 4096, (2048<<6), 128, 0}, /*Sams*/
Shashank Mittalc20b5a12009-11-18 19:35:30 -0800138 /* Note: Width flag is 0 for 8 bit Flash and 1 for 16 bit flash */
139 /* Note: Onenand flag is 0 for NAND Flash and 1 for OneNAND flash */
140 /* Note: The First row will be filled at runtime during ONFI probe */
Shashank Mittal83d16d02009-11-18 16:54:42 -0800141};
Shashank Mittal8e49dec2010-03-01 15:19:04 -0800142static void set_nand_configuration(char type)
143{
144 if(type == TYPE_MODEM_PARTITION)
145 {
146 CFG0 = CFG0_M;
147 CFG1 = CFG1_M;
148 }
149 else
150 {
151 CFG0 = CFG0_A;
152 CFG1 = CFG1_A;
153 }
154}
Shashank Mittal83d16d02009-11-18 16:54:42 -0800155
156static void flash_nand_read_id(dmov_s *cmdlist, unsigned *ptrlist)
Dima Zavin03cf4312009-01-23 16:38:30 -0800157{
158 dmov_s *cmd = cmdlist;
159 unsigned *ptr = ptrlist;
160 unsigned *data = ptrlist + 4;
161
162 data[0] = 0 | 4;
163 data[1] = NAND_CMD_FETCH_ID;
164 data[2] = 1;
165 data[3] = 0;
166 data[4] = 0;
Shashank Mittalc20b5a12009-11-18 19:35:30 -0800167 data[5] = 0;
168 data[6] = 0;
169 data[7] = 0xAAD40000; /* Default value for CFG0 for reading device id */
Dima Zavin03cf4312009-01-23 16:38:30 -0800170
Shashank Mittalc20b5a12009-11-18 19:35:30 -0800171 /* Read NAND device id */
Dima Zavin03cf4312009-01-23 16:38:30 -0800172 cmd[0].cmd = 0 | CMD_OCB;
Shashank Mittalc20b5a12009-11-18 19:35:30 -0800173 cmd[0].src = paddr(&data[7]);
174 cmd[0].dst = NAND_DEV0_CFG0;
Dima Zavin03cf4312009-01-23 16:38:30 -0800175 cmd[0].len = 4;
176
Shashank Mittalc20b5a12009-11-18 19:35:30 -0800177 cmd[1].cmd = 0;
178 cmd[1].src = NAND_SFLASHC_BURST_CFG;
179 cmd[1].dst = paddr(&data[5]);
Dima Zavin03cf4312009-01-23 16:38:30 -0800180 cmd[1].len = 4;
181
182 cmd[2].cmd = 0;
Shashank Mittalc20b5a12009-11-18 19:35:30 -0800183 cmd[2].src = paddr(&data[6]);
184 cmd[2].dst = NAND_SFLASHC_BURST_CFG;
Dima Zavin03cf4312009-01-23 16:38:30 -0800185 cmd[2].len = 4;
186
Shashank Mittalc20b5a12009-11-18 19:35:30 -0800187 cmd[3].cmd = 0;
188 cmd[3].src = paddr(&data[0]);
189 cmd[3].dst = NAND_FLASH_CHIP_SELECT;
Dima Zavin03cf4312009-01-23 16:38:30 -0800190 cmd[3].len = 4;
191
Shashank Mittalc20b5a12009-11-18 19:35:30 -0800192 cmd[4].cmd = DST_CRCI_NAND_CMD;
193 cmd[4].src = paddr(&data[1]);
194 cmd[4].dst = NAND_FLASH_CMD;
Dima Zavin03cf4312009-01-23 16:38:30 -0800195 cmd[4].len = 4;
196
Shashank Mittalc20b5a12009-11-18 19:35:30 -0800197 cmd[5].cmd = 0;
198 cmd[5].src = paddr(&data[2]);
199 cmd[5].dst = NAND_EXEC_CMD;
200 cmd[5].len = 4;
201
202 cmd[6].cmd = SRC_CRCI_NAND_DATA;
203 cmd[6].src = NAND_FLASH_STATUS;
204 cmd[6].dst = paddr(&data[3]);
205 cmd[6].len = 4;
206
207 cmd[7].cmd = 0;
208 cmd[7].src = NAND_READ_ID;
209 cmd[7].dst = paddr(&data[4]);
210 cmd[7].len = 4;
211
212 cmd[8].cmd = CMD_OCU | CMD_LC;
213 cmd[8].src = paddr(&data[5]);
214 cmd[8].dst = NAND_SFLASHC_BURST_CFG;
215 cmd[8].len = 4;
216
Dima Zavin03cf4312009-01-23 16:38:30 -0800217 ptr[0] = (paddr(cmd) >> 3) | CMD_PTR_LP;
218
219 dmov_exec_cmdptr(DMOV_NAND_CHAN, ptr);
220
221#if VERBOSE
222 dprintf(INFO, "status: %x\n", data[3]);
223#endif
Dima Zavin03cf4312009-01-23 16:38:30 -0800224
Shashank Mittal83d16d02009-11-18 16:54:42 -0800225 flash_info.id = data[4];
Dima Zavinca337f52009-03-02 16:41:44 -0800226 flash_info.vendor = data[4] & 0xff;
227 flash_info.device = (data[4] >> 8) & 0xff;
Shashank Mittal83d16d02009-11-18 16:54:42 -0800228 return;
229}
Dima Zavinca337f52009-03-02 16:41:44 -0800230
Shashank Mittalad3d05c2009-11-19 15:53:57 -0800231static int flash_nand_block_isbad(dmov_s *cmdlist, unsigned *ptrlist,
232 unsigned page)
233{
234 dmov_s *cmd = cmdlist;
235 unsigned *ptr = ptrlist;
236 unsigned *data = ptrlist + 4;
237 char buf[4];
Shashank Mittaldcc2e352009-11-19 19:11:16 -0800238 unsigned cwperpage;
239
240 cwperpage = (flash_pagesize >> 9);
Shashank Mittalad3d05c2009-11-19 15:53:57 -0800241
242 /* Check first page of this block */
243 if(page & 63)
244 page = page - (page & 63);
245
246 /* Check bad block marker */
247 data[0] = NAND_CMD_PAGE_READ; /* command */
248
249 /* addr0 */
250 if (CFG1 & CFG1_WIDE_FLASH)
Shashank Mittaldcc2e352009-11-19 19:11:16 -0800251 data[1] = (page << 16) | ((528*(cwperpage-1)) >> 1);
Shashank Mittalad3d05c2009-11-19 15:53:57 -0800252 else
Shashank Mittaldcc2e352009-11-19 19:11:16 -0800253 data[1] = (page << 16) | (528*(cwperpage-1));
Shashank Mittalad3d05c2009-11-19 15:53:57 -0800254
255 data[2] = (page >> 16) & 0xff; /* addr1 */
256 data[3] = 0 | 4; /* chipsel */
257 data[4] = NAND_CFG0_RAW & ~(7U << 6); /* cfg0 */
258 data[5] = NAND_CFG1_RAW | (CFG1 & CFG1_WIDE_FLASH); /* cfg1 */
259 data[6] = 1;
260 data[7] = CLEAN_DATA_32; /* flash status */
261 data[8] = CLEAN_DATA_32; /* buf status */
262
263 cmd[0].cmd = DST_CRCI_NAND_CMD | CMD_OCB;
264 cmd[0].src = paddr(&data[0]);
265 cmd[0].dst = NAND_FLASH_CMD;
266 cmd[0].len = 16;
267
268 cmd[1].cmd = 0;
269 cmd[1].src = paddr(&data[4]);
270 cmd[1].dst = NAND_DEV0_CFG0;
271 cmd[1].len = 8;
272
273 cmd[2].cmd = 0;
274 cmd[2].src = paddr(&data[6]);
275 cmd[2].dst = NAND_EXEC_CMD;
276 cmd[2].len = 4;
277
278 cmd[3].cmd = SRC_CRCI_NAND_DATA;
279 cmd[3].src = NAND_FLASH_STATUS;
280 cmd[3].dst = paddr(&data[7]);
281 cmd[3].len = 8;
282
283 cmd[4].cmd = CMD_OCU | CMD_LC;
Shashank Mittaldcc2e352009-11-19 19:11:16 -0800284 cmd[4].src = NAND_FLASH_BUFFER + (flash_pagesize - (528*(cwperpage-1)));
Shashank Mittalad3d05c2009-11-19 15:53:57 -0800285 cmd[4].dst = paddr(&buf);
286 cmd[4].len = 4;
287
288 ptr[0] = (paddr(cmd) >> 3) | CMD_PTR_LP;
289
290 dmov_exec_cmdptr(DMOV_NAND_CHAN, ptr);
291
292#if VERBOSE
293 dprintf(INFO, "status: %x\n", data[7]);
294#endif
295
296 /* we fail if there was an operation error, a mpu error, or the
297 ** erase success bit was not set.
298 */
299 if(data[7] & 0x110) return -1;
300
301 /* Check for bad block marker byte */
302 if (CFG1 & CFG1_WIDE_FLASH) {
303 if (buf[0] != 0xFF || buf[1] != 0xFF)
304 return 1;
305 } else {
306 if (buf[0] != 0xFF)
307 return 1;
308 }
309
310 return 0;
311}
312
Shashank Mittalc20b5a12009-11-18 19:35:30 -0800313static int flash_nand_erase_block(dmov_s *cmdlist, unsigned *ptrlist,
314 unsigned page)
Dima Zavin03cf4312009-01-23 16:38:30 -0800315{
316 dmov_s *cmd = cmdlist;
317 unsigned *ptr = ptrlist;
318 unsigned *data = ptrlist + 4;
Shashank Mittalad3d05c2009-11-19 15:53:57 -0800319 int isbad = 0;
Dima Zavin03cf4312009-01-23 16:38:30 -0800320
321 /* only allow erasing on block boundaries */
322 if(page & 63) return -1;
323
Shashank Mittalad3d05c2009-11-19 15:53:57 -0800324 /* Check for bad block and erase only if block is not marked bad */
325 isbad = flash_nand_block_isbad(cmdlist, ptrlist, page);
326
327 if (isbad) {
328 dprintf(INFO, "skipping @ %d (bad block)\n", page >> 6);
329 return -1;
330 }
331
332 /* Erase block */
Dima Zavin03cf4312009-01-23 16:38:30 -0800333 data[0] = NAND_CMD_BLOCK_ERASE;
334 data[1] = page;
335 data[2] = 0;
336 data[3] = 0 | 4;
337 data[4] = 1;
338 data[5] = 0xeeeeeeee;
339 data[6] = CFG0 & (~(7 << 6)); /* CW_PER_PAGE = 0 */
340 data[7] = CFG1;
Murali Palnatic54d13a2010-01-15 19:50:19 +0530341 data[8] = 0x00000020;
342 data[9] = 0x000000C0;
Dima Zavin03cf4312009-01-23 16:38:30 -0800343
344 cmd[0].cmd = DST_CRCI_NAND_CMD | CMD_OCB;
345 cmd[0].src = paddr(&data[0]);
346 cmd[0].dst = NAND_FLASH_CMD;
347 cmd[0].len = 16;
348
349 cmd[1].cmd = 0;
350 cmd[1].src = paddr(&data[6]);
351 cmd[1].dst = NAND_DEV0_CFG0;
352 cmd[1].len = 8;
353
354 cmd[2].cmd = 0;
355 cmd[2].src = paddr(&data[4]);
356 cmd[2].dst = NAND_EXEC_CMD;
357 cmd[2].len = 4;
358
Murali Palnatic54d13a2010-01-15 19:50:19 +0530359 cmd[3].cmd = SRC_CRCI_NAND_DATA;
Dima Zavin03cf4312009-01-23 16:38:30 -0800360 cmd[3].src = NAND_FLASH_STATUS;
361 cmd[3].dst = paddr(&data[5]);
362 cmd[3].len = 4;
363
Murali Palnatic54d13a2010-01-15 19:50:19 +0530364 cmd[4].cmd = 0;
365 cmd[4].src = paddr(&data[8]);
366 cmd[4].dst = NAND_FLASH_STATUS;
367 cmd[4].len = 4;
368
369 cmd[5].cmd = CMD_OCU | CMD_LC;
370 cmd[5].src = paddr(&data[9]);
371 cmd[5].dst = NAND_READ_STATUS;
372 cmd[5].len = 4;
373
Dima Zavin03cf4312009-01-23 16:38:30 -0800374 ptr[0] = (paddr(cmd) >> 3) | CMD_PTR_LP;
375
376 dmov_exec_cmdptr(DMOV_NAND_CHAN, ptr);
377
378#if VERBOSE
379 dprintf(INFO, "status: %x\n", data[5]);
380#endif
381
382 /* we fail if there was an operation error, a mpu error, or the
383 ** erase success bit was not set.
384 */
385 if(data[5] & 0x110) return -1;
386 if(!(data[5] & 0x80)) return -1;
387
388 return 0;
389}
390
391struct data_flash_io {
392 unsigned cmd;
393 unsigned addr0;
394 unsigned addr1;
395 unsigned chipsel;
396 unsigned cfg0;
397 unsigned cfg1;
398 unsigned exec;
399 unsigned ecc_cfg;
400 unsigned ecc_cfg_save;
Murali Palnatic54d13a2010-01-15 19:50:19 +0530401 unsigned clrfstatus;
402 unsigned clrrstatus;
Dima Zavin03cf4312009-01-23 16:38:30 -0800403 struct {
404 unsigned flash_status;
405 unsigned buffer_status;
Shashank Mittaldcc2e352009-11-19 19:11:16 -0800406 } result[8];
Dima Zavin03cf4312009-01-23 16:38:30 -0800407};
408
Shashank Mittalc20b5a12009-11-18 19:35:30 -0800409static int _flash_nand_read_page(dmov_s *cmdlist, unsigned *ptrlist,
410 unsigned page, void *_addr, void *_spareaddr)
Dima Zavin03cf4312009-01-23 16:38:30 -0800411{
412 dmov_s *cmd = cmdlist;
413 unsigned *ptr = ptrlist;
414 struct data_flash_io *data = (void*) (ptrlist + 4);
415 unsigned addr = (unsigned) _addr;
416 unsigned spareaddr = (unsigned) _spareaddr;
417 unsigned n;
Shashank Mittalad3d05c2009-11-19 15:53:57 -0800418 int isbad = 0;
Shashank Mittaldcc2e352009-11-19 19:11:16 -0800419 unsigned cwperpage;
420 cwperpage = (flash_pagesize >> 9);
Shashank Mittalad3d05c2009-11-19 15:53:57 -0800421
422 /* Check for bad block and read only from a good block */
423 isbad = flash_nand_block_isbad(cmdlist, ptrlist, page);
424 if (isbad)
425 return -2;
Dima Zavin03cf4312009-01-23 16:38:30 -0800426
427 data->cmd = NAND_CMD_PAGE_READ_ECC;
428 data->addr0 = page << 16;
429 data->addr1 = (page >> 16) & 0xff;
430 data->chipsel = 0 | 4; /* flash0 + undoc bit */
431
432 /* GO bit for the EXEC register */
433 data->exec = 1;
434
435 data->cfg0 = CFG0;
436 data->cfg1 = CFG1;
437
438 data->ecc_cfg = 0x203;
439
440 /* save existing ecc config */
441 cmd->cmd = CMD_OCB;
442 cmd->src = NAND_EBI2_ECC_BUF_CFG;
443 cmd->dst = paddr(&data->ecc_cfg_save);
444 cmd->len = 4;
445 cmd++;
446
Shashank Mittaldcc2e352009-11-19 19:11:16 -0800447 for(n = 0; n < cwperpage; n++) {
Dima Zavin03cf4312009-01-23 16:38:30 -0800448 /* write CMD / ADDR0 / ADDR1 / CHIPSEL regs in a burst */
449 cmd->cmd = DST_CRCI_NAND_CMD;
450 cmd->src = paddr(&data->cmd);
451 cmd->dst = NAND_FLASH_CMD;
452 cmd->len = ((n == 0) ? 16 : 4);
453 cmd++;
454
455 if (n == 0) {
456 /* block on cmd ready, set configuration */
457 cmd->cmd = 0;
458 cmd->src = paddr(&data->cfg0);
459 cmd->dst = NAND_DEV0_CFG0;
460 cmd->len = 8;
461 cmd++;
462
463 /* set our ecc config */
464 cmd->cmd = 0;
465 cmd->src = paddr(&data->ecc_cfg);
466 cmd->dst = NAND_EBI2_ECC_BUF_CFG;
467 cmd->len = 4;
468 cmd++;
469 }
470 /* kick the execute register */
471 cmd->cmd = 0;
472 cmd->src = paddr(&data->exec);
473 cmd->dst = NAND_EXEC_CMD;
474 cmd->len = 4;
475 cmd++;
476
477 /* block on data ready, then read the status register */
478 cmd->cmd = SRC_CRCI_NAND_DATA;
479 cmd->src = NAND_FLASH_STATUS;
480 cmd->dst = paddr(&data->result[n]);
481 cmd->len = 8;
482 cmd++;
483
484 /* read data block */
485 cmd->cmd = 0;
486 cmd->src = NAND_FLASH_BUFFER;
487 cmd->dst = addr + n * 516;
Shashank Mittaldcc2e352009-11-19 19:11:16 -0800488 cmd->len = ((n < (cwperpage -1 )) ? 516 : (512 - ((cwperpage - 1) << 2)));
Dima Zavin03cf4312009-01-23 16:38:30 -0800489 cmd++;
490 }
491
492 /* read extra data */
493 cmd->cmd = 0;
494 cmd->src = NAND_FLASH_BUFFER + 500;
495 cmd->dst = spareaddr;
496 cmd->len = 16;
497 cmd++;
498
499 /* restore saved ecc config */
500 cmd->cmd = CMD_OCU | CMD_LC;
501 cmd->src = paddr(&data->ecc_cfg_save);
502 cmd->dst = NAND_EBI2_ECC_BUF_CFG;
503 cmd->len = 4;
504
505 ptr[0] = (paddr(cmdlist) >> 3) | CMD_PTR_LP;
506
507 dmov_exec_cmdptr(DMOV_NAND_CHAN, ptr);
508
509#if VERBOSE
510 dprintf(INFO, "read page %d: status: %x %x %x %x\n",
511 page, data[5], data[6], data[7], data[8]);
512 for(n = 0; n < 4; n++) {
513 ptr = (unsigned*)(addr + 512 * n);
Shashank Mittalc20b5a12009-11-18 19:35:30 -0800514 dprintf(INFO, "data%d: %x %x %x %x\n", n, ptr[0], ptr[1], ptr[2], ptr[3]);
Dima Zavin03cf4312009-01-23 16:38:30 -0800515 ptr = (unsigned*)(spareaddr + 16 * n);
Shashank Mittalc20b5a12009-11-18 19:35:30 -0800516 dprintf(INFO, "spare data%d %x %x %x %x\n", n, ptr[0], ptr[1], ptr[2], ptr[3]);
Dima Zavin03cf4312009-01-23 16:38:30 -0800517 }
518#endif
519
520 /* if any of the writes failed (0x10), or there was a
521 ** protection violation (0x100), we lose
522 */
Shashank Mittaldcc2e352009-11-19 19:11:16 -0800523 for(n = 0; n < cwperpage; n++) {
Dima Zavin03cf4312009-01-23 16:38:30 -0800524 if (data->result[n].flash_status & 0x110) {
525 return -1;
526 }
527 }
528
529 return 0;
530}
531
Shashank Mittalc20b5a12009-11-18 19:35:30 -0800532static int _flash_nand_write_page(dmov_s *cmdlist, unsigned *ptrlist, unsigned page,
Shashank Mittald0c836d2009-11-20 10:31:18 -0800533 const void *_addr, const void *_spareaddr, unsigned raw_mode)
Dima Zavin03cf4312009-01-23 16:38:30 -0800534{
535 dmov_s *cmd = cmdlist;
536 unsigned *ptr = ptrlist;
537 struct data_flash_io *data = (void*) (ptrlist + 4);
538 unsigned addr = (unsigned) _addr;
539 unsigned spareaddr = (unsigned) _spareaddr;
Shashank Mittalc20b5a12009-11-18 19:35:30 -0800540 unsigned n;
Shashank Mittaldcc2e352009-11-19 19:11:16 -0800541 unsigned cwperpage;
542 cwperpage = (flash_pagesize >> 9);
Shashank Mittal8e49dec2010-03-01 15:19:04 -0800543 unsigned modem_partition = 0;
544 if (CFG0 == CFG0_M)
545 {
546 modem_partition = 1;
547 }
Dima Zavin03cf4312009-01-23 16:38:30 -0800548
549 data->cmd = NAND_CMD_PRG_PAGE;
550 data->addr0 = page << 16;
551 data->addr1 = (page >> 16) & 0xff;
552 data->chipsel = 0 | 4; /* flash0 + undoc bit */
Murali Palnatic54d13a2010-01-15 19:50:19 +0530553 data->clrfstatus = 0x00000020;
554 data->clrrstatus = 0x000000C0;
Dima Zavin03cf4312009-01-23 16:38:30 -0800555
Shashank Mittald0c836d2009-11-20 10:31:18 -0800556 if (!raw_mode){
557 data->cfg0 = CFG0;
558 data->cfg1 = CFG1;
559 }else{
560 data->cfg0 = (NAND_CFG0_RAW & ~(7 << 6)) |((cwperpage-1) << 6);
561 data->cfg1 = NAND_CFG1_RAW | (CFG1 & CFG1_WIDE_FLASH);
562 }
Dima Zavin03cf4312009-01-23 16:38:30 -0800563
564 /* GO bit for the EXEC register */
565 data->exec = 1;
566
Shashank Mittal8e49dec2010-03-01 15:19:04 -0800567 if (modem_partition)
568 data->ecc_cfg = 0x1FF;
569 else
570 data->ecc_cfg = 0x203;
Dima Zavin03cf4312009-01-23 16:38:30 -0800571
572 /* save existing ecc config */
573 cmd->cmd = CMD_OCB;
574 cmd->src = NAND_EBI2_ECC_BUF_CFG;
575 cmd->dst = paddr(&data->ecc_cfg_save);
576 cmd->len = 4;
577 cmd++;
578
Shashank Mittaldcc2e352009-11-19 19:11:16 -0800579 for(n = 0; n < cwperpage; n++) {
580 /* write CMD / ADDR0 / ADDR1 / CHIPSEL regs in a burst */
Dima Zavin03cf4312009-01-23 16:38:30 -0800581 cmd->cmd = DST_CRCI_NAND_CMD;
582 cmd->src = paddr(&data->cmd);
583 cmd->dst = NAND_FLASH_CMD;
584 cmd->len = ((n == 0) ? 16 : 4);
585 cmd++;
586
587 if (n == 0) {
588 /* set configuration */
589 cmd->cmd = 0;
590 cmd->src = paddr(&data->cfg0);
591 cmd->dst = NAND_DEV0_CFG0;
592 cmd->len = 8;
593 cmd++;
594
595 /* set our ecc config */
596 cmd->cmd = 0;
597 cmd->src = paddr(&data->ecc_cfg);
598 cmd->dst = NAND_EBI2_ECC_BUF_CFG;
599 cmd->len = 4;
600 cmd++;
601 }
602
603 /* write data block */
604 cmd->cmd = 0;
Dima Zavin03cf4312009-01-23 16:38:30 -0800605 cmd->dst = NAND_FLASH_BUFFER;
Shashank Mittald0c836d2009-11-20 10:31:18 -0800606 if (!raw_mode){
Shashank Mittal8e49dec2010-03-01 15:19:04 -0800607 if(modem_partition){
608 cmd->src = addr + n * 512;
609 cmd->len = 512;
610 }else{
611 cmd->src = addr + n * 516;
612 cmd->len = ((n < (cwperpage - 1)) ? 516 : (512 - ((cwperpage - 1) << 2)));
613 }
Shashank Mittald0c836d2009-11-20 10:31:18 -0800614 }else{
615 cmd->src = addr;
616 cmd->len = 528;
617 }
Dima Zavin03cf4312009-01-23 16:38:30 -0800618 cmd++;
619
Shashank Mittal8e49dec2010-03-01 15:19:04 -0800620 if ((n == (cwperpage - 1)) && (!raw_mode) && (!modem_partition)) {
Dima Zavin03cf4312009-01-23 16:38:30 -0800621 /* write extra data */
622 cmd->cmd = 0;
623 cmd->src = spareaddr;
Shashank Mittaldcc2e352009-11-19 19:11:16 -0800624 cmd->dst = NAND_FLASH_BUFFER + (512 - ((cwperpage - 1) << 2));
625 cmd->len = (cwperpage << 2);
Dima Zavin03cf4312009-01-23 16:38:30 -0800626 cmd++;
627 }
628
629 /* kick the execute register */
630 cmd->cmd = 0;
631 cmd->src = paddr(&data->exec);
632 cmd->dst = NAND_EXEC_CMD;
633 cmd->len = 4;
634 cmd++;
635
636 /* block on data ready, then read the status register */
637 cmd->cmd = SRC_CRCI_NAND_DATA;
638 cmd->src = NAND_FLASH_STATUS;
639 cmd->dst = paddr(&data->result[n]);
640 cmd->len = 8;
641 cmd++;
Murali Palnatic54d13a2010-01-15 19:50:19 +0530642
643 cmd->cmd = 0;
644 cmd->src = paddr(&data->clrfstatus);
645 cmd->dst = NAND_FLASH_STATUS;
646 cmd->len = 4;
647 cmd++;
648
649 cmd->cmd = 0;
650 cmd->src = paddr(&data->clrrstatus);
651 cmd->dst = NAND_READ_STATUS;
652 cmd->len = 4;
653 cmd++;
Dima Zavin03cf4312009-01-23 16:38:30 -0800654 }
655
656 /* restore saved ecc config */
657 cmd->cmd = CMD_OCU | CMD_LC;
658 cmd->src = paddr(&data->ecc_cfg_save);
659 cmd->dst = NAND_EBI2_ECC_BUF_CFG;
660 cmd->len = 4;
661
662 ptr[0] = (paddr(cmdlist) >> 3) | CMD_PTR_LP;
663
664 dmov_exec_cmdptr(DMOV_NAND_CHAN, ptr);
665
666#if VERBOSE
667 dprintf(INFO, "write page %d: status: %x %x %x %x\n",
668 page, data[5], data[6], data[7], data[8]);
669#endif
670
671 /* if any of the writes failed (0x10), or there was a
672 ** protection violation (0x100), or the program success
673 ** bit (0x80) is unset, we lose
674 */
Shashank Mittaldcc2e352009-11-19 19:11:16 -0800675 for(n = 0; n < cwperpage; n++) {
Dima Zavin03cf4312009-01-23 16:38:30 -0800676 if(data->result[n].flash_status & 0x110) return -1;
677 if(!(data->result[n].flash_status & 0x80)) return -1;
678 }
679
Dima Zavin5582c7d2009-03-03 15:17:59 -0800680#if VERIFY_WRITE
681 n = _flash_read_page(cmdlist, ptrlist, page, flash_data,
Shashank Mittalc20b5a12009-11-18 19:35:30 -0800682 flash_data + 2048);
Dima Zavin5582c7d2009-03-03 15:17:59 -0800683 if (n != 0)
684 return -1;
685 if (memcmp(flash_data, _addr, 2048) ||
Shashank Mittalc20b5a12009-11-18 19:35:30 -0800686 memcmp(flash_data + 2048, _spareaddr, 16)) {
Dima Zavin5582c7d2009-03-03 15:17:59 -0800687 dprintf(CRITICAL, "verify error @ page %d\n", page);
688 return -1;
689 }
690#endif
Dima Zavin03cf4312009-01-23 16:38:30 -0800691 return 0;
692}
Shashank Mittald0c836d2009-11-20 10:31:18 -0800693char empty_buf[528];
694static int flash_nand_mark_badblock(dmov_s *cmdlist, unsigned *ptrlist, unsigned page)
695{
696 memset(empty_buf,0,528);
697 /* Going to first page of the block */
698 if(page & 63)
699 page = page - (page & 63);
700 return _flash_nand_write_page(cmdlist, ptrlist, page, empty_buf, 0, 1);
701}
Dima Zavin03cf4312009-01-23 16:38:30 -0800702
Shashank Mittal83d16d02009-11-18 16:54:42 -0800703unsigned nand_cfg0;
704unsigned nand_cfg1;
705
Shashank Mittalc20b5a12009-11-18 19:35:30 -0800706static int flash_nand_read_config(dmov_s *cmdlist, unsigned *ptrlist)
Dima Zavin03cf4312009-01-23 16:38:30 -0800707{
Shashank Mittal8e49dec2010-03-01 15:19:04 -0800708 static unsigned CFG0_TMP, CFG1_TMP;
Dima Zavin03cf4312009-01-23 16:38:30 -0800709 cmdlist[0].cmd = CMD_OCB;
710 cmdlist[0].src = NAND_DEV0_CFG0;
Shashank Mittal8e49dec2010-03-01 15:19:04 -0800711 cmdlist[0].dst = paddr(&CFG0_TMP);
Dima Zavin03cf4312009-01-23 16:38:30 -0800712 cmdlist[0].len = 4;
713
714 cmdlist[1].cmd = CMD_OCU | CMD_LC;
715 cmdlist[1].src = NAND_DEV0_CFG1;
Shashank Mittal8e49dec2010-03-01 15:19:04 -0800716 cmdlist[1].dst = paddr(&CFG1_TMP);
Dima Zavin03cf4312009-01-23 16:38:30 -0800717 cmdlist[1].len = 4;
718
719 *ptrlist = (paddr(cmdlist) >> 3) | CMD_PTR_LP;
720
721 dmov_exec_cmdptr(DMOV_NAND_CHAN, ptrlist);
722
Shashank Mittal8e49dec2010-03-01 15:19:04 -0800723 if((CFG0_TMP == 0) || (CFG1_TMP == 0)) {
Dima Zavin03cf4312009-01-23 16:38:30 -0800724 return -1;
725 }
726
Shashank Mittal8e49dec2010-03-01 15:19:04 -0800727 CFG0_A = CFG0_TMP;
728 CFG1_A = CFG1_TMP;
Shashank Mittal83d16d02009-11-18 16:54:42 -0800729 if (flash_info.type == FLASH_16BIT_NAND_DEVICE) {
730 nand_cfg1 |= CFG1_WIDE_FLASH;
731 }
Dima Zavin03cf4312009-01-23 16:38:30 -0800732 dprintf(INFO, "nandcfg: %x %x (initial)\n", CFG0, CFG1);
733
Shashank Mittal8e49dec2010-03-01 15:19:04 -0800734 CFG0_A = (((flash_pagesize >> 9) - 1) << 6) /* 4/8 cw/pg for 2/4k */
Shashank Mittalc20b5a12009-11-18 19:35:30 -0800735 | (516 << 9) /* 516 user data bytes */
736 | (10 << 19) /* 10 parity bytes */
737 | (5 << 27) /* 5 address cycles */
Murali Palnatic54d13a2010-01-15 19:50:19 +0530738 | (0 << 30) /* Do not read status before data */
Shashank Mittalc20b5a12009-11-18 19:35:30 -0800739 | (1 << 31) /* Send read cmd */
740 /* 0 spare bytes for 16 bit nand or 1 spare bytes for 8 bit */
741 | ((nand_cfg1 & CFG1_WIDE_FLASH) ? (0 << 23) : (1 << 23));
Shashank Mittal8e49dec2010-03-01 15:19:04 -0800742 CFG1_A = (0 << 0) /* Enable ecc */
Shashank Mittalc20b5a12009-11-18 19:35:30 -0800743 | (7 << 2) /* 8 recovery cycles */
744 | (0 << 5) /* Allow CS deassertion */
Shashank Mittaldcc2e352009-11-19 19:11:16 -0800745 | ((flash_pagesize - (528 * ((flash_pagesize >> 9) - 1)) + 1) << 6) /* Bad block marker location */
Shashank Mittalc20b5a12009-11-18 19:35:30 -0800746 | (0 << 16) /* Bad block in user data area */
747 | (2 << 17) /* 6 cycle tWB/tRB */
748 | (nand_cfg1 & CFG1_WIDE_FLASH); /* preserve wide flash flag */
Dima Zavin03cf4312009-01-23 16:38:30 -0800749
Shashank Mittal8e49dec2010-03-01 15:19:04 -0800750 dprintf(INFO, "nandcfg(Apps): %x %x (used)\n", CFG0_A, CFG1_A);
Dima Zavin03cf4312009-01-23 16:38:30 -0800751
Shashank Mittal8e49dec2010-03-01 15:19:04 -0800752 CFG0_M = CFG0_TMP;
753 CFG1_M = CFG1_TMP;
754 if (flash_info.type == FLASH_16BIT_NAND_DEVICE) {
755 nand_cfg1 |= CFG1_WIDE_FLASH;
756 }
757 CFG0_M = (((flash_pagesize >> 9) - 1) << 6) /* 4/8 cw/pg for 2/4k */
758 | (512 << 9) /* 512 user data bytes */
759 | (10 << 19) /* 10 parity bytes */
760 | (5 << 27) /* 5 address cycles */
761 | (0 << 30) /* Do not read status before data */
762 | (1 << 31) /* Send read cmd */
763 | ((nand_cfg1 & CFG1_WIDE_FLASH) ? (4 << 23) : (5 << 23));
764 CFG1_M = (0 << 0) /* Enable ecc */
765 | (7 << 2) /* 8 recovery cycles */
766 | (0 << 5) /* Allow CS deassertion */
767 | ((flash_pagesize - (528 * ((flash_pagesize >> 9) - 1)) + 1) << 6) /* Bad block marker location */
768 | (0 << 16) /* Bad block in user data area */
769 | (2 << 17) /* 6 cycle tWB/tRB */
770 | (nand_cfg1 & CFG1_WIDE_FLASH); /* preserve wide flash flag */
771 dprintf(INFO, "nandcfg(Modem): %x %x (used)\n", CFG0_M, CFG1_M);
Dima Zavin03cf4312009-01-23 16:38:30 -0800772 return 0;
773}
774
Shashank Mittalc20b5a12009-11-18 19:35:30 -0800775/* OneNAND programming functions */
776
777static void flash_onenand_read_id(dmov_s *cmdlist, unsigned *ptrlist)
778{
779 dmov_s *cmd = cmdlist;
780 unsigned *ptr = ptrlist;
781 unsigned *data = ptrlist + 4;
782
783 data[0] = SFLASH_BCFG;
784 data[1] = SFLASH_PREPCMD(8, 0, 0, NAND_SFCMD_DATXS, NAND_SFCMD_ASYNC, NAND_SFCMD_REGRD);
785 data[2] = (ONENAND_DEVICE_ID << 16) | (ONENAND_MANUFACTURER_ID);
786 data[3] = (ONENAND_DATA_BUFFER_SIZE << 16) | (ONENAND_VERSION_ID);
787 data[4] = (ONENAND_AMOUNT_OF_BUFFERS << 16) | (ONENAND_BOOT_BUFFER_SIZE);
788 data[5] = (CLEAN_DATA_16 << 16) | (ONENAND_TECHNOLOGY);
789 data[6] = CLEAN_DATA_32; //status
790 data[7] = CLEAN_DATA_32; //register read
791 data[8] = CLEAN_DATA_32; //register read
792 data[9] = CLEAN_DATA_32; //register read
793 data[10] = CLEAN_DATA_32; //register read
794 data[11] = 1;
795 data[12] = 0 | 4;
796
797 /* Setup controller in SFLASH mode */
798 cmd[0].cmd = 0 | CMD_OCB;
799 cmd[0].src = paddr(&data[0]);
800 cmd[0].dst = NAND_SFLASHC_BURST_CFG;
801 cmd[0].len = 4;
802
803 /* Enable data mover for controller */
804 cmd[1].cmd = 0;
805 cmd[1].src = paddr(&data[12]);
806 cmd[1].dst = NAND_FLASH_CHIP_SELECT;
807 cmd[1].len = 4;
808
809 /* Setup SFLASHC_CMD with xfers in async mode */
810 cmd[2].cmd = DST_CRCI_NAND_CMD;
811 cmd[2].src = paddr(&data[1]);
812 cmd[2].dst = NAND_SFLASHC_CMD;
813 cmd[2].len = 4;
814
815 /* Setup to read device information */
816 cmd[3].cmd = 0;
817 cmd[3].src = paddr(&data[2]);
818 cmd[3].dst = NAND_ADDR0;
819 cmd[3].len = 8;
820
821 cmd[4].cmd = 0;
822 cmd[4].src = paddr(&data[4]);
823 cmd[4].dst = NAND_ADDR2;
824 cmd[4].len = 8;
825
826 /* Set execute bit */
827 cmd[5].cmd = 0;
828 cmd[5].src = paddr(&data[11]);
829 cmd[5].dst = NAND_SFLASHC_EXEC_CMD;
830 cmd[5].len = 4;
831
832 /* Check status */
833 cmd[6].cmd = SRC_CRCI_NAND_DATA;
834 cmd[6].src = NAND_SFLASHC_STATUS;
835 cmd[6].dst = paddr(&data[6]);
836 cmd[6].len = 4;
837
838 /* Read result device registers */
839 cmd[7].cmd = 0 | CMD_OCU | CMD_LC;
840 cmd[7].src = NAND_GENP_REG0;
841 cmd[7].dst = paddr(&data[7]);
842 cmd[7].len = 16;
843
844 ptr[0] = (paddr(cmd) >> 3) | CMD_PTR_LP;
845
846 dmov_exec_cmdptr(DMOV_NAND_CHAN, ptr);
847
848#if VERBOSE
849 dprintf(INFO, "status: %x\n", data[6]);
850#endif
851
852 flash_info.id = data[7];
853 flash_info.vendor = data[7] & CLEAN_DATA_16;
854 flash_info.device = (data[7] >> 16) & CLEAN_DATA_16;
855 return;
856}
857
858
859struct data_onenand_erase {
860 unsigned sfbcfg;
861 unsigned sfcmd[4];
862 unsigned sfexec;
863 unsigned sfstat[4];
864 unsigned addr0;
865 unsigned addr1;
866 unsigned addr2;
867 unsigned addr3;
868 unsigned addr4;
869 unsigned addr5;
870 unsigned addr6;
871 unsigned data0;
872 unsigned data1;
873 unsigned data2;
874 unsigned data3;
875 unsigned data4;
876 unsigned data5;
877 unsigned data6;
878};
879
Shashank Mittalad3d05c2009-11-19 15:53:57 -0800880
881static int _flash_onenand_read_page(dmov_s *cmdlist, unsigned *ptrlist,
882 unsigned page, void *_addr,
883 void *_spareaddr, unsigned raw_mode);
884
885
886static int flash_onenand_block_isbad(dmov_s *cmdlist, unsigned *ptrlist,
887 unsigned page)
888{
889 unsigned char page_data[2112];
890 unsigned char *oobptr = &(page_data[2048]);
891
892 /* Going to first page of the block */
893 if(page & 63)
894 page = page - (page & 63);
895
896 /* Reading page in raw mode */
897 if (_flash_onenand_read_page(cmdlist, ptrlist,page, page_data, 0, 1))
898 return 1;
899
900 /* Checking if block is bad */
901 if ((oobptr[0] != 0xFF) || (oobptr[1] != 0xFF) ||
902 (oobptr[16] != 0xFF) || (oobptr[17] != 0xFF) ||
903 (oobptr[32] != 0xFF) || (oobptr[33] != 0xFF) ||
904 (oobptr[48] != 0xFF) || (oobptr[49] != 0xFF)
905 )
906 {
907 return 1;
908 }
909 return 0;
910}
911
Shashank Mittalc20b5a12009-11-18 19:35:30 -0800912static int flash_onenand_erase_block(dmov_s *cmdlist, unsigned *ptrlist,
913 unsigned page)
914{
915 dmov_s *cmd = cmdlist;
916 unsigned *ptr = ptrlist;
917 struct data_onenand_erase *data = (void *)ptrlist + 4;
Shashank Mittalad3d05c2009-11-19 15:53:57 -0800918 int isbad = 0;
Shashank Mittaldcc2e352009-11-19 19:11:16 -0800919 unsigned erasesize = (flash_pagesize << 6);
920 unsigned onenand_startaddr1 = DEVICE_FLASHCORE_0 | (page * flash_pagesize)/erasesize;
Shashank Mittalc20b5a12009-11-18 19:35:30 -0800921 unsigned onenand_startaddr8 = 0x0000;
922 unsigned onenand_startaddr2 = DEVICE_BUFFERRAM_0 << 15;
923 unsigned onenand_startbuffer = DATARAM0_0 << 8;
924
925 unsigned controller_status;
926 unsigned interrupt_status;
927 unsigned ecc_status;
928
Shashank Mittaldcc2e352009-11-19 19:11:16 -0800929 if((page * flash_pagesize) & (erasesize-1)) return -1;
Shashank Mittalc20b5a12009-11-18 19:35:30 -0800930
Shashank Mittalad3d05c2009-11-19 15:53:57 -0800931 /* Check for bad block and erase only if block is not marked bad */
932 isbad = flash_onenand_block_isbad(cmdlist, ptrlist, page);
933 if (isbad)
934 {
935 dprintf(INFO, "skipping @ %d (bad block)\n", page >> 6);
936 return -1;
937 }
938
939 /*Erase block*/
Shashank Mittalc20b5a12009-11-18 19:35:30 -0800940 onenand_startaddr1 = DEVICE_FLASHCORE_0 |
Shashank Mittaldcc2e352009-11-19 19:11:16 -0800941 ((page * flash_pagesize) / (erasesize));
Shashank Mittalc20b5a12009-11-18 19:35:30 -0800942 onenand_startaddr8 = 0x0000;
943 onenand_startaddr2 = DEVICE_BUFFERRAM_0 << 15;
944 onenand_startbuffer = DATARAM0_0 << 8;
945
946
947 data->sfbcfg = SFLASH_BCFG;
948 data->sfcmd[0] = SFLASH_PREPCMD(7, 0, 0,
949 NAND_SFCMD_CMDXS,
950 NAND_SFCMD_ASYNC,
951 NAND_SFCMD_REGWR);
952 data->sfcmd[1] = SFLASH_PREPCMD(0, 0, 32,
953 NAND_SFCMD_CMDXS,
954 NAND_SFCMD_ASYNC,
955 NAND_SFCMD_INTHI);
956 data->sfcmd[2] = SFLASH_PREPCMD(3, 7, 0,
957 NAND_SFCMD_DATXS,
958 NAND_SFCMD_ASYNC,
959 NAND_SFCMD_REGRD);
960 data->sfcmd[3] = SFLASH_PREPCMD(4, 10, 0,
961 NAND_SFCMD_CMDXS,
962 NAND_SFCMD_ASYNC,
963 NAND_SFCMD_REGWR);
964 data->sfexec = 1;
965 data->sfstat[0] = CLEAN_DATA_32;
966 data->sfstat[1] = CLEAN_DATA_32;
967 data->sfstat[2] = CLEAN_DATA_32;
968 data->sfstat[3] = CLEAN_DATA_32;
969 data->addr0 = (ONENAND_INTERRUPT_STATUS << 16) |
970 (ONENAND_SYSTEM_CONFIG_1);
971 data->addr1 = (ONENAND_START_ADDRESS_8 << 16) |
972 (ONENAND_START_ADDRESS_1);
973 data->addr2 = (ONENAND_START_BUFFER << 16) |
974 (ONENAND_START_ADDRESS_2);
975 data->addr3 = (ONENAND_ECC_STATUS << 16) |
976 (ONENAND_COMMAND);
977 data->addr4 = (ONENAND_CONTROLLER_STATUS << 16) |
978 (ONENAND_INTERRUPT_STATUS);
979 data->addr5 = (ONENAND_INTERRUPT_STATUS << 16) |
980 (ONENAND_SYSTEM_CONFIG_1);
981 data->addr6 = (ONENAND_START_ADDRESS_3 << 16) |
982 (ONENAND_START_ADDRESS_1);
983 data->data0 = (ONENAND_CLRINTR << 16) |
984 (ONENAND_SYSCFG1_ECCENA);
985 data->data1 = (onenand_startaddr8 << 16) |
986 (onenand_startaddr1);
987 data->data2 = (onenand_startbuffer << 16) |
988 (onenand_startaddr2);
989 data->data3 = (CLEAN_DATA_16 << 16) |
990 (ONENAND_CMDERAS);
991 data->data4 = (CLEAN_DATA_16 << 16) |
992 (CLEAN_DATA_16);
993 data->data5 = (ONENAND_CLRINTR << 16) |
994 (ONENAND_SYSCFG1_ECCENA);
995 data->data6 = (ONENAND_STARTADDR3_RES << 16) |
996 (ONENAND_STARTADDR1_RES);
997
998 /***************************************************************/
999 /* Write the necessary address registers in the onenand device */
1000 /***************************************************************/
1001
1002 /* Enable and configure the SFlash controller */
1003 cmd->cmd = 0 | CMD_OCB;
1004 cmd->src = paddr(&data->sfbcfg);
1005 cmd->dst = NAND_SFLASHC_BURST_CFG;
1006 cmd->len = 4;
1007 cmd++;
1008
1009 /* Block on cmd ready and write CMD register */
1010 cmd->cmd = DST_CRCI_NAND_CMD;
1011 cmd->src = paddr(&data->sfcmd[0]);
1012 cmd->dst = NAND_SFLASHC_CMD;
1013 cmd->len = 4;
1014 cmd++;
1015
1016 /* Write the ADDR0 and ADDR1 registers */
1017 cmd->cmd = 0;
1018 cmd->src = paddr(&data->addr0);
1019 cmd->dst = NAND_ADDR0;
1020 cmd->len = 8;
1021 cmd++;
1022
1023 /* Write the ADDR2 ADDR3 ADDR4 ADDR5 registers */
1024 cmd->cmd = 0;
1025 cmd->src = paddr(&data->addr2);
1026 cmd->dst = NAND_ADDR2;
1027 cmd->len = 16;
1028 cmd++;
1029
1030 /* Write the ADDR6 registers */
1031 cmd->cmd = 0;
1032 cmd->src = paddr(&data->addr6);
1033 cmd->dst = NAND_ADDR6;
1034 cmd->len = 4;
1035 cmd++;
1036
1037 /* Write the GENP0, GENP1, GENP2, GENP3, GENP4 registers */
1038 cmd->cmd = 0;
1039 cmd->src = paddr(&data->data0);
1040 cmd->dst = NAND_GENP_REG0;
1041 cmd->len = 16;
1042 cmd++;
1043
1044 /* Write the FLASH_DEV_CMD4,5,6 registers */
1045 cmd->cmd = 0;
1046 cmd->src = paddr(&data->data4);
1047 cmd->dst = NAND_DEV_CMD4;
1048 cmd->len = 12;
1049 cmd++;
1050
1051 /* Kick the execute command */
1052 cmd->cmd = 0;
1053 cmd->src = paddr(&data->sfexec);
1054 cmd->dst = NAND_SFLASHC_EXEC_CMD;
1055 cmd->len = 4;
1056 cmd++;
1057
1058 /* Block on data ready, and read the status register */
1059 cmd->cmd = SRC_CRCI_NAND_DATA;
1060 cmd->src = NAND_SFLASHC_STATUS;
1061 cmd->dst = paddr(&data->sfstat[0]);
1062 cmd->len = 4;
1063 cmd++;
1064
1065 /***************************************************************/
1066 /* Wait for the interrupt from the Onenand device controller */
1067 /***************************************************************/
1068
1069 /* Block on cmd ready and write CMD register */
1070 cmd->cmd = DST_CRCI_NAND_CMD;
1071 cmd->src = paddr(&data->sfcmd[1]);
1072 cmd->dst = NAND_SFLASHC_CMD;
1073 cmd->len = 4;
1074 cmd++;
1075
1076 /* Kick the execute command */
1077 cmd->cmd = 0;
1078 cmd->src = paddr(&data->sfexec);
1079 cmd->dst = NAND_SFLASHC_EXEC_CMD;
1080 cmd->len = 4;
1081 cmd++;
1082
1083 /* Block on data ready, and read the status register */
1084 cmd->cmd = SRC_CRCI_NAND_DATA;
1085 cmd->src = NAND_SFLASHC_STATUS;
1086 cmd->dst = paddr(&data->sfstat[1]);
1087 cmd->len = 4;
1088 cmd++;
1089
1090 /***************************************************************/
1091 /* Read the necessary status registers from the onenand device */
1092 /***************************************************************/
1093
1094 /* Block on cmd ready and write CMD register */
1095 cmd->cmd = DST_CRCI_NAND_CMD;
1096 cmd->src = paddr(&data->sfcmd[2]);
1097 cmd->dst = NAND_SFLASHC_CMD;
1098 cmd->len = 4;
1099 cmd++;
1100
1101 /* Kick the execute command */
1102 cmd->cmd = 0;
1103 cmd->src = paddr(&data->sfexec);
1104 cmd->dst = NAND_SFLASHC_EXEC_CMD;
1105 cmd->len = 4;
1106 cmd++;
1107
1108 /* Block on data ready, and read the status register */
1109 cmd->cmd = SRC_CRCI_NAND_DATA;
1110 cmd->src = NAND_SFLASHC_STATUS;
1111 cmd->dst = paddr(&data->sfstat[2]);
1112 cmd->len = 4;
1113 cmd++;
1114
1115 /* Read the GENP3 register */
1116 cmd->cmd = 0;
1117 cmd->src = NAND_GENP_REG3;
1118 cmd->dst = paddr(&data->data3);
1119 cmd->len = 4;
1120 cmd++;
1121
1122 /* Read the DEVCMD4 register */
1123 cmd->cmd = 0;
1124 cmd->src = NAND_DEV_CMD4;
1125 cmd->dst = paddr(&data->data4);
1126 cmd->len = 4;
1127 cmd++;
1128
1129 /***************************************************************/
1130 /* Restore the necessary registers to proper values */
1131 /***************************************************************/
1132
1133 /* Block on cmd ready and write CMD register */
1134 cmd->cmd = DST_CRCI_NAND_CMD;
1135 cmd->src = paddr(&data->sfcmd[3]);
1136 cmd->dst = NAND_SFLASHC_CMD;
1137 cmd->len = 4;
1138 cmd++;
1139
1140 /* Kick the execute command */
1141 cmd->cmd = 0;
1142 cmd->src = paddr(&data->sfexec);
1143 cmd->dst = NAND_SFLASHC_EXEC_CMD;
1144 cmd->len = 4;
1145 cmd++;
1146
1147 /* Block on data ready, and read the status register */
1148 cmd->cmd = SRC_CRCI_NAND_DATA | CMD_OCU | CMD_LC;
1149 cmd->src = NAND_SFLASHC_STATUS;
1150 cmd->dst = paddr(&data->sfstat[3]);
1151 cmd->len = 4;
1152 cmd++;
1153
1154 ptr[0] = (paddr(cmdlist) >> 3) | CMD_PTR_LP;
1155
1156 dmov_exec_cmdptr(DMOV_NAND_CHAN, ptr);
1157
1158 ecc_status = (data->data3 >> 16) & 0x0000FFFF;
1159 interrupt_status = (data->data4 >> 0) & 0x0000FFFF;
1160 controller_status = (data->data4 >> 16) & 0x0000FFFF;
1161
1162#if VERBOSE
1163 dprintf(INFO, "\n%s: sflash status %x %x %x %x\n", __func__,
1164 data->sfstat[0],
1165 data->sfstat[1],
1166 data->sfstat[2],
1167 data->sfstat[3]);
1168
1169 dprintf(INFO, "%s: controller_status = %x\n", __func__,
1170 controller_status);
1171 dprintf(INFO, "%s: interrupt_status = %x\n", __func__,
1172 interrupt_status);
1173 dprintf(INFO, "%s: ecc_status = %x\n", __func__,
1174 ecc_status);
1175#endif
1176 /* Check for errors, protection violations etc */
1177 if ((controller_status != 0)
1178 || (data->sfstat[0] & 0x110)
1179 || (data->sfstat[1] & 0x110)
1180 || (data->sfstat[2] & 0x110)
1181 || (data->sfstat[3] & 0x110)) {
1182 dprintf(CRITICAL, "%s: ECC/MPU/OP error\n", __func__);
1183 return -1;
1184 }
1185
1186
1187#if VERBOSE
1188 dprintf(INFO, "status: %x\n", data[5]);
1189#endif
1190
1191 return 0;
1192}
1193
1194
1195struct data_onenand_read {
1196 unsigned sfbcfg;
1197 unsigned sfcmd[9];
1198 unsigned sfexec;
1199 unsigned sfstat[9];
1200 unsigned addr0;
1201 unsigned addr1;
1202 unsigned addr2;
1203 unsigned addr3;
1204 unsigned addr4;
1205 unsigned addr5;
1206 unsigned addr6;
1207 unsigned data0;
1208 unsigned data1;
1209 unsigned data2;
1210 unsigned data3;
1211 unsigned data4;
1212 unsigned data5;
1213 unsigned data6;
1214 unsigned macro[5];
1215};
1216
1217
1218static int _flash_onenand_read_page(dmov_s *cmdlist, unsigned *ptrlist,
Shashank Mittalad3d05c2009-11-19 15:53:57 -08001219 unsigned page, void *_addr, void *_spareaddr,
1220 unsigned raw_mode)
Shashank Mittalc20b5a12009-11-18 19:35:30 -08001221{
1222 dmov_s *cmd = cmdlist;
1223 unsigned *ptr = ptrlist;
1224 struct data_onenand_read *data = (void*) (ptrlist + 4);
1225 unsigned addr = (unsigned) _addr;
1226 unsigned curr_addr = (unsigned) _addr;
1227 unsigned spareaddr = (unsigned) _spareaddr;
1228 unsigned i;
Shashank Mittaldcc2e352009-11-19 19:11:16 -08001229 unsigned erasesize = (flash_pagesize<<6);
1230 unsigned writesize = flash_pagesize;
Shashank Mittalc20b5a12009-11-18 19:35:30 -08001231
1232 unsigned onenand_startaddr1 = DEVICE_FLASHCORE_0 |
Shashank Mittaldcc2e352009-11-19 19:11:16 -08001233 ((unsigned)(page * flash_pagesize) / erasesize);
1234 unsigned onenand_startaddr8 = (((unsigned)(page * flash_pagesize) &
Shashank Mittalc20b5a12009-11-18 19:35:30 -08001235 (erasesize - 1)) / writesize) << 2;
1236 unsigned onenand_startaddr2 = DEVICE_BUFFERRAM_0 << 15;
1237 unsigned onenand_startbuffer = DATARAM0_0 << 8;
Shashank Mittalad3d05c2009-11-19 15:53:57 -08001238 unsigned onenand_sysconfig1 = (raw_mode == 1) ? ONENAND_SYSCFG1_ECCDIS :\
1239 ONENAND_SYSCFG1_ECCENA;
Shashank Mittalc20b5a12009-11-18 19:35:30 -08001240
1241 unsigned controller_status;
1242 unsigned interrupt_status;
1243 unsigned ecc_status;
Shashank Mittalad3d05c2009-11-19 15:53:57 -08001244 if (raw_mode != 1)
1245 {
1246 int isbad = 0;
1247 isbad = flash_onenand_block_isbad(cmdlist, ptrlist, page);
1248 if (isbad)
1249 return -2;
1250 }
Shashank Mittalc20b5a12009-11-18 19:35:30 -08001251
1252 //static int oobfree_offset[8] = {2, 14, 18, 30, 34, 46, 50, 62};
1253 //static int oobfree_length[8] = {3, 2, 3, 2, 3, 2, 3, 2};
1254
1255 data->sfbcfg = SFLASH_BCFG;
1256 data->sfcmd[0] = SFLASH_PREPCMD(7, 0, 0,
1257 NAND_SFCMD_CMDXS,
1258 NAND_SFCMD_ASYNC,
1259 NAND_SFCMD_REGWR);
1260 data->sfcmd[1] = SFLASH_PREPCMD(0, 0, 32,
1261 NAND_SFCMD_CMDXS,
1262 NAND_SFCMD_ASYNC,
1263 NAND_SFCMD_INTHI);
1264 data->sfcmd[2] = SFLASH_PREPCMD(3, 7, 0,
1265 NAND_SFCMD_DATXS,
1266 NAND_SFCMD_ASYNC,
1267 NAND_SFCMD_REGRD);
1268 data->sfcmd[3] = SFLASH_PREPCMD(256, 0, 0,
1269 NAND_SFCMD_DATXS,
1270 NAND_SFCMD_ASYNC,
1271 NAND_SFCMD_DATRD);
1272 data->sfcmd[4] = SFLASH_PREPCMD(256, 0, 0,
1273 NAND_SFCMD_DATXS,
1274 NAND_SFCMD_ASYNC,
1275 NAND_SFCMD_DATRD);
1276 data->sfcmd[5] = SFLASH_PREPCMD(256, 0, 0,
1277 NAND_SFCMD_DATXS,
1278 NAND_SFCMD_ASYNC,
1279 NAND_SFCMD_DATRD);
1280 data->sfcmd[6] = SFLASH_PREPCMD(256, 0, 0,
1281 NAND_SFCMD_DATXS,
1282 NAND_SFCMD_ASYNC,
1283 NAND_SFCMD_DATRD);
1284 data->sfcmd[7] = SFLASH_PREPCMD(32, 0, 0,
1285 NAND_SFCMD_DATXS,
1286 NAND_SFCMD_ASYNC,
1287 NAND_SFCMD_DATRD);
1288 data->sfcmd[8] = SFLASH_PREPCMD(4, 10, 0,
1289 NAND_SFCMD_CMDXS,
1290 NAND_SFCMD_ASYNC,
1291 NAND_SFCMD_REGWR);
1292 data->sfexec = 1;
1293 data->sfstat[0] = CLEAN_DATA_32;
1294 data->sfstat[1] = CLEAN_DATA_32;
1295 data->sfstat[2] = CLEAN_DATA_32;
1296 data->sfstat[3] = CLEAN_DATA_32;
1297 data->sfstat[4] = CLEAN_DATA_32;
1298 data->sfstat[5] = CLEAN_DATA_32;
1299 data->sfstat[6] = CLEAN_DATA_32;
1300 data->sfstat[7] = CLEAN_DATA_32;
1301 data->sfstat[8] = CLEAN_DATA_32;
1302
1303 data->addr0 = (ONENAND_INTERRUPT_STATUS << 16) |
1304 (ONENAND_SYSTEM_CONFIG_1);
1305 data->addr1 = (ONENAND_START_ADDRESS_8 << 16) |
1306 (ONENAND_START_ADDRESS_1);
1307 data->addr2 = (ONENAND_START_BUFFER << 16) |
1308 (ONENAND_START_ADDRESS_2);
1309 data->addr3 = (ONENAND_ECC_STATUS << 16) |
1310 (ONENAND_COMMAND);
1311 data->addr4 = (ONENAND_CONTROLLER_STATUS << 16) |
1312 (ONENAND_INTERRUPT_STATUS);
1313 data->addr5 = (ONENAND_INTERRUPT_STATUS << 16) |
1314 (ONENAND_SYSTEM_CONFIG_1);
1315 data->addr6 = (ONENAND_START_ADDRESS_3 << 16) |
1316 (ONENAND_START_ADDRESS_1);
1317 data->data0 = (ONENAND_CLRINTR << 16) |
1318 (onenand_sysconfig1);
1319 data->data1 = (onenand_startaddr8 << 16) |
1320 (onenand_startaddr1);
1321 data->data2 = (onenand_startbuffer << 16) |
1322 (onenand_startaddr2);
1323 data->data3 = (CLEAN_DATA_16 << 16) |
1324 (ONENAND_CMDLOADSPARE);
1325 data->data4 = (CLEAN_DATA_16 << 16) |
1326 (CLEAN_DATA_16);
1327 data->data5 = (ONENAND_CLRINTR << 16) |
1328 (ONENAND_SYSCFG1_ECCENA);
1329 data->data6 = (ONENAND_STARTADDR3_RES << 16) |
1330 (ONENAND_STARTADDR1_RES);
1331 data->macro[0] = 0x0200;
1332 data->macro[1] = 0x0300;
1333 data->macro[2] = 0x0400;
1334 data->macro[3] = 0x0500;
1335 data->macro[4] = 0x8010;
1336
1337 /*************************************************************/
1338 /* Write necessary address registers in the onenand device */
1339 /*************************************************************/
1340
1341 /* Enable and configure the SFlash controller */
1342 cmd->cmd = 0 | CMD_OCB;
1343 cmd->src = paddr(&data->sfbcfg);
1344 cmd->dst = NAND_SFLASHC_BURST_CFG;
1345 cmd->len = 4;
1346 cmd++;
1347
1348 /* Block on cmd ready and write CMD register */
1349 cmd->cmd = DST_CRCI_NAND_CMD;
1350 cmd->src = paddr(&data->sfcmd[0]);
1351 cmd->dst = NAND_SFLASHC_CMD;
1352 cmd->len = 4;
1353 cmd++;
1354
1355 /* Write the ADDR0 and ADDR1 registers */
1356 cmd->cmd = 0;
1357 cmd->src = paddr(&data->addr0);
1358 cmd->dst = NAND_ADDR0;
1359 cmd->len = 8;
1360 cmd++;
1361
1362 /* Write the ADDR2 ADDR3 ADDR4 ADDR5 registers */
1363 cmd->cmd = 0;
1364 cmd->src = paddr(&data->addr2);
1365 cmd->dst = NAND_ADDR2;
1366 cmd->len = 16;
1367 cmd++;
1368
1369 /* Write the ADDR6 registers */
1370 cmd->cmd = 0;
1371 cmd->src = paddr(&data->addr6);
1372 cmd->dst = NAND_ADDR6;
1373 cmd->len = 4;
1374 cmd++;
1375
1376 /* Write the GENP0, GENP1, GENP2, GENP3 registers */
1377 cmd->cmd = 0;
1378 cmd->src = paddr(&data->data0);
1379 cmd->dst = NAND_GENP_REG0;
1380 cmd->len = 16;
1381 cmd++;
1382
1383 /* Write the FLASH_DEV_CMD4,5,6 registers */
1384 cmd->cmd = 0;
1385 cmd->src = paddr(&data->data4);
1386 cmd->dst = NAND_DEV_CMD4;
1387 cmd->len = 12;
1388 cmd++;
1389
1390 /* Kick the execute command */
1391 cmd->cmd = 0;
1392 cmd->src = paddr(&data->sfexec);
1393 cmd->dst = NAND_SFLASHC_EXEC_CMD;
1394 cmd->len = 4;
1395 cmd++;
1396
1397 /* Block on data ready, and read the status register */
1398 cmd->cmd = SRC_CRCI_NAND_DATA;
1399 cmd->src = NAND_SFLASHC_STATUS;
1400 cmd->dst = paddr(&data->sfstat[0]);
1401 cmd->len = 4;
1402 cmd++;
1403
1404 /*************************************************************/
1405 /* Wait for the interrupt from the Onenand device controller */
1406 /*************************************************************/
1407
1408 /* Block on cmd ready and write CMD register */
1409 cmd->cmd = DST_CRCI_NAND_CMD;
1410 cmd->src = paddr(&data->sfcmd[1]);
1411 cmd->dst = NAND_SFLASHC_CMD;
1412 cmd->len = 4;
1413 cmd++;
1414
1415 /* Kick the execute command */
1416 cmd->cmd = 0;
1417 cmd->src = paddr(&data->sfexec);
1418 cmd->dst = NAND_SFLASHC_EXEC_CMD;
1419 cmd->len = 4;
1420 cmd++;
1421
1422 /* Block on data ready, and read the status register */
1423 cmd->cmd = SRC_CRCI_NAND_DATA;
1424 cmd->src = NAND_SFLASHC_STATUS;
1425 cmd->dst = paddr(&data->sfstat[1]);
1426 cmd->len = 4;
1427 cmd++;
1428
1429
1430 /*************************************************************/
1431 /* Read necessary status registers from the onenand device */
1432 /*************************************************************/
1433
1434 /* Block on cmd ready and write CMD register */
1435 cmd->cmd = DST_CRCI_NAND_CMD;
1436 cmd->src = paddr(&data->sfcmd[2]);
1437 cmd->dst = NAND_SFLASHC_CMD;
1438 cmd->len = 4;
1439 cmd++;
1440
1441 /* Kick the execute command */
1442 cmd->cmd = 0;
1443 cmd->src = paddr(&data->sfexec);
1444 cmd->dst = NAND_SFLASHC_EXEC_CMD;
1445 cmd->len = 4;
1446 cmd++;
1447
1448 /* Block on data ready, and read the status register */
1449 cmd->cmd = SRC_CRCI_NAND_DATA;
1450 cmd->src = NAND_SFLASHC_STATUS;
1451 cmd->dst = paddr(&data->sfstat[2]);
1452 cmd->len = 4;
1453 cmd++;
1454
1455 /* Read the GENP3 register */
1456 cmd->cmd = 0;
1457 cmd->src = NAND_GENP_REG3;
1458 cmd->dst = paddr(&data->data3);
1459 cmd->len = 4;
1460 cmd++;
1461
1462 /* Read the DEVCMD4 register */
1463 cmd->cmd = 0;
1464 cmd->src = NAND_DEV_CMD4;
1465 cmd->dst = paddr(&data->data4);
1466 cmd->len = 4;
1467 cmd++;
1468
1469
1470 /*************************************************************/
1471 /* Read the data ram area from the onenand buffer ram */
1472 /*************************************************************/
1473
1474 if (addr) {
1475
1476 data->data3 = (CLEAN_DATA_16 << 16) |
1477 (ONENAND_CMDLOAD);
1478
1479 for (i = 0; i < 4; i++) {
1480
1481 /* Block on cmd ready and write CMD register */
1482 cmd->cmd = DST_CRCI_NAND_CMD;
1483 cmd->src = paddr(&data->sfcmd[3+i]);
1484 cmd->dst = NAND_SFLASHC_CMD;
1485 cmd->len = 4;
1486 cmd++;
1487
1488 /* Write the MACRO1 register */
1489 cmd->cmd = 0;
1490 cmd->src = paddr(&data->macro[i]);
1491 cmd->dst = NAND_MACRO1_REG;
1492 cmd->len = 4;
1493 cmd++;
1494
1495 /* Kick the execute command */
1496 cmd->cmd = 0;
1497 cmd->src = paddr(&data->sfexec);
1498 cmd->dst = NAND_SFLASHC_EXEC_CMD;
1499 cmd->len = 4;
1500 cmd++;
1501
1502 /* Block on data rdy, & read status register */
1503 cmd->cmd = SRC_CRCI_NAND_DATA;
1504 cmd->src = NAND_SFLASHC_STATUS;
1505 cmd->dst = paddr(&data->sfstat[3+i]);
1506 cmd->len = 4;
1507 cmd++;
1508
1509 /* Transfer nand ctlr buf contents to usr buf */
1510 cmd->cmd = 0;
1511 cmd->src = NAND_FLASH_BUFFER;
1512 cmd->dst = curr_addr;
1513 cmd->len = 512;
1514 curr_addr += 512;
1515 cmd++;
1516 }
1517 }
1518
Shashank Mittalad3d05c2009-11-19 15:53:57 -08001519 /* Read oob bytes in Raw Mode */
1520 if (raw_mode == 1)
1521 {
1522 /* Block on cmd ready and write CMD register */
1523 cmd->cmd = DST_CRCI_NAND_CMD;
1524 cmd->src = paddr(&data->sfcmd[7]);
1525 cmd->dst = NAND_SFLASHC_CMD;
1526 cmd->len = 4;
1527 cmd++;
1528
1529 /* Write the MACRO1 register */
1530 cmd->cmd = 0;
1531 cmd->src = paddr(&data->macro[4]);
1532 cmd->dst = NAND_MACRO1_REG;
1533 cmd->len = 4;
1534 cmd++;
1535
1536 /* Kick the execute command */
1537 cmd->cmd = 0;
1538 cmd->src = paddr(&data->sfexec);
1539 cmd->dst = NAND_SFLASHC_EXEC_CMD;
1540 cmd->len = 4;
1541 cmd++;
1542
1543 /* Block on data rdy, & read status register */
1544 cmd->cmd = SRC_CRCI_NAND_DATA;
1545 cmd->src = NAND_SFLASHC_STATUS;
1546 cmd->dst = paddr(&data->sfstat[7]);
1547 cmd->len = 4;
1548 cmd++;
1549
1550 /* Transfer nand ctlr buf contents to usr buf */
1551 cmd->cmd = 0;
1552 cmd->src = NAND_FLASH_BUFFER;
1553 cmd->dst = curr_addr;
1554 cmd->len = 64;
1555 curr_addr += 64;
1556 cmd++;
1557 }
1558
Shashank Mittalc20b5a12009-11-18 19:35:30 -08001559 /*************************************************************/
1560 /* Restore the necessary registers to proper values */
1561 /*************************************************************/
1562
1563 /* Block on cmd ready and write CMD register */
1564 cmd->cmd = DST_CRCI_NAND_CMD;
1565 cmd->src = paddr(&data->sfcmd[8]);
1566 cmd->dst = NAND_SFLASHC_CMD;
1567 cmd->len = 4;
1568 cmd++;
1569
1570 /* Kick the execute command */
1571 cmd->cmd = 0;
1572 cmd->src = paddr(&data->sfexec);
1573 cmd->dst = NAND_SFLASHC_EXEC_CMD;
1574 cmd->len = 4;
1575 cmd++;
1576
1577 /* Block on data ready, and read the status register */
1578 cmd->cmd = SRC_CRCI_NAND_DATA | CMD_OCU | CMD_LC;
1579 cmd->src = NAND_SFLASHC_STATUS;
1580 cmd->dst = paddr(&data->sfstat[8]);
1581 cmd->len = 4;
1582 cmd++;
1583
1584
1585 ptr[0] = (paddr(cmdlist) >> 3) | CMD_PTR_LP;
1586
1587 dmov_exec_cmdptr(DMOV_NAND_CHAN, ptr);
1588
1589
1590 ecc_status = (data->data3 >> 16) &
1591 0x0000FFFF;
1592 interrupt_status = (data->data4 >> 0) &
1593 0x0000FFFF;
1594 controller_status = (data->data4 >> 16) &
1595 0x0000FFFF;
1596
1597#if VERBOSE
1598 dprintf(INFO, "\n%s: sflash status %x %x %x %x %x %x %x"
1599 "%x %x\n", __func__,
1600 data->sfstat[0],
1601 data->sfstat[1],
1602 data->sfstat[2],
1603 data->sfstat[3],
1604 data->sfstat[4],
1605 data->sfstat[5],
1606 data->sfstat[6],
1607 data->sfstat[7]);
1608
1609 dprintf(INFO, "%s: controller_status = %x\n", __func__,
1610 controller_status);
1611 dprintf(INFO, "%s: interrupt_status = %x\n", __func__,
1612 interrupt_status);
1613 dprintf(INFO, "%s: ecc_status = %x\n", __func__,
1614 ecc_status);
1615#endif
1616 /* Check for errors, protection violations etc */
1617 if ((controller_status != 0)
1618 || (data->sfstat[0] & 0x110)
1619 || (data->sfstat[1] & 0x110)
1620 || (data->sfstat[2] & 0x110)
1621 || ((data->sfstat[3] & 0x110) &&
1622 (addr))
1623 || ((data->sfstat[4] & 0x110) &&
1624 (addr))
1625 || ((data->sfstat[5] & 0x110) &&
1626 (addr))
1627 || ((data->sfstat[6] & 0x110) &&
1628 (addr))) {
1629 dprintf(INFO, "%s: ECC/MPU/OP error\n", __func__);
1630 return -1;
1631 }
1632
1633#if VERBOSE
1634 dprintf(INFO, "read page %d: status: %x %x %x %x\n",
1635 page, data[5], data[6], data[7], data[8]);
1636 for(n = 0; n < 4; n++) {
1637 ptr = (unsigned*)(addr + 512 * n);
1638 dprintf(INFO, "data%d: %x %x %x %x\n", n, ptr[0], ptr[1], ptr[2], ptr[3]);
1639 ptr = (unsigned*)(spareaddr + 16 * n);
1640 dprintf(INFO, "spare data%d %x %x %x %x\n", n, ptr[0], ptr[1], ptr[2], ptr[3]);
1641 }
1642#endif
1643
1644 return 0;
1645}
1646
1647
1648struct data_onenand_write {
1649 unsigned sfbcfg;
1650 unsigned sfcmd[9];
1651 unsigned sfexec;
1652 unsigned sfstat[9];
1653 unsigned addr0;
1654 unsigned addr1;
1655 unsigned addr2;
1656 unsigned addr3;
1657 unsigned addr4;
1658 unsigned addr5;
1659 unsigned addr6;
1660 unsigned data0;
1661 unsigned data1;
1662 unsigned data2;
1663 unsigned data3;
1664 unsigned data4;
1665 unsigned data5;
1666 unsigned data6;
1667 unsigned macro[5];
1668};
1669
1670static int _flash_onenand_write_page(dmov_s *cmdlist, unsigned *ptrlist,
1671 unsigned page, const void *_addr,
Shashank Mittald0c836d2009-11-20 10:31:18 -08001672 const void *_spareaddr, unsigned raw_mode)
Shashank Mittalc20b5a12009-11-18 19:35:30 -08001673{
1674 dmov_s *cmd = cmdlist;
1675 unsigned *ptr = ptrlist;
1676 struct data_onenand_write *data = (void*) (ptrlist + 4);
1677 unsigned addr = (unsigned) _addr;
1678 unsigned addr_curr = (unsigned) _addr;
1679 char * spareaddr = (char *) _spareaddr;
1680 unsigned i, j, k;
1681
Shashank Mittaldcc2e352009-11-19 19:11:16 -08001682 unsigned erasesize = (flash_pagesize<<6);
1683 unsigned writesize = flash_pagesize;
Shashank Mittalc20b5a12009-11-18 19:35:30 -08001684
Shashank Mittaldcc2e352009-11-19 19:11:16 -08001685 unsigned onenand_startaddr1 = (page * flash_pagesize) / erasesize;
1686 unsigned onenand_startaddr8 = (((unsigned)(page * flash_pagesize) &
Shashank Mittalc20b5a12009-11-18 19:35:30 -08001687 (erasesize-1)) / writesize) << 2;
1688 unsigned onenand_startaddr2 = DEVICE_BUFFERRAM_0 << 15;
1689 unsigned onenand_startbuffer = DATARAM0_0 << 8;
Shashank Mittald0c836d2009-11-20 10:31:18 -08001690 unsigned onenand_sysconfig1 = (raw_mode == 1) ? ONENAND_SYSCFG1_ECCDIS :\
1691 ONENAND_SYSCFG1_ECCENA;
Shashank Mittalc20b5a12009-11-18 19:35:30 -08001692
1693 unsigned controller_status;
1694 unsigned interrupt_status;
1695 unsigned ecc_status;
1696
1697 char flash_oob[64];
1698
1699 unsigned oobfree_offset[8] = {2, 14, 18, 30, 34, 46, 50, 62};
1700 unsigned oobfree_length[8] = {3, 2, 3, 2, 3, 2, 3, 2};
1701
1702 for (i = 0; i < 64; i++)
1703 flash_oob[i] = 0xFF;
1704
1705 data->sfbcfg = SFLASH_BCFG;
1706 data->sfcmd[0] = SFLASH_PREPCMD(256, 0, 0,
1707 NAND_SFCMD_CMDXS,
1708 NAND_SFCMD_ASYNC,
1709 NAND_SFCMD_DATWR);
1710 data->sfcmd[1] = SFLASH_PREPCMD(256, 0, 0,
1711 NAND_SFCMD_CMDXS,
1712 NAND_SFCMD_ASYNC,
1713 NAND_SFCMD_DATWR);
1714 data->sfcmd[2] = SFLASH_PREPCMD(256, 0, 0,
1715 NAND_SFCMD_CMDXS,
1716 NAND_SFCMD_ASYNC,
1717 NAND_SFCMD_DATWR);
1718 data->sfcmd[3] = SFLASH_PREPCMD(256, 0, 0,
1719 NAND_SFCMD_CMDXS,
1720 NAND_SFCMD_ASYNC,
1721 NAND_SFCMD_DATWR);
1722 data->sfcmd[4] = SFLASH_PREPCMD(32, 0, 0,
1723 NAND_SFCMD_CMDXS,
1724 NAND_SFCMD_ASYNC,
1725 NAND_SFCMD_DATWR);
1726 data->sfcmd[5] = SFLASH_PREPCMD(7, 0, 0,
1727 NAND_SFCMD_CMDXS,
1728 NAND_SFCMD_ASYNC,
1729 NAND_SFCMD_REGWR);
1730 data->sfcmd[6] = SFLASH_PREPCMD(0, 0, 32,
1731 NAND_SFCMD_CMDXS,
1732 NAND_SFCMD_ASYNC,
1733 NAND_SFCMD_INTHI);
1734 data->sfcmd[7] = SFLASH_PREPCMD(3, 7, 0,
1735 NAND_SFCMD_DATXS,
1736 NAND_SFCMD_ASYNC,
1737 NAND_SFCMD_REGRD);
1738 data->sfcmd[8] = SFLASH_PREPCMD(4, 10, 0,
1739 NAND_SFCMD_CMDXS,
1740 NAND_SFCMD_ASYNC,
1741 NAND_SFCMD_REGWR);
1742 data->sfexec = 1;
1743
1744 data->sfstat[0] = CLEAN_DATA_32;
1745 data->sfstat[1] = CLEAN_DATA_32;
1746 data->sfstat[2] = CLEAN_DATA_32;
1747 data->sfstat[3] = CLEAN_DATA_32;
1748 data->sfstat[4] = CLEAN_DATA_32;
1749 data->sfstat[5] = CLEAN_DATA_32;
1750 data->sfstat[6] = CLEAN_DATA_32;
1751 data->sfstat[7] = CLEAN_DATA_32;
1752 data->sfstat[8] = CLEAN_DATA_32;
1753 data->addr0 = (ONENAND_INTERRUPT_STATUS << 16) |
1754 (ONENAND_SYSTEM_CONFIG_1);
1755 data->addr1 = (ONENAND_START_ADDRESS_8 << 16) |
1756 (ONENAND_START_ADDRESS_1);
1757 data->addr2 = (ONENAND_START_BUFFER << 16) |
1758 (ONENAND_START_ADDRESS_2);
1759 data->addr3 = (ONENAND_ECC_STATUS << 16) |
1760 (ONENAND_COMMAND);
1761 data->addr4 = (ONENAND_CONTROLLER_STATUS << 16) |
1762 (ONENAND_INTERRUPT_STATUS);
1763 data->addr5 = (ONENAND_INTERRUPT_STATUS << 16) |
1764 (ONENAND_SYSTEM_CONFIG_1);
1765 data->addr6 = (ONENAND_START_ADDRESS_3 << 16) |
1766 (ONENAND_START_ADDRESS_1);
1767 data->data0 = (ONENAND_CLRINTR << 16) |
1768 (onenand_sysconfig1);
1769 data->data1 = (onenand_startaddr8 << 16) |
1770 (onenand_startaddr1);
1771 data->data2 = (onenand_startbuffer << 16) |
1772 (onenand_startaddr2);
1773 data->data3 = (CLEAN_DATA_16 << 16) |
1774 (ONENAND_CMDPROGSPARE);
1775 data->data3 = (CLEAN_DATA_16 << 16) |
1776 (ONENAND_CMDPROGSPARE);
1777 data->data4 = (CLEAN_DATA_16 << 16) |
1778 (CLEAN_DATA_16);
1779 data->data5 = (ONENAND_CLRINTR << 16) |
1780 (ONENAND_SYSCFG1_ECCENA);
1781 data->data6 = (ONENAND_STARTADDR3_RES << 16) |
1782 (ONENAND_STARTADDR1_RES);
1783 data->macro[0] = 0x0200;
1784 data->macro[1] = 0x0300;
1785 data->macro[2] = 0x0400;
1786 data->macro[3] = 0x0500;
1787 data->macro[4] = 0x8010;
1788
1789
1790 /*************************************************************/
1791 /* Write the data ram area in the onenand buffer ram */
1792 /*************************************************************/
1793
1794 /* Enable and configure the SFlash controller */
1795 cmd->cmd = 0 | CMD_OCB;
1796 cmd->src = paddr(&data->sfbcfg);
1797 cmd->dst = NAND_SFLASHC_BURST_CFG;
1798 cmd->len = 4;
1799 cmd++;
1800
1801 if (addr) {
1802 data->data3 = (CLEAN_DATA_16 << 16) |
1803 (ONENAND_CMDPROG);
1804
1805 for (i = 0; i < 4; i++) {
1806
1807 /* Block on cmd ready and write CMD register */
1808 cmd->cmd = DST_CRCI_NAND_CMD;
1809 cmd->src = paddr(&data->sfcmd[i]);
1810 cmd->dst = NAND_SFLASHC_CMD;
1811 cmd->len = 4;
1812 cmd++;
1813
1814 /* Trnsfr usr buf contents to nand ctlr buf */
1815 cmd->cmd = 0;
1816 cmd->src = paddr(addr_curr);
1817 cmd->dst = NAND_FLASH_BUFFER;
1818 cmd->len = 512;
Shashank Mittald0c836d2009-11-20 10:31:18 -08001819 if(!raw_mode)
1820 addr_curr += 512;
Shashank Mittalc20b5a12009-11-18 19:35:30 -08001821 cmd++;
1822
1823 /* Write the MACRO1 register */
1824 cmd->cmd = 0;
1825 cmd->src = paddr(&data->macro[i]);
1826 cmd->dst = NAND_MACRO1_REG;
1827 cmd->len = 4;
1828 cmd++;
1829
1830 /* Kick the execute command */
1831 cmd->cmd = 0;
1832 cmd->src = paddr(&data->sfexec);
1833 cmd->dst = NAND_SFLASHC_EXEC_CMD;
1834 cmd->len = 4;
1835 cmd++;
1836
1837 /* Block on data rdy, & read status register */
1838 cmd->cmd = SRC_CRCI_NAND_DATA;
1839 cmd->src = NAND_SFLASHC_STATUS;
1840 cmd->dst = paddr(&data->sfstat[i]);
1841 cmd->len = 4;
1842 cmd++;
1843
1844 }
1845 }
1846
1847 /* Block on cmd ready and write CMD register */
1848 cmd->cmd = DST_CRCI_NAND_CMD;
1849 cmd->src = paddr(&data->sfcmd[4]);
1850 cmd->dst = NAND_SFLASHC_CMD;
1851 cmd->len = 4;
1852 cmd++;
1853
1854 if (spareaddr)
1855 {
1856 // Auto mode
1857 for (i = 0, k = 0; i < 8; i++) {
1858 for (j = 0; j < oobfree_length[i]; j++) {
1859 flash_oob[j+oobfree_offset[i]] = spareaddr[k];
1860 k++;
1861 }
1862 }
1863
1864 cmd->cmd = 0;
1865 cmd->src = paddr(&flash_oob);
1866 cmd->dst = NAND_FLASH_BUFFER;
1867 cmd->len = 64;
1868 cmd++;
1869 }
1870
Shashank Mittald0c836d2009-11-20 10:31:18 -08001871 if (raw_mode){
1872 cmd->cmd = 0;
1873 cmd->src = paddr(addr_curr);
1874 cmd->dst = NAND_FLASH_BUFFER;
1875 cmd->len = 64;
1876 cmd++;
1877 }
1878
Shashank Mittalc20b5a12009-11-18 19:35:30 -08001879 /* Write the MACRO1 register */
1880 cmd->cmd = 0;
1881 cmd->src = paddr(&data->macro[4]);
1882 cmd->dst = NAND_MACRO1_REG;
1883 cmd->len = 4;
1884 cmd++;
1885
1886 /* Kick the execute command */
1887 cmd->cmd = 0;
1888 cmd->src = paddr(&data->sfexec);
1889 cmd->dst = NAND_SFLASHC_EXEC_CMD;
1890 cmd->len = 4;
1891 cmd++;
1892
1893 /* Block on data ready, and read the status register */
1894 cmd->cmd = SRC_CRCI_NAND_DATA;
1895 cmd->src = NAND_SFLASHC_STATUS;
1896 cmd->dst = paddr(&data->sfstat[4]);
1897 cmd->len = 4;
1898 cmd++;
1899
1900 /*************************************************************/
1901 /* Write necessary address registers in the onenand device */
1902 /*************************************************************/
1903
1904 /* Block on cmd ready and write CMD register */
1905 cmd->cmd = DST_CRCI_NAND_CMD;
1906 cmd->src = paddr(&data->sfcmd[5]);
1907 cmd->dst = NAND_SFLASHC_CMD;
1908 cmd->len = 4;
1909 cmd++;
1910
1911 /* Write the ADDR0 and ADDR1 registers */
1912 cmd->cmd = 0;
1913 cmd->src = paddr(&data->addr0);
1914 cmd->dst = NAND_ADDR0;
1915 cmd->len = 8;
1916 cmd++;
1917
1918 /* Write the ADDR2 ADDR3 ADDR4 ADDR5 registers */
1919 cmd->cmd = 0;
1920 cmd->src = paddr(&data->addr2);
1921 cmd->dst = NAND_ADDR2;
1922 cmd->len = 16;
1923 cmd++;
1924
1925 /* Write the ADDR6 registers */
1926 cmd->cmd = 0;
1927 cmd->src = paddr(&data->addr6);
1928 cmd->dst = NAND_ADDR6;
1929 cmd->len = 4;
1930 cmd++;
1931
1932 /* Write the GENP0, GENP1, GENP2, GENP3 registers */
1933 cmd->cmd = 0;
1934 cmd->src = paddr(&data->data0);
1935 cmd->dst = NAND_GENP_REG0;
1936 cmd->len = 16;
1937 cmd++;
1938
1939 /* Write the FLASH_DEV_CMD4,5,6 registers */
1940 cmd->cmd = 0;
1941 cmd->src = paddr(&data->data4);
1942 cmd->dst = NAND_DEV_CMD4;
1943 cmd->len = 12;
1944 cmd++;
1945
1946 /* Kick the execute command */
1947 cmd->cmd = 0;
1948 cmd->src = paddr(&data->sfexec);
1949 cmd->dst = NAND_SFLASHC_EXEC_CMD;
1950 cmd->len = 4;
1951 cmd++;
1952
1953 /* Block on data ready, and read the status register */
1954 cmd->cmd = SRC_CRCI_NAND_DATA;
1955 cmd->src = NAND_SFLASHC_STATUS;
1956 cmd->dst = paddr(&data->sfstat[5]);
1957 cmd->len = 4;
1958 cmd++;
1959
1960 /*************************************************************/
1961 /* Wait for the interrupt from the Onenand device controller */
1962 /*************************************************************/
1963
1964 /* Block on cmd ready and write CMD register */
1965 cmd->cmd = DST_CRCI_NAND_CMD;
1966 cmd->src = paddr(&data->sfcmd[6]);
1967 cmd->dst = NAND_SFLASHC_CMD;
1968 cmd->len = 4;
1969 cmd++;
1970
1971 /* Kick the execute command */
1972 cmd->cmd = 0;
1973 cmd->src = paddr(&data->sfexec);
1974 cmd->dst = NAND_SFLASHC_EXEC_CMD;
1975 cmd->len = 4;
1976 cmd++;
1977
1978 /* Block on data ready, and read the status register */
1979 cmd->cmd = SRC_CRCI_NAND_DATA;
1980 cmd->src = NAND_SFLASHC_STATUS;
1981 cmd->dst = paddr(&data->sfstat[6]);
1982 cmd->len = 4;
1983 cmd++;
1984
1985 /*************************************************************/
1986 /* Read necessary status registers from the onenand device */
1987 /*************************************************************/
1988
1989 /* Block on cmd ready and write CMD register */
1990 cmd->cmd = DST_CRCI_NAND_CMD;
1991 cmd->src = paddr(&data->sfcmd[7]);
1992 cmd->dst = NAND_SFLASHC_CMD;
1993 cmd->len = 4;
1994 cmd++;
1995
1996 /* Kick the execute command */
1997 cmd->cmd = 0;
1998 cmd->src = paddr(&data->sfexec);
1999 cmd->dst = NAND_SFLASHC_EXEC_CMD;
2000 cmd->len = 4;
2001 cmd++;
2002
2003 /* Block on data ready, and read the status register */
2004 cmd->cmd = SRC_CRCI_NAND_DATA;
2005 cmd->src = NAND_SFLASHC_STATUS;
2006 cmd->dst = paddr(&data->sfstat[7]);
2007 cmd->len = 4;
2008 cmd++;
2009
2010 /* Read the GENP3 register */
2011 cmd->cmd = 0;
2012 cmd->src = NAND_GENP_REG3;
2013 cmd->dst = paddr(&data->data3);
2014 cmd->len = 4;
2015 cmd++;
2016
2017 /* Read the DEVCMD4 register */
2018 cmd->cmd = 0;
2019 cmd->src = NAND_DEV_CMD4;
2020 cmd->dst = paddr(&data->data4);
2021 cmd->len = 4;
2022 cmd++;
2023
2024
2025 /*************************************************************/
2026 /* Restore the necessary registers to proper values */
2027 /*************************************************************/
2028
2029 /* Block on cmd ready and write CMD register */
2030 cmd->cmd = DST_CRCI_NAND_CMD;
2031 cmd->src = paddr(&data->sfcmd[8]);
2032 cmd->dst = NAND_SFLASHC_CMD;
2033 cmd->len = 4;
2034 cmd++;
2035
2036 /* Kick the execute command */
2037 cmd->cmd = 0;
2038 cmd->src = paddr(&data->sfexec);
2039 cmd->dst = NAND_SFLASHC_EXEC_CMD;
2040 cmd->len = 4;
2041 cmd++;
2042
2043 /* Block on data ready, and read the status register */
2044 cmd->cmd = SRC_CRCI_NAND_DATA | CMD_OCU | CMD_LC;
2045 cmd->src = NAND_SFLASHC_STATUS;
2046 cmd->dst = paddr(&data->sfstat[8]);
2047 cmd->len = 4;
2048 cmd++;
2049
2050
2051 ptr[0] = (paddr(cmdlist) >> 3) | CMD_PTR_LP;
2052
2053 dmov_exec_cmdptr(DMOV_NAND_CHAN, ptr);
2054
2055 ecc_status = (data->data3 >> 16) & 0x0000FFFF;
2056 interrupt_status = (data->data4 >> 0)&0x0000FFFF;
2057 controller_status = (data->data4 >> 16)&0x0000FFFF;
2058
2059#if VERBOSE
2060 dprintf(INFO, "\n%s: sflash status %x %x %x %x %x %x %x %x %x\n", __func__,
2061 data->sfstat[0],
2062 data->sfstat[1],
2063 data->sfstat[2],
2064 data->sfstat[3],
2065 data->sfstat[4],
2066 data->sfstat[5],
2067 data->sfstat[6],
2068 data->sfstat[7],
2069 data->sfstat[8]);
2070
2071 dprintf(INFO, "%s: controller_status = %x\n", __func__,
2072 controller_status);
2073 dprintf(INFO, "%s: interrupt_status = %x\n", __func__,
2074 interrupt_status);
2075 dprintf(INFO, "%s: ecc_status = %x\n", __func__,
2076 ecc_status);
2077#endif
2078 /* Check for errors, protection violations etc */
2079 if ((controller_status != 0)
2080 || (data->sfstat[5] & 0x110)
2081 || (data->sfstat[6] & 0x110)
2082 || (data->sfstat[7] & 0x110)
2083 || (data->sfstat[8] & 0x110)
2084 || ((data->sfstat[0] & 0x110) &&
2085 (addr))
2086 || ((data->sfstat[1] & 0x110) &&
2087 (addr))
2088 || ((data->sfstat[2] & 0x110) &&
2089 (addr))
2090 || ((data->sfstat[3] & 0x110) &&
2091 (addr))) {
2092 dprintf(CRITICAL, "%s: ECC/MPU/OP error\n", __func__);
2093 return -1;
2094 }
2095
2096
2097 return 0;
2098}
Shashank Mittald0c836d2009-11-20 10:31:18 -08002099
2100static int flash_onenand_mark_badblock(dmov_s *cmdlist, unsigned *ptrlist, unsigned page)
2101{
2102 memset(empty_buf,0,528);
2103 /* Going to first page of the block */
2104 if(page & 63)
2105 page = page - (page & 63);
2106 return _flash_onenand_write_page(cmdlist, ptrlist, page, empty_buf, 0, 1);
2107}
2108
2109static int flash_mark_badblock(dmov_s *cmdlist, unsigned *ptrlist, unsigned page)
2110{
2111 switch(flash_info.type) {
2112 case FLASH_8BIT_NAND_DEVICE:
2113 case FLASH_16BIT_NAND_DEVICE:
2114 return flash_nand_mark_badblock(cmdlist, ptrlist, page);
2115 case FLASH_ONENAND_DEVICE:
2116 return flash_onenand_mark_badblock(cmdlist, ptrlist, page);
2117 default:
2118 return -1;
2119 }
2120}
2121
2122
Shashank Mittalc20b5a12009-11-18 19:35:30 -08002123/* Wrapper functions */
2124static void flash_read_id(dmov_s *cmdlist, unsigned *ptrlist)
2125{
2126 int dev_found = 0;
2127 unsigned index;
2128
2129 // Try to read id
2130 flash_nand_read_id(cmdlist, ptrlist);
2131 // Check if we support the device
2132 for (index=1;
2133 index < (sizeof(supported_flash)/sizeof(struct flash_identification));
2134 index++)
2135 {
2136 if ((flash_info.id & supported_flash[index].mask) ==
2137 (supported_flash[index].flash_id &
2138 (supported_flash[index].mask))) {
2139 dev_found = 1;
2140 break;
2141 }
2142 }
2143
2144 if(!dev_found) {
2145 flash_onenand_read_id(cmdlist, ptrlist);
2146 for (index=1;
2147 index < (sizeof(supported_flash)/sizeof(struct flash_identification));
2148 index++)
2149 {
2150 if ((flash_info.id & supported_flash[index].mask) ==
2151 (supported_flash[index].flash_id &
2152 (supported_flash[index].mask))) {
2153 dev_found = 1;
2154 break;
2155 }
2156 }
2157 }
2158
2159
2160
2161 if(dev_found) {
2162 if (supported_flash[index].widebus)
2163 flash_info.type = FLASH_16BIT_NAND_DEVICE;
2164 else
2165 flash_info.type = FLASH_8BIT_NAND_DEVICE;
2166 if (supported_flash[index].onenand)
2167 flash_info.type = FLASH_ONENAND_DEVICE;
2168 flash_info.page_size = supported_flash[index].pagesize;
Shashank Mittaldcc2e352009-11-19 19:11:16 -08002169 flash_pagesize = flash_info.page_size;
Shashank Mittalc20b5a12009-11-18 19:35:30 -08002170 flash_info.block_size = supported_flash[index].blksize;
2171 flash_info.spare_size = supported_flash[index].oobsize;
2172 if (flash_info.block_size && flash_info.page_size)
2173 {
2174 flash_info.num_blocks = supported_flash[index].density;
2175 flash_info.num_blocks /= (flash_info.block_size * flash_info.page_size);
2176 }
2177 else
2178 {
2179 flash_info.num_blocks = 0;
2180 }
2181 ASSERT(flash_info.num_blocks);
2182 return;
2183 }
2184
2185 // Assume 8 bit nand device for backward compatability
2186 if (dev_found == 0) {
2187 dprintf(INFO, "Device not supported. Assuming 8 bit NAND device\n");
2188 flash_info.type = FLASH_8BIT_NAND_DEVICE;
2189 }
2190 dprintf(INFO, "nandid: 0x%x maker=0x%02x device=0x%02x page_size=%d\n",
2191 flash_info.id, flash_info.vendor, flash_info.device,
2192 flash_info.page_size);
2193 dprintf(INFO, " spare_size=%d block_size=%d num_blocks=%d\n",
2194 flash_info.spare_size, flash_info.block_size,
2195 flash_info.num_blocks);
2196}
2197
2198static int flash_erase_block(dmov_s *cmdlist, unsigned *ptrlist, unsigned page)
2199{
2200 switch(flash_info.type) {
2201 case FLASH_8BIT_NAND_DEVICE:
2202 case FLASH_16BIT_NAND_DEVICE:
2203 return flash_nand_erase_block(cmdlist, ptrlist, page);
2204 case FLASH_ONENAND_DEVICE:
2205 return flash_onenand_erase_block(cmdlist, ptrlist, page);
2206 default:
2207 return -1;
2208 }
2209}
2210
2211static int _flash_read_page(dmov_s *cmdlist, unsigned *ptrlist,
2212 unsigned page, void *_addr, void *_spareaddr)
2213{
2214 switch(flash_info.type) {
2215 case FLASH_8BIT_NAND_DEVICE:
2216 case FLASH_16BIT_NAND_DEVICE:
2217 return _flash_nand_read_page(cmdlist, ptrlist, page, _addr, _spareaddr);
2218 case FLASH_ONENAND_DEVICE:
Shashank Mittalad3d05c2009-11-19 15:53:57 -08002219 return _flash_onenand_read_page(cmdlist, ptrlist, page, _addr, _spareaddr, 0);
Shashank Mittalc20b5a12009-11-18 19:35:30 -08002220 default:
2221 return -1;
2222 }
2223}
2224
Shashank Mittalad3d05c2009-11-19 15:53:57 -08002225static int _flash_block_isbad(dmov_s *cmdlist, unsigned *ptrlist, unsigned page)
2226{
2227 switch(flash_info.type) {
2228 case FLASH_8BIT_NAND_DEVICE:
2229 case FLASH_16BIT_NAND_DEVICE:
2230 return flash_nand_block_isbad(cmdlist, ptrlist, page);
2231 case FLASH_ONENAND_DEVICE:
2232 return flash_onenand_block_isbad(cmdlist, ptrlist, page);
2233 default:
2234 return -1;
2235 }
2236}
Shashank Mittalc20b5a12009-11-18 19:35:30 -08002237
2238static int _flash_write_page(dmov_s *cmdlist, unsigned *ptrlist,
2239 unsigned page, const void *_addr,
2240 const void *_spareaddr)
2241{
2242 switch(flash_info.type) {
2243 case FLASH_8BIT_NAND_DEVICE:
2244 case FLASH_16BIT_NAND_DEVICE:
Shashank Mittald0c836d2009-11-20 10:31:18 -08002245 return _flash_nand_write_page(cmdlist, ptrlist, page, _addr, _spareaddr, 0);
Shashank Mittalc20b5a12009-11-18 19:35:30 -08002246 case FLASH_ONENAND_DEVICE:
Shashank Mittald0c836d2009-11-20 10:31:18 -08002247 return _flash_onenand_write_page(cmdlist, ptrlist, page, _addr, _spareaddr, 0);
Shashank Mittalc20b5a12009-11-18 19:35:30 -08002248 default:
2249 return -1;
2250 }
2251}
2252
Dima Zavin03cf4312009-01-23 16:38:30 -08002253static unsigned *flash_ptrlist;
2254static dmov_s *flash_cmdlist;
Dima Zavin03cf4312009-01-23 16:38:30 -08002255
2256static struct ptable *flash_ptable = NULL;
2257
Dima Zavine5f64352009-03-02 16:04:20 -08002258void flash_init(void)
Dima Zavin03cf4312009-01-23 16:38:30 -08002259{
Dima Zavine5f64352009-03-02 16:04:20 -08002260 ASSERT(flash_ptable == NULL);
Dima Zavin03cf4312009-01-23 16:38:30 -08002261
2262 flash_ptrlist = memalign(32, 1024);
2263 flash_cmdlist = memalign(32, 1024);
Ajay Dudani232ce812009-12-02 00:14:11 -08002264 flash_data = memalign(32, 4096 + 128);
2265 flash_spare = memalign(32, 128);
Dima Zavin03cf4312009-01-23 16:38:30 -08002266
Dima Zavin03cf4312009-01-23 16:38:30 -08002267 flash_read_id(flash_cmdlist, flash_ptrlist);
Shashank Mittal83d16d02009-11-18 16:54:42 -08002268 if((FLASH_8BIT_NAND_DEVICE == flash_info.type)
2269 ||(FLASH_16BIT_NAND_DEVICE == flash_info.type)) {
Shashank Mittalc20b5a12009-11-18 19:35:30 -08002270 if(flash_nand_read_config(flash_cmdlist, flash_ptrlist)) {
Shashank Mittal83d16d02009-11-18 16:54:42 -08002271 dprintf(CRITICAL, "ERROR: could not read CFG0/CFG1 state\n");
2272 ASSERT(0);
2273 }
2274 }
Dima Zavin03cf4312009-01-23 16:38:30 -08002275}
2276
2277struct ptable *flash_get_ptable(void)
2278{
2279 return flash_ptable;
2280}
2281
Dima Zavine5f64352009-03-02 16:04:20 -08002282void flash_set_ptable(struct ptable *new_ptable)
2283{
2284 ASSERT(flash_ptable == NULL && new_ptable != NULL);
2285 flash_ptable = new_ptable;
2286}
2287
Dima Zavinca337f52009-03-02 16:41:44 -08002288struct flash_info *flash_get_info(void)
2289{
2290 return &flash_info;
2291}
2292
Dima Zavin03cf4312009-01-23 16:38:30 -08002293int flash_erase(struct ptentry *ptn)
2294{
2295 unsigned block = ptn->start;
2296 unsigned count = ptn->length;
2297
Shashank Mittal8e49dec2010-03-01 15:19:04 -08002298 set_nand_configuration(ptn->type);
Dima Zavin03cf4312009-01-23 16:38:30 -08002299 while(count-- > 0) {
2300 if(flash_erase_block(flash_cmdlist, flash_ptrlist, block * 64)) {
2301 dprintf(INFO, "cannot erase @ %d (bad block?)\n", block);
2302 }
2303 block++;
2304 }
2305 return 0;
2306}
2307
2308int flash_read_ext(struct ptentry *ptn, unsigned extra_per_page,
Shashank Mittalc20b5a12009-11-18 19:35:30 -08002309 unsigned offset, void *data, unsigned bytes)
Dima Zavin03cf4312009-01-23 16:38:30 -08002310{
Shashank Mittaldcc2e352009-11-19 19:11:16 -08002311 unsigned page = (ptn->start * 64) + (offset / flash_pagesize);
Dima Zavin03cf4312009-01-23 16:38:30 -08002312 unsigned lastpage = (ptn->start + ptn->length) * 64;
Shashank Mittaldcc2e352009-11-19 19:11:16 -08002313 unsigned count = (bytes + flash_pagesize - 1 + extra_per_page) / (flash_pagesize + extra_per_page);
Dima Zavin03cf4312009-01-23 16:38:30 -08002314 unsigned *spare = (unsigned*) flash_spare;
2315 unsigned errors = 0;
2316 unsigned char *image = data;
Shashank Mittalad3d05c2009-11-19 15:53:57 -08002317 unsigned current_block = (page - (page & 63)) >> 6;
2318 unsigned start_block = ptn->start;
2319 int result = 0;
2320 int isbad = 0;
Dima Zavin03cf4312009-01-23 16:38:30 -08002321
Shashank Mittal8e49dec2010-03-01 15:19:04 -08002322 ASSERT(ptn->type == TYPE_APPS_PARTITION);
2323 set_nand_configuration(TYPE_APPS_PARTITION);
2324
Shashank Mittaldcc2e352009-11-19 19:11:16 -08002325 if(offset & (flash_pagesize - 1))
Dima Zavin03cf4312009-01-23 16:38:30 -08002326 return -1;
2327
Shashank Mittalad3d05c2009-11-19 15:53:57 -08002328 // Adjust page offset based on number of bad blocks from start to current page
2329 while (start_block < current_block) {
2330 isbad = _flash_block_isbad(flash_cmdlist, flash_ptrlist, start_block*64);
2331 if (isbad)
2332 page += 64;
2333
2334 start_block++;
2335 }
2336
Dima Zavin03cf4312009-01-23 16:38:30 -08002337 while(page < lastpage) {
2338 if(count == 0) {
2339 dprintf(INFO, "flash_read_image: success (%d errors)\n", errors);
2340 return 0;
2341 }
2342
Shashank Mittalad3d05c2009-11-19 15:53:57 -08002343 result = _flash_read_page(flash_cmdlist, flash_ptrlist, page, image, spare);
2344
2345 if (result == -1) {
2346 // bad page, go to next page
2347 page++;
Dima Zavin03cf4312009-01-23 16:38:30 -08002348 errors++;
2349 continue;
2350 }
Shashank Mittalad3d05c2009-11-19 15:53:57 -08002351 else if (result == -2) {
2352 // bad block, go to next block same offset
2353 page += 64;
2354 errors++;
2355 continue;
2356 }
2357
2358 page++;
Shashank Mittaldcc2e352009-11-19 19:11:16 -08002359 image += flash_pagesize;
Dima Zavin03cf4312009-01-23 16:38:30 -08002360 memcpy(image, spare, extra_per_page);
2361 image += extra_per_page;
2362 count -= 1;
2363 }
2364
2365 /* could not find enough valid pages before we hit the end */
2366 dprintf(INFO, "flash_read_image: failed (%d errors)\n", errors);
2367 return 0xffffffff;
2368}
2369
2370int flash_write(struct ptentry *ptn, unsigned extra_per_page, const void *data,
2371 unsigned bytes)
2372{
2373 unsigned page = ptn->start * 64;
2374 unsigned lastpage = (ptn->start + ptn->length) * 64;
2375 unsigned *spare = (unsigned*) flash_spare;
2376 const unsigned char *image = data;
Shashank Mittaldcc2e352009-11-19 19:11:16 -08002377 unsigned wsize = flash_pagesize + extra_per_page;
Dima Zavin03cf4312009-01-23 16:38:30 -08002378 unsigned n;
2379 int r;
2380
Shashank Mittal8e49dec2010-03-01 15:19:04 -08002381 if ((flash_info.type == FLASH_ONENAND_DEVICE) && (ptn->type == TYPE_MODEM_PARTITION))
2382 {
2383 dprintf(CRITICAL, "flash_write_image: feature not supported\n");
2384 return -1;
2385 }
2386
2387 set_nand_configuration(ptn->type);
Dima Zavin03cf4312009-01-23 16:38:30 -08002388 for(n = 0; n < 16; n++) spare[n] = 0xffffffff;
2389
2390 while(bytes > 0) {
2391 if(bytes < wsize) {
2392 dprintf(CRITICAL, "flash_write_image: image undersized (%d < %d)\n", bytes, wsize);
2393 return -1;
2394 }
2395 if(page >= lastpage) {
2396 dprintf(CRITICAL, "flash_write_image: out of space\n");
2397 return -1;
2398 }
2399
2400 if((page & 63) == 0) {
2401 if(flash_erase_block(flash_cmdlist, flash_ptrlist, page)) {
2402 dprintf(INFO, "flash_write_image: bad block @ %d\n", page >> 6);
2403 page += 64;
2404 continue;
2405 }
2406 }
2407
2408 if(extra_per_page) {
Shashank Mittald0c836d2009-11-20 10:31:18 -08002409 r = _flash_write_page(flash_cmdlist, flash_ptrlist, page, image, image + flash_pagesize);
Dima Zavin03cf4312009-01-23 16:38:30 -08002410 } else {
Shashank Mittald0c836d2009-11-20 10:31:18 -08002411 r = _flash_write_page(flash_cmdlist, flash_ptrlist, page, image, spare);
Dima Zavin03cf4312009-01-23 16:38:30 -08002412 }
2413 if(r) {
2414 dprintf(INFO, "flash_write_image: write failure @ page %d (src %d)\n", page, image - (const unsigned char *)data);
2415 image -= (page & 63) * wsize;
2416 bytes += (page & 63) * wsize;
2417 page &= ~63;
2418 if(flash_erase_block(flash_cmdlist, flash_ptrlist, page)) {
2419 dprintf(INFO, "flash_write_image: erase failure @ page %d\n", page);
2420 }
Shashank Mittal8e49dec2010-03-01 15:19:04 -08002421 if (ptn->type != TYPE_MODEM_PARTITION) {
2422 flash_mark_badblock(flash_cmdlist, flash_ptrlist, page);
2423 }
Dima Zavin03cf4312009-01-23 16:38:30 -08002424 dprintf(INFO, "flash_write_image: restart write @ page %d (src %d)\n", page, image - (const unsigned char *)data);
2425 page += 64;
2426 continue;
2427 }
Shashank Mittald0c836d2009-11-20 10:31:18 -08002428 page++;
Dima Zavin03cf4312009-01-23 16:38:30 -08002429 image += wsize;
2430 bytes -= wsize;
2431 }
2432
2433 /* erase any remaining pages in the partition */
2434 page = (page + 63) & (~63);
2435 while(page < lastpage){
2436 if(flash_erase_block(flash_cmdlist, flash_ptrlist, page)) {
2437 dprintf(INFO, "flash_write_image: bad block @ %d\n", page >> 6);
2438 }
2439 page += 64;
2440 }
2441
2442 dprintf(INFO, "flash_write_image: success\n");
2443 return 0;
2444}
2445
2446#if 0
2447static int flash_read_page(unsigned page, void *data, void *extra)
2448{
2449 return _flash_read_page(flash_cmdlist, flash_ptrlist,
2450 page, data, extra);
2451}
2452#endif
Shashank Mittaldcc2e352009-11-19 19:11:16 -08002453
2454unsigned flash_page_size(void)
2455{
2456 return flash_pagesize;
2457}