blob: 4030c34d02c02b3c0077042cf0040860ca68a97c [file] [log] [blame]
Dima Zavin03cf4312009-01-23 16:38:30 -08001/*
2 * Copyright (c) 2008, Google Inc.
3 * All rights reserved.
Aparna Mallavarapuc5946f22013-04-08 21:44:51 +05304 * Copyright (c) 2009-2013, The Linux Foundation. All rights reserved.
Dima Zavin03cf4312009-01-23 16:38:30 -08005 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in
Shashank Mittalc20b5a12009-11-18 19:35:30 -080012 * the documentation and/or other materials provided with the
Dima Zavin03cf4312009-01-23 16:38:30 -080013 * distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
18 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
Shashank Mittalc20b5a12009-11-18 19:35:30 -080022 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
Dima Zavin03cf4312009-01-23 16:38:30 -080023 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
25 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29#include <debug.h>
30#include <reg.h>
31#include <stdlib.h>
32#include <string.h>
33#include <dev/flash.h>
34#include <lib/ptable.h>
Ajay Dudani168f6cb2009-12-07 19:04:02 -080035#include <nand.h>
Dima Zavin03cf4312009-01-23 16:38:30 -080036
37#include "dmov.h"
Dima Zavin03cf4312009-01-23 16:38:30 -080038
39#define VERBOSE 0
Dima Zavin5582c7d2009-03-03 15:17:59 -080040#define VERIFY_WRITE 0
41
42static void *flash_spare;
43static void *flash_data;
Chandan Uddaraju14e57eb2010-06-28 12:11:06 -070044void platform_config_interleaved_mode_gpios(void);
Dima Zavin03cf4312009-01-23 16:38:30 -080045
46typedef struct dmov_ch dmov_ch;
Ajay Dudanib01e5062011-12-03 23:23:42 -080047struct dmov_ch {
Dima Zavin03cf4312009-01-23 16:38:30 -080048 volatile unsigned cmd;
49 volatile unsigned result;
50 volatile unsigned status;
51 volatile unsigned config;
52};
53
Ajay Dudanib01e5062011-12-03 23:23:42 -080054static void dmov_prep_ch(dmov_ch * ch, unsigned id)
Dima Zavin03cf4312009-01-23 16:38:30 -080055{
56 ch->cmd = DMOV_CMD_PTR(id);
57 ch->result = DMOV_RSLT(id);
58 ch->status = DMOV_STATUS(id);
59 ch->config = DMOV_CONFIG(id);
60}
61
62#define SRC_CRCI_NAND_CMD CMD_SRC_CRCI(DMOV_NAND_CRCI_CMD)
63#define DST_CRCI_NAND_CMD CMD_DST_CRCI(DMOV_NAND_CRCI_CMD)
64#define SRC_CRCI_NAND_DATA CMD_SRC_CRCI(DMOV_NAND_CRCI_DATA)
65#define DST_CRCI_NAND_DATA CMD_DST_CRCI(DMOV_NAND_CRCI_DATA)
66
Channagoud Kadabi404a7062011-03-21 19:27:50 +053067#define CFG0_RAW 0xA80420C0
68#define CFG1_RAW 0x5045D
69
70#define CFG0_RAW_BCHECC 0xA80428C0
Shashank Mittalad3d05c2009-11-19 15:53:57 -080071
Dima Zavin03cf4312009-01-23 16:38:30 -080072static unsigned CFG0, CFG1;
Shashank Mittal8e49dec2010-03-01 15:19:04 -080073static unsigned CFG0_M, CFG1_M;
74static unsigned CFG0_A, CFG1_A;
Channagoud Kadabi404a7062011-03-21 19:27:50 +053075static unsigned NAND_CFG0_RAW, NAND_CFG1_RAW;
76static unsigned ECC_BCH_CFG;
77
78static uint32_t enable_bch_ecc;
Channagoud Kadabib2fb6ba2011-07-29 19:19:01 +053079static unsigned int *bbtbl;
Dima Zavin03cf4312009-01-23 16:38:30 -080080
81#define CFG1_WIDE_FLASH (1U << 1)
82
83#define paddr(n) ((unsigned) (n))
84
85static int dmov_exec_cmdptr(unsigned id, unsigned *ptr)
86{
87 dmov_ch ch;
88 unsigned n;
89
90 dmov_prep_ch(&ch, id);
91
Kinson Chik1f461162011-09-07 15:07:50 -070092 /* Set IRQ_EN low, not using IRQ mode */
93 writel(DMOV_CONFIG_FOREC_FLUSH_RSLT | 0x0, ch.config);
94
Dima Zavin03cf4312009-01-23 16:38:30 -080095 writel(DMOV_CMD_PTR_LIST | DMOV_CMD_ADDR(paddr(ptr)), ch.cmd);
96
Ajay Dudanib01e5062011-12-03 23:23:42 -080097 while (!(readl(ch.status) & DMOV_STATUS_RSLT_VALID)) ;
Dima Zavin03cf4312009-01-23 16:38:30 -080098
99 n = readl(ch.status);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800100 while (DMOV_STATUS_RSLT_COUNT(n)) {
Dima Zavin03cf4312009-01-23 16:38:30 -0800101 n = readl(ch.result);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800102 if (n != 0x80000002) {
Dima Zavin03cf4312009-01-23 16:38:30 -0800103 dprintf(CRITICAL, "ERROR: result: %x\n", n);
104 dprintf(CRITICAL, "ERROR: flush: %x %x %x %x\n",
105 readl(DMOV_FLUSH0(DMOV_NAND_CHAN)),
106 readl(DMOV_FLUSH1(DMOV_NAND_CHAN)),
107 readl(DMOV_FLUSH2(DMOV_NAND_CHAN)),
108 readl(DMOV_FLUSH3(DMOV_NAND_CHAN)));
109 }
110 n = readl(ch.status);
111 }
112
113 return 0;
114}
115
Dima Zavinca337f52009-03-02 16:41:44 -0800116static struct flash_info flash_info;
Shashank Mittaldcc2e352009-11-19 19:11:16 -0800117static unsigned flash_pagesize = 0;
Chandan Uddaraju14e57eb2010-06-28 12:11:06 -0700118static int interleaved_mode = 0;
Channagoud Kadabibeb17d52011-03-25 17:14:00 +0530119static unsigned num_pages_per_blk = 0;
120static unsigned num_pages_per_blk_mask = 0;
Dima Zavin03cf4312009-01-23 16:38:30 -0800121
Shashank Mittal83d16d02009-11-18 16:54:42 -0800122struct flash_identification {
Shashank Mittalc20b5a12009-11-18 19:35:30 -0800123 unsigned flash_id;
124 unsigned mask;
125 unsigned density;
126 unsigned widebus;
127 unsigned pagesize;
128 unsigned blksize;
129 unsigned oobsize;
130 unsigned onenand;
Shashank Mittal83d16d02009-11-18 16:54:42 -0800131};
132
Ajay Dudanib01e5062011-12-03 23:23:42 -0800133static struct flash_identification supported_flash[] = {
134 /* Flash ID ID Mask Density(MB) Wid Pgsz Blksz oobsz onenand Manuf */
135 {0x00000000, 0xFFFFFFFF, 0, 0, 0, 0, 0, 0}, /*ONFI*/ {0x1500aaec, 0xFF00FFFF, (256 << 20), 0, 2048, (2048 << 6), 64, 0}, /*Sams */
136 {0x5500baec, 0xFF00FFFF, (256 << 20), 1, 2048, (2048 << 6), 64, 0}, /*Sams */
137 {0x1500aa98, 0xFFFFFFFF, (256 << 20), 0, 2048, (2048 << 6), 64, 0}, /*Tosh */
138 {0x5500ba98, 0xFFFFFFFF, (256 << 20), 1, 2048, (2048 << 6), 64, 0}, /*Tosh */
139 {0xd580b12c, 0xFFFFFFFF, (256 << 20), 1, 2048, (2048 << 6), 64, 0}, /*Micr */
140 {0x5590bc2c, 0xFFFFFFFF, (512 << 20), 1, 2048, (2048 << 6), 64, 0}, /*Micr */
141 {0x1580aa2c, 0xFFFFFFFF, (256 << 20), 0, 2048, (2048 << 6), 64, 0}, /*Micr */
142 {0x1590aa2c, 0xFFFFFFFF, (256 << 20), 0, 2048, (2048 << 6), 64, 0}, /*Micr */
143 {0x1590ac2c, 0xFFFFFFFF, (512 << 20), 0, 2048, (2048 << 6), 64, 0}, /*Micr */
144 {0x5580baad, 0xFFFFFFFF, (256 << 20), 1, 2048, (2048 << 6), 64, 0}, /*Hynx */
145 {0x5510baad, 0xFFFFFFFF, (256 << 20), 1, 2048, (2048 << 6), 64, 0}, /*Hynx */
146 {0x004000ec, 0xFFFFFFFF, (256 << 20), 0, 2048, (2048 << 6), 64, 1}, /*Sams */
147 {0x005c00ec, 0xFFFFFFFF, (256 << 20), 0, 2048, (2048 << 6), 64, 1}, /*Sams */
148 {0x005800ec, 0xFFFFFFFF, (256 << 20), 0, 2048, (2048 << 6), 64, 1}, /*Sams */
149 {0x6600bcec, 0xFF00FFFF, (512 << 20), 1, 4096, (4096 << 6), 128, 0}, /*Sams */
150 {0x5580ba2c, 0xFFFFFFFF, (256 << 20), 1, 2048, (2048 << 6), 64, 0}, /*Hynx */
Channagoud Kadabi71bcec22012-01-09 19:22:52 +0530151 {0x6600b3ec, 0xFFFFFFFF, (1024 << 20), 1, 4096, (4096 << 6), 128, 0}, /*Sams */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800152 {0x2600482c, 0xFF00FFFF, (2048 << 20), 0, 4096, (4096 << 7), 224, 0}, /*8bit bch ecc */
Channagoud Kadabi7a6ded72012-07-02 15:32:21 +0530153 {0x55d1b32c, 0xFFFFFFFF, (1024 << 20), 1, 2048, (2048 << 6), 64, 0}, /*Micr */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800154 /* Note: Width flag is 0 for 8 bit Flash and 1 for 16 bit flash */
155 /* Note: Onenand flag is 0 for NAND Flash and 1 for OneNAND flash */
156 /* Note: The First row will be filled at runtime during ONFI probe */
Shashank Mittal83d16d02009-11-18 16:54:42 -0800157};
Ajay Dudanib01e5062011-12-03 23:23:42 -0800158
Shashank Mittal8e49dec2010-03-01 15:19:04 -0800159static void set_nand_configuration(char type)
160{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800161 if (type == TYPE_MODEM_PARTITION) {
Shashank Mittal8e49dec2010-03-01 15:19:04 -0800162 CFG0 = CFG0_M;
163 CFG1 = CFG1_M;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800164 } else {
Shashank Mittal8e49dec2010-03-01 15:19:04 -0800165 CFG0 = CFG0_A;
166 CFG1 = CFG1_A;
167 }
168}
Shashank Mittal83d16d02009-11-18 16:54:42 -0800169
Ajay Dudanib01e5062011-12-03 23:23:42 -0800170static void flash_nand_read_id(dmov_s * cmdlist, unsigned *ptrlist)
Dima Zavin03cf4312009-01-23 16:38:30 -0800171{
172 dmov_s *cmd = cmdlist;
173 unsigned *ptr = ptrlist;
174 unsigned *data = ptrlist + 4;
175
176 data[0] = 0 | 4;
177 data[1] = NAND_CMD_FETCH_ID;
178 data[2] = 1;
179 data[3] = 0;
180 data[4] = 0;
Shashank Mittalc20b5a12009-11-18 19:35:30 -0800181 data[5] = 0;
182 data[6] = 0;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800183 data[7] = 0xAAD40000; /* Default value for CFG0 for reading device id */
Dima Zavin03cf4312009-01-23 16:38:30 -0800184
Shashank Mittalc20b5a12009-11-18 19:35:30 -0800185 /* Read NAND device id */
Dima Zavin03cf4312009-01-23 16:38:30 -0800186 cmd[0].cmd = 0 | CMD_OCB;
Shashank Mittalc20b5a12009-11-18 19:35:30 -0800187 cmd[0].src = paddr(&data[7]);
188 cmd[0].dst = NAND_DEV0_CFG0;
Dima Zavin03cf4312009-01-23 16:38:30 -0800189 cmd[0].len = 4;
190
Shashank Mittalc20b5a12009-11-18 19:35:30 -0800191 cmd[1].cmd = 0;
192 cmd[1].src = NAND_SFLASHC_BURST_CFG;
193 cmd[1].dst = paddr(&data[5]);
Dima Zavin03cf4312009-01-23 16:38:30 -0800194 cmd[1].len = 4;
195
196 cmd[2].cmd = 0;
Shashank Mittalc20b5a12009-11-18 19:35:30 -0800197 cmd[2].src = paddr(&data[6]);
198 cmd[2].dst = NAND_SFLASHC_BURST_CFG;
Dima Zavin03cf4312009-01-23 16:38:30 -0800199 cmd[2].len = 4;
200
Shashank Mittalc20b5a12009-11-18 19:35:30 -0800201 cmd[3].cmd = 0;
202 cmd[3].src = paddr(&data[0]);
203 cmd[3].dst = NAND_FLASH_CHIP_SELECT;
Dima Zavin03cf4312009-01-23 16:38:30 -0800204 cmd[3].len = 4;
205
Shashank Mittalc20b5a12009-11-18 19:35:30 -0800206 cmd[4].cmd = DST_CRCI_NAND_CMD;
207 cmd[4].src = paddr(&data[1]);
208 cmd[4].dst = NAND_FLASH_CMD;
Dima Zavin03cf4312009-01-23 16:38:30 -0800209 cmd[4].len = 4;
210
Shashank Mittalc20b5a12009-11-18 19:35:30 -0800211 cmd[5].cmd = 0;
212 cmd[5].src = paddr(&data[2]);
213 cmd[5].dst = NAND_EXEC_CMD;
214 cmd[5].len = 4;
215
216 cmd[6].cmd = SRC_CRCI_NAND_DATA;
217 cmd[6].src = NAND_FLASH_STATUS;
218 cmd[6].dst = paddr(&data[3]);
219 cmd[6].len = 4;
220
221 cmd[7].cmd = 0;
222 cmd[7].src = NAND_READ_ID;
223 cmd[7].dst = paddr(&data[4]);
224 cmd[7].len = 4;
225
226 cmd[8].cmd = CMD_OCU | CMD_LC;
227 cmd[8].src = paddr(&data[5]);
228 cmd[8].dst = NAND_SFLASHC_BURST_CFG;
229 cmd[8].len = 4;
230
Dima Zavin03cf4312009-01-23 16:38:30 -0800231 ptr[0] = (paddr(cmd) >> 3) | CMD_PTR_LP;
232
233 dmov_exec_cmdptr(DMOV_NAND_CHAN, ptr);
234
235#if VERBOSE
236 dprintf(INFO, "status: %x\n", data[3]);
237#endif
Dima Zavin03cf4312009-01-23 16:38:30 -0800238
Shashank Mittal83d16d02009-11-18 16:54:42 -0800239 flash_info.id = data[4];
Dima Zavinca337f52009-03-02 16:41:44 -0800240 flash_info.vendor = data[4] & 0xff;
241 flash_info.device = (data[4] >> 8) & 0xff;
Shashank Mittal83d16d02009-11-18 16:54:42 -0800242 return;
243}
Dima Zavinca337f52009-03-02 16:41:44 -0800244
Ajay Dudanib01e5062011-12-03 23:23:42 -0800245static int
246flash_nand_block_isbad(dmov_s * cmdlist, unsigned *ptrlist, unsigned page)
Shashank Mittalad3d05c2009-11-19 15:53:57 -0800247{
248 dmov_s *cmd = cmdlist;
249 unsigned *ptr = ptrlist;
250 unsigned *data = ptrlist + 4;
251 char buf[4];
Shashank Mittaldcc2e352009-11-19 19:11:16 -0800252 unsigned cwperpage;
253
254 cwperpage = (flash_pagesize >> 9);
Shashank Mittalad3d05c2009-11-19 15:53:57 -0800255
256 /* Check first page of this block */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800257 if (page & num_pages_per_blk_mask)
Channagoud Kadabibeb17d52011-03-25 17:14:00 +0530258 page = page - (page & num_pages_per_blk_mask);
Shashank Mittalad3d05c2009-11-19 15:53:57 -0800259
260 /* Check bad block marker */
261 data[0] = NAND_CMD_PAGE_READ; /* command */
262
263 /* addr0 */
264 if (CFG1 & CFG1_WIDE_FLASH)
Channagoud Kadabi404a7062011-03-21 19:27:50 +0530265 data[1] = enable_bch_ecc ?
Ajay Dudanib01e5062011-12-03 23:23:42 -0800266 ((page << 16) | ((532 * (cwperpage - 1)) >> 1)) :
267 ((page << 16) | ((528 * (cwperpage - 1)) >> 1));
Channagoud Kadabi404a7062011-03-21 19:27:50 +0530268
Shashank Mittalad3d05c2009-11-19 15:53:57 -0800269 else
Channagoud Kadabi404a7062011-03-21 19:27:50 +0530270 data[1] = enable_bch_ecc ?
Ajay Dudanib01e5062011-12-03 23:23:42 -0800271 ((page << 16) | (532 * (cwperpage - 1))) :
272 ((page << 16) | (528 * (cwperpage - 1)));
Shashank Mittalad3d05c2009-11-19 15:53:57 -0800273
Ajay Dudanib01e5062011-12-03 23:23:42 -0800274 data[2] = (page >> 16) & 0xff; /* addr1 */
275 data[3] = 0 | 4; /* chipsel */
276 data[4] = NAND_CFG0_RAW & ~(7U << 6); /* cfg0 */
277 data[5] = NAND_CFG1_RAW | (CFG1 & CFG1_WIDE_FLASH); /* cfg1 */
Channagoud Kadabi404a7062011-03-21 19:27:50 +0530278 if (enable_bch_ecc) {
Ajay Dudanib01e5062011-12-03 23:23:42 -0800279 data[6] = ECC_BCH_CFG; /* ECC CFG */
Channagoud Kadabi404a7062011-03-21 19:27:50 +0530280 }
281 data[7] = 1;
282 data[8] = CLEAN_DATA_32; /* flash status */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800283 data[9] = CLEAN_DATA_32; /* buf status */
Shashank Mittalad3d05c2009-11-19 15:53:57 -0800284
285 cmd[0].cmd = DST_CRCI_NAND_CMD | CMD_OCB;
286 cmd[0].src = paddr(&data[0]);
287 cmd[0].dst = NAND_FLASH_CMD;
288 cmd[0].len = 16;
289
290 cmd[1].cmd = 0;
291 cmd[1].src = paddr(&data[4]);
292 cmd[1].dst = NAND_DEV0_CFG0;
Channagoud Kadabi404a7062011-03-21 19:27:50 +0530293 if (enable_bch_ecc) {
294 cmd[1].len = 12;
295 } else {
296 cmd[1].len = 8;
297 }
Shashank Mittalad3d05c2009-11-19 15:53:57 -0800298
299 cmd[2].cmd = 0;
Channagoud Kadabi404a7062011-03-21 19:27:50 +0530300 cmd[2].src = paddr(&data[7]);
Shashank Mittalad3d05c2009-11-19 15:53:57 -0800301 cmd[2].dst = NAND_EXEC_CMD;
302 cmd[2].len = 4;
303
304 cmd[3].cmd = SRC_CRCI_NAND_DATA;
305 cmd[3].src = NAND_FLASH_STATUS;
Channagoud Kadabi404a7062011-03-21 19:27:50 +0530306 cmd[3].dst = paddr(&data[8]);
Shashank Mittalad3d05c2009-11-19 15:53:57 -0800307 cmd[3].len = 8;
308
309 cmd[4].cmd = CMD_OCU | CMD_LC;
Channagoud Kadabi404a7062011-03-21 19:27:50 +0530310 cmd[4].src = NAND_FLASH_BUFFER + (flash_pagesize - (enable_bch_ecc ?
Ajay Dudanib01e5062011-12-03 23:23:42 -0800311 (532 *
312 (cwperpage -
313 1)) : (528 *
314 (cwperpage
315 - 1))));
Shashank Mittalad3d05c2009-11-19 15:53:57 -0800316 cmd[4].dst = paddr(&buf);
317 cmd[4].len = 4;
318
319 ptr[0] = (paddr(cmd) >> 3) | CMD_PTR_LP;
320
321 dmov_exec_cmdptr(DMOV_NAND_CHAN, ptr);
322
323#if VERBOSE
Channagoud Kadabi404a7062011-03-21 19:27:50 +0530324 dprintf(INFO, "status: %x\n", data[8]);
Shashank Mittalad3d05c2009-11-19 15:53:57 -0800325#endif
326
327 /* we fail if there was an operation error, a mpu error, or the
Ajay Dudanib01e5062011-12-03 23:23:42 -0800328 ** erase success bit was not set.
329 */
330 if (data[8] & 0x110)
331 return -1;
Shashank Mittalad3d05c2009-11-19 15:53:57 -0800332
333 /* Check for bad block marker byte */
334 if (CFG1 & CFG1_WIDE_FLASH) {
335 if (buf[0] != 0xFF || buf[1] != 0xFF)
336 return 1;
337 } else {
338 if (buf[0] != 0xFF)
339 return 1;
340 }
341
342 return 0;
343}
344
Ajay Dudanib01e5062011-12-03 23:23:42 -0800345static int
346flash_nand_block_isbad_interleave(dmov_s * cmdlist, unsigned *ptrlist,
347 unsigned page)
Murali Nalajalaa8c94c62010-03-05 20:24:30 +0530348{
349 dmov_s *cmd = cmdlist;
350 unsigned *ptr = ptrlist;
351 unsigned *data = ptrlist + 4;
352 char buf01[4];
353 char buf10[4];
354 unsigned cwperpage;
355
Ajay Dudanib01e5062011-12-03 23:23:42 -0800356 cwperpage = ((flash_pagesize >> 1) >> 9);
Murali Nalajalaa8c94c62010-03-05 20:24:30 +0530357
358 /* Check first page of this block */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800359 if (page & 63)
Murali Nalajalaa8c94c62010-03-05 20:24:30 +0530360 page = page - (page & 63);
361
362 /* Check bad block marker */
363 data[0] = NAND_CMD_PAGE_READ; /* command */
364
365 /* addr0 */
366 if (CFG1 & CFG1_WIDE_FLASH)
Ajay Dudanib01e5062011-12-03 23:23:42 -0800367 data[1] = (page << 16) | ((528 * (cwperpage - 1)) >> 1);
Murali Nalajalaa8c94c62010-03-05 20:24:30 +0530368 else
Ajay Dudanib01e5062011-12-03 23:23:42 -0800369 data[1] = (page << 16) | (528 * (cwperpage - 1));
Murali Nalajalaa8c94c62010-03-05 20:24:30 +0530370
Ajay Dudanib01e5062011-12-03 23:23:42 -0800371 data[2] = (page >> 16) & 0xff; /* addr1 */
372 data[3] = 0 | 4; /* chipsel CS0 */
373 data[4] = 0 | 5; /* chipsel CS1 */
374 data[5] = NAND_CFG0_RAW & ~(7U << 6); /* cfg0 */
375 data[6] = NAND_CFG1_RAW | (CFG1 & CFG1_WIDE_FLASH); /* cfg1 */
Murali Nalajalaa8c94c62010-03-05 20:24:30 +0530376 data[7] = 1;
377 data[8] = CLEAN_DATA_32; /* NC01 flash status */
378 data[9] = CLEAN_DATA_32; /* NC01 buf01 status */
379 data[10] = CLEAN_DATA_32; /* NC10 flash status */
380 data[11] = CLEAN_DATA_32; /* NC10 buf10 status */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800381 data[12] = 0x00000A3C; /* adm_mux_data_ack_req_nc01 */
382 data[13] = 0x0000053C; /* adm_mux_cmd_ack_req_nc01 */
383 data[14] = 0x00000F28; /* adm_mux_data_ack_req_nc10 */
384 data[15] = 0x00000F14; /* adm_mux_cmd_ack_req_nc10 */
385 data[16] = 0x00000FC0; /* adm_default_mux */
386 data[17] = 0x00000805; /* enable CS1 */
387 data[18] = 0x00000801; /* disable CS1 */
Murali Nalajalaa8c94c62010-03-05 20:24:30 +0530388
389 /* enable CS1 */
390 cmd[0].cmd = 0;
391 cmd[0].src = paddr(data[17]);
392 cmd[0].dst = EBI2_CHIP_SELECT_CFG0;
393 cmd[0].len = 4;
394
395 /* Reading last code word from NC01 */
396 /* 0xF14 */
397 cmd[1].cmd = 0;
398 cmd[1].src = paddr(data[15]);
399 cmd[1].dst = EBI2_NAND_ADM_MUX;
400 cmd[1].len = 4;
401
402 cmd[2].cmd = DST_CRCI_NAND_CMD;
403 cmd[2].src = paddr(&data[0]);
404 cmd[2].dst = NC01(NAND_FLASH_CMD);
405 cmd[2].len = 16;
406
407 cmd[3].cmd = 0;
408 cmd[3].src = paddr(&data[5]);
409 cmd[3].dst = NC01(NAND_DEV0_CFG0);
410 cmd[3].len = 8;
411
412 cmd[4].cmd = 0;
413 cmd[4].src = paddr(&data[7]);
414 cmd[4].dst = NC01(NAND_EXEC_CMD);
415 cmd[4].len = 4;
416
417 /* 0xF28 */
418 cmd[5].cmd = 0;
419 cmd[5].src = paddr(data[14]);
420 cmd[5].dst = EBI2_NAND_ADM_MUX;
421 cmd[5].len = 4;
422
423 cmd[6].cmd = SRC_CRCI_NAND_DATA;
424 cmd[6].src = NC01(NAND_FLASH_STATUS);
425 cmd[6].dst = paddr(&data[8]);
426 cmd[6].len = 8;
427
428 cmd[7].cmd = 0;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800429 cmd[7].src =
430 NC01(NAND_FLASH_BUFFER) + (flash_pagesize -
431 (528 * (cwperpage - 1)));
Murali Nalajalaa8c94c62010-03-05 20:24:30 +0530432 cmd[7].dst = paddr(&buf01);
433 cmd[7].len = 4;
434
435 /* Reading last code word from NC10 */
436 /* 0x53C */
437 cmd[8].cmd = 0;
438 cmd[8].src = paddr(data[13]);
439 cmd[8].dst = EBI2_NAND_ADM_MUX;
440 cmd[8].len = 4;
441
442 cmd[9].cmd = DST_CRCI_NAND_CMD;
443 cmd[9].src = paddr(&data[0]);
444 cmd[9].dst = NC10(NAND_FLASH_CMD);
445 cmd[9].len = 12;
446
447 cmd[10].cmd = 0;
448 cmd[10].src = paddr(&data[4]);
449 cmd[10].dst = NC10(NAND_FLASH_CHIP_SELECT);
450 cmd[10].len = 4;
451
452 cmd[11].cmd = 0;
453 cmd[11].src = paddr(&data[5]);
454 cmd[11].dst = NC10(NAND_DEV1_CFG0);
455 cmd[11].len = 8;
456
457 cmd[12].cmd = 0;
458 cmd[12].src = paddr(&data[7]);
459 cmd[12].dst = NC10(NAND_EXEC_CMD);
460 cmd[12].len = 4;
461
462 /* 0xA3C */
463 cmd[13].cmd = 0;
464 cmd[13].src = paddr(data[12]);
465 cmd[13].dst = EBI2_NAND_ADM_MUX;
466 cmd[13].len = 4;
467
468 cmd[14].cmd = SRC_CRCI_NAND_DATA;
469 cmd[14].src = NC10(NAND_FLASH_STATUS);
470 cmd[14].dst = paddr(&data[10]);
471 cmd[14].len = 8;
472
473 cmd[15].cmd = 0;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800474 cmd[15].src =
475 NC10(NAND_FLASH_BUFFER) + (flash_pagesize -
476 (528 * (cwperpage - 1)));
Murali Nalajalaa8c94c62010-03-05 20:24:30 +0530477 cmd[15].dst = paddr(&buf10);
478 cmd[15].len = 4;
479
480 cmd[16].cmd = 0;
481 cmd[16].src = paddr(&data[16]);
482 cmd[16].dst = EBI2_NAND_ADM_MUX;
483 cmd[16].len = 4;
484
485 /* setting default value */
486 cmd[17].cmd = CMD_OCU | CMD_LC;
487 cmd[17].src = paddr(&data[18]);
488 cmd[17].dst = EBI2_CHIP_SELECT_CFG0;
489 cmd[17].len = 4;
490
491 ptr[0] = (paddr(cmd) >> 3) | CMD_PTR_LP;
492
493 dmov_exec_cmdptr(DMOV_NAND_CHAN, ptr);
494
495#if VERBOSE
496 dprintf(INFO, "NC01 status: %x\n", data[8]);
497 dprintf(INFO, "NC10 status: %x\n", data[10]);
498#endif
499
500 /* we fail if there was an operation error, a mpu error, or the
Ajay Dudanib01e5062011-12-03 23:23:42 -0800501 ** erase success bit was not set.
502 */
503 if ((data[8] & 0x110) || (data[10] & 0x110))
504 return -1;
Murali Nalajalaa8c94c62010-03-05 20:24:30 +0530505
506 /* Check for bad block marker byte */
507 if (CFG1 & CFG1_WIDE_FLASH) {
508 if ((buf01[0] != 0xFF || buf01[1] != 0xFF) ||
Ajay Dudanib01e5062011-12-03 23:23:42 -0800509 (buf10[0] != 0xFF || buf10[1] != 0xFF))
Murali Nalajalaa8c94c62010-03-05 20:24:30 +0530510 return 1;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800511 } else {
512 if (buf01[0] != 0xFF || buf10[0] != 0xFF)
Murali Nalajalaa8c94c62010-03-05 20:24:30 +0530513 return 1;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800514 }
Murali Nalajalaa8c94c62010-03-05 20:24:30 +0530515
516 return 0;
517}
518
Ajay Dudanib01e5062011-12-03 23:23:42 -0800519static int
520flash_nand_erase_block(dmov_s * cmdlist, unsigned *ptrlist, unsigned page)
Dima Zavin03cf4312009-01-23 16:38:30 -0800521{
522 dmov_s *cmd = cmdlist;
523 unsigned *ptr = ptrlist;
524 unsigned *data = ptrlist + 4;
Shashank Mittalad3d05c2009-11-19 15:53:57 -0800525 int isbad = 0;
Dima Zavin03cf4312009-01-23 16:38:30 -0800526
527 /* only allow erasing on block boundaries */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800528 if (page & num_pages_per_blk_mask)
529 return -1;
Dima Zavin03cf4312009-01-23 16:38:30 -0800530
Shashank Mittalad3d05c2009-11-19 15:53:57 -0800531 /* Check for bad block and erase only if block is not marked bad */
532 isbad = flash_nand_block_isbad(cmdlist, ptrlist, page);
533
534 if (isbad) {
Ajay Dudanib01e5062011-12-03 23:23:42 -0800535 dprintf(INFO, "skipping @ %d (bad block)\n",
536 page / num_pages_per_blk);
Shashank Mittalad3d05c2009-11-19 15:53:57 -0800537 return -1;
538 }
539
540 /* Erase block */
Dima Zavin03cf4312009-01-23 16:38:30 -0800541 data[0] = NAND_CMD_BLOCK_ERASE;
542 data[1] = page;
543 data[2] = 0;
544 data[3] = 0 | 4;
545 data[4] = 1;
546 data[5] = 0xeeeeeeee;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800547 data[6] = CFG0 & (~(7 << 6)); /* CW_PER_PAGE = 0 */
Dima Zavin03cf4312009-01-23 16:38:30 -0800548 data[7] = CFG1;
Channagoud Kadabi404a7062011-03-21 19:27:50 +0530549 data[8] = ECC_BCH_CFG;
550 data[9] = 0x00000020;
551 data[10] = 0x000000C0;
Dima Zavin03cf4312009-01-23 16:38:30 -0800552
553 cmd[0].cmd = DST_CRCI_NAND_CMD | CMD_OCB;
554 cmd[0].src = paddr(&data[0]);
555 cmd[0].dst = NAND_FLASH_CMD;
556 cmd[0].len = 16;
557
558 cmd[1].cmd = 0;
559 cmd[1].src = paddr(&data[6]);
560 cmd[1].dst = NAND_DEV0_CFG0;
Channagoud Kadabi404a7062011-03-21 19:27:50 +0530561 if (enable_bch_ecc) {
562 cmd[1].len = 12;
563 } else {
564 cmd[1].len = 8;
565 }
Dima Zavin03cf4312009-01-23 16:38:30 -0800566
567 cmd[2].cmd = 0;
568 cmd[2].src = paddr(&data[4]);
569 cmd[2].dst = NAND_EXEC_CMD;
570 cmd[2].len = 4;
571
Murali Palnatic54d13a2010-01-15 19:50:19 +0530572 cmd[3].cmd = SRC_CRCI_NAND_DATA;
Dima Zavin03cf4312009-01-23 16:38:30 -0800573 cmd[3].src = NAND_FLASH_STATUS;
574 cmd[3].dst = paddr(&data[5]);
575 cmd[3].len = 4;
576
Murali Palnatic54d13a2010-01-15 19:50:19 +0530577 cmd[4].cmd = 0;
Channagoud Kadabi404a7062011-03-21 19:27:50 +0530578 cmd[4].src = paddr(&data[9]);
Murali Palnatic54d13a2010-01-15 19:50:19 +0530579 cmd[4].dst = NAND_FLASH_STATUS;
580 cmd[4].len = 4;
581
582 cmd[5].cmd = CMD_OCU | CMD_LC;
Channagoud Kadabi404a7062011-03-21 19:27:50 +0530583 cmd[5].src = paddr(&data[10]);
Murali Palnatic54d13a2010-01-15 19:50:19 +0530584 cmd[5].dst = NAND_READ_STATUS;
585 cmd[5].len = 4;
586
Dima Zavin03cf4312009-01-23 16:38:30 -0800587 ptr[0] = (paddr(cmd) >> 3) | CMD_PTR_LP;
588
589 dmov_exec_cmdptr(DMOV_NAND_CHAN, ptr);
590
591#if VERBOSE
592 dprintf(INFO, "status: %x\n", data[5]);
593#endif
594
595 /* we fail if there was an operation error, a mpu error, or the
596 ** erase success bit was not set.
597 */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800598 if (data[5] & 0x110)
599 return -1;
600 if (!(data[5] & 0x80))
601 return -1;
Dima Zavin03cf4312009-01-23 16:38:30 -0800602
603 return 0;
604}
605
Ajay Dudanib01e5062011-12-03 23:23:42 -0800606static int
607flash_nand_erase_block_interleave(dmov_s * cmdlist, unsigned *ptrlist,
608 unsigned page)
Murali Nalajalaa8c94c62010-03-05 20:24:30 +0530609{
610 dmov_s *cmd = cmdlist;
611 unsigned *ptr = ptrlist;
612 unsigned *data = ptrlist + 4;
613 int isbad = 0;
614
615 /* only allow erasing on block boundaries */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800616 if (page & 63)
617 return -1;
Murali Nalajalaa8c94c62010-03-05 20:24:30 +0530618
619 /* Check for bad block and erase only if block is not marked bad */
620 isbad = flash_nand_block_isbad(cmdlist, ptrlist, page);
621
622 if (isbad) {
623 dprintf(INFO, "skipping @ %d (bad block)\n", page >> 6);
624 return -1;
625 }
626
627 /* Erase block */
628 data[0] = NAND_CMD_BLOCK_ERASE;
629 data[1] = page;
630 data[2] = 0;
631 data[3] = 0 | 4; /* chipselect CS0 */
632 data[4] = 0 | 5; /* chipselect CS1 */
633 data[5] = 1;
634 data[6] = 0xeeeeeeee;
635 data[7] = 0xeeeeeeee;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800636 data[8] = CFG0 & (~(7 << 6)); /* CW_PER_PAGE = 0 */
Murali Nalajalaa8c94c62010-03-05 20:24:30 +0530637 data[9] = CFG1;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800638 data[10] = 0x00000A3C; /* adm_mux_data_ack_req_nc01 */
639 data[11] = 0x0000053C; /* adm_mux_cmd_ack_req_nc01 */
640 data[12] = 0x00000F28; /* adm_mux_data_ack_req_nc10 */
641 data[13] = 0x00000F14; /* adm_mux_cmd_ack_req_nc10 */
642 data[14] = 0x00000FC0; /* adm_default_mux */
Murali Nalajalaa8c94c62010-03-05 20:24:30 +0530643 data[15] = 0x00000805; /* enable CS1 */
644 data[16] = 0x00000801; /* disable CS1 */
645
646 /* enable CS1 */
647 cmd[0].cmd = 0 | CMD_OCB;
648 cmd[0].src = paddr(data[15]);
649 cmd[0].dst = EBI2_CHIP_SELECT_CFG0;
650 cmd[0].len = 4;
651
652 /* Reading last code word from NC01 */
653 /* 0xF14 */
654 cmd[1].cmd = 0;
655 cmd[1].src = paddr(data[13]);
656 cmd[1].dst = EBI2_NAND_ADM_MUX;
657 cmd[1].len = 4;
658
659 cmd[2].cmd = DST_CRCI_NAND_CMD;
660 cmd[2].src = paddr(&data[0]);
661 cmd[2].dst = NC01(NAND_FLASH_CMD);
662 cmd[2].len = 16;
663
664 cmd[3].cmd = 0;
665 cmd[3].src = paddr(&data[8]);
666 cmd[3].dst = NC01(NAND_DEV0_CFG0);
667 cmd[3].len = 8;
668
669 cmd[4].cmd = 0;
670 cmd[4].src = paddr(&data[5]);
671 cmd[4].dst = NC01(NAND_EXEC_CMD);
672 cmd[4].len = 4;
673
674 /* 0xF28 */
675 cmd[5].cmd = 0;
676 cmd[5].src = paddr(data[12]);
677 cmd[5].dst = EBI2_NAND_ADM_MUX;
678 cmd[5].len = 4;
679
680 cmd[6].cmd = SRC_CRCI_NAND_DATA;
681 cmd[6].src = NC01(NAND_FLASH_STATUS);
682 cmd[6].dst = paddr(&data[6]);
683 cmd[6].len = 4;
684
685 /* Reading last code word from NC10 */
686 /* 0x53C */
687 cmd[7].cmd = 0;
688 cmd[7].src = paddr(data[11]);
689 cmd[7].dst = EBI2_NAND_ADM_MUX;
690 cmd[7].len = 4;
691
692 cmd[8].cmd = DST_CRCI_NAND_CMD;
693 cmd[8].src = paddr(&data[0]);
694 cmd[8].dst = NC10(NAND_FLASH_CMD);
695 cmd[8].len = 12;
696
697 cmd[9].cmd = 0;
698 cmd[9].src = paddr(&data[4]);
699 cmd[9].dst = NC10(NAND_FLASH_CHIP_SELECT);
700 cmd[9].len = 4;
701
702 cmd[10].cmd = 0;
703 cmd[10].src = paddr(&data[8]);
704 cmd[10].dst = NC10(NAND_DEV1_CFG0);
705 cmd[10].len = 8;
706
707 cmd[11].cmd = 0;
708 cmd[11].src = paddr(&data[5]);
709 cmd[11].dst = NC10(NAND_EXEC_CMD);
710 cmd[11].len = 4;
711
712 /* 0xA3C */
713 cmd[12].cmd = 0;
714 cmd[12].src = paddr(data[10]);
715 cmd[12].dst = EBI2_NAND_ADM_MUX;
716 cmd[12].len = 4;
717
718 cmd[13].cmd = SRC_CRCI_NAND_DATA;
719 cmd[13].src = NC10(NAND_FLASH_STATUS);
720 cmd[13].dst = paddr(&data[7]);
721 cmd[13].len = 4;
722
723 /* adm default mux state */
724 /* 0xFCO */
725 cmd[14].cmd = 0;
726 cmd[14].src = paddr(data[14]);
727 cmd[14].dst = EBI2_NAND_ADM_MUX;
728 cmd[14].len = 4;
729
730 /* disable CS1 */
731 cmd[15].cmd = CMD_OCU | CMD_LC;
732 cmd[15].src = paddr(data[16]);
733 cmd[15].dst = EBI2_CHIP_SELECT_CFG0;
734 cmd[15].len = 4;
735
736 ptr[0] = (paddr(cmd) >> 3) | CMD_PTR_LP;
737
738 dmov_exec_cmdptr(DMOV_NAND_CHAN, ptr);
739
740#if VERBOSE
741 dprintf(INFO, "NC01 status: %x\n", data[6]);
742 dprintf(INFO, "NC10 status: %x\n", data[7]);
743#endif
744
745 /* we fail if there was an operation error, a mpu error, or the
746 ** erase success bit was not set.
747 */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800748 if (data[6] & 0x110 || data[7] & 0x110)
749 return -1;
750 if (!(data[6] & 0x80) || !(data[7] & 0x80))
751 return -1;
Murali Nalajalaa8c94c62010-03-05 20:24:30 +0530752
753 return 0;
754}
755
Dima Zavin03cf4312009-01-23 16:38:30 -0800756struct data_flash_io {
757 unsigned cmd;
758 unsigned addr0;
759 unsigned addr1;
760 unsigned chipsel;
761 unsigned cfg0;
762 unsigned cfg1;
Channagoud Kadabi404a7062011-03-21 19:27:50 +0530763 unsigned ecc_bch_cfg;
Dima Zavin03cf4312009-01-23 16:38:30 -0800764 unsigned exec;
765 unsigned ecc_cfg;
766 unsigned ecc_cfg_save;
Murali Palnatic54d13a2010-01-15 19:50:19 +0530767 unsigned clrfstatus;
768 unsigned clrrstatus;
Dima Zavin03cf4312009-01-23 16:38:30 -0800769 struct {
770 unsigned flash_status;
771 unsigned buffer_status;
Shashank Mittaldcc2e352009-11-19 19:11:16 -0800772 } result[8];
Dima Zavin03cf4312009-01-23 16:38:30 -0800773};
774
Murali Nalajalaa8c94c62010-03-05 20:24:30 +0530775struct interleave_data_flash_io {
776 uint32_t cmd;
777 uint32_t addr0;
778 uint32_t addr1;
779 uint32_t chipsel_cs0;
780 uint32_t chipsel_cs1;
781 uint32_t cfg0;
782 uint32_t cfg1;
783 uint32_t exec;
784 uint32_t ecc_cfg;
785 uint32_t ecc_cfg_save;
786 uint32_t ebi2_chip_select_cfg0;
787 uint32_t adm_mux_data_ack_req_nc01;
788 uint32_t adm_mux_cmd_ack_req_nc01;
789 uint32_t adm_mux_data_ack_req_nc10;
790 uint32_t adm_mux_cmd_ack_req_nc10;
791 uint32_t adm_default_mux;
792 uint32_t default_ebi2_chip_select_cfg0;
793 struct {
794 uint32_t flash_status;
795 } result[16];
796};
797
Ajay Dudanib01e5062011-12-03 23:23:42 -0800798static int
799_flash_nand_read_page(dmov_s * cmdlist, unsigned *ptrlist,
800 unsigned page, void *_addr, void *_spareaddr)
Dima Zavin03cf4312009-01-23 16:38:30 -0800801{
802 dmov_s *cmd = cmdlist;
803 unsigned *ptr = ptrlist;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800804 struct data_flash_io *data = (void *)(ptrlist + 4);
805 unsigned addr = (unsigned)_addr;
806 unsigned spareaddr = (unsigned)_spareaddr;
Dima Zavin03cf4312009-01-23 16:38:30 -0800807 unsigned n;
Shashank Mittalad3d05c2009-11-19 15:53:57 -0800808 int isbad = 0;
Shashank Mittaldcc2e352009-11-19 19:11:16 -0800809 unsigned cwperpage;
Channagoud Kadabib2fb6ba2011-07-29 19:19:01 +0530810 unsigned block = 0;
Shashank Mittaldcc2e352009-11-19 19:11:16 -0800811 cwperpage = (flash_pagesize >> 9);
Shashank Mittalad3d05c2009-11-19 15:53:57 -0800812
Channagoud Kadabib2fb6ba2011-07-29 19:19:01 +0530813 /* Find the block no for the page */
814 block = page / num_pages_per_blk;
815
816 /* Check the bad block table for each block
817 * -1: indicates the block needs to be checked if good or bad
818 * 1 : The block is bad
819 * 0 : The block is good
820 */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800821 if (bbtbl[block] == -1) {
Channagoud Kadabib2fb6ba2011-07-29 19:19:01 +0530822 isbad = flash_nand_block_isbad(cmdlist, ptrlist, page);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800823 if (isbad) {
Channagoud Kadabib2fb6ba2011-07-29 19:19:01 +0530824 /* Found bad , set the bad table entry */
825 bbtbl[block] = 1;
826 return -2;
827 } else {
828 /* Found good block , set the table entry &
Ajay Dudanib01e5062011-12-03 23:23:42 -0800829 * continue reading the data
830 */
Channagoud Kadabib2fb6ba2011-07-29 19:19:01 +0530831 bbtbl[block] = 0;
832 }
Ajay Dudanib01e5062011-12-03 23:23:42 -0800833 } else if (bbtbl[block] == 1) {
834 /* If the block is already identified as bad, return error */
Shashank Mittalad3d05c2009-11-19 15:53:57 -0800835 return -2;
Channagoud Kadabib2fb6ba2011-07-29 19:19:01 +0530836 }
Dima Zavin03cf4312009-01-23 16:38:30 -0800837
838 data->cmd = NAND_CMD_PAGE_READ_ECC;
839 data->addr0 = page << 16;
840 data->addr1 = (page >> 16) & 0xff;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800841 data->chipsel = 0 | 4; /* flash0 + undoc bit */
Dima Zavin03cf4312009-01-23 16:38:30 -0800842
843 /* GO bit for the EXEC register */
844 data->exec = 1;
845
846 data->cfg0 = CFG0;
847 data->cfg1 = CFG1;
848
Channagoud Kadabi404a7062011-03-21 19:27:50 +0530849 if (enable_bch_ecc) {
850 data->ecc_bch_cfg = ECC_BCH_CFG;
851 }
Dima Zavin03cf4312009-01-23 16:38:30 -0800852 data->ecc_cfg = 0x203;
853
854 /* save existing ecc config */
855 cmd->cmd = CMD_OCB;
856 cmd->src = NAND_EBI2_ECC_BUF_CFG;
857 cmd->dst = paddr(&data->ecc_cfg_save);
858 cmd->len = 4;
859 cmd++;
860
Ajay Dudanib01e5062011-12-03 23:23:42 -0800861 for (n = 0; n < cwperpage; n++) {
Dima Zavin03cf4312009-01-23 16:38:30 -0800862 /* write CMD / ADDR0 / ADDR1 / CHIPSEL regs in a burst */
863 cmd->cmd = DST_CRCI_NAND_CMD;
864 cmd->src = paddr(&data->cmd);
865 cmd->dst = NAND_FLASH_CMD;
866 cmd->len = ((n == 0) ? 16 : 4);
867 cmd++;
868
869 if (n == 0) {
870 /* block on cmd ready, set configuration */
871 cmd->cmd = 0;
872 cmd->src = paddr(&data->cfg0);
873 cmd->dst = NAND_DEV0_CFG0;
Channagoud Kadabi404a7062011-03-21 19:27:50 +0530874 if (enable_bch_ecc) {
875 cmd->len = 12;
876 } else {
877 cmd->len = 8;
878 }
Dima Zavin03cf4312009-01-23 16:38:30 -0800879 cmd++;
880
881 /* set our ecc config */
882 cmd->cmd = 0;
883 cmd->src = paddr(&data->ecc_cfg);
884 cmd->dst = NAND_EBI2_ECC_BUF_CFG;
885 cmd->len = 4;
886 cmd++;
887 }
888 /* kick the execute register */
889 cmd->cmd = 0;
890 cmd->src = paddr(&data->exec);
891 cmd->dst = NAND_EXEC_CMD;
892 cmd->len = 4;
893 cmd++;
894
895 /* block on data ready, then read the status register */
896 cmd->cmd = SRC_CRCI_NAND_DATA;
897 cmd->src = NAND_FLASH_STATUS;
898 cmd->dst = paddr(&data->result[n]);
899 cmd->len = 8;
900 cmd++;
901
902 /* read data block */
903 cmd->cmd = 0;
904 cmd->src = NAND_FLASH_BUFFER;
905 cmd->dst = addr + n * 516;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800906 cmd->len =
907 ((n <
908 (cwperpage - 1)) ? 516 : (512 - ((cwperpage - 1) << 2)));
Dima Zavin03cf4312009-01-23 16:38:30 -0800909 cmd++;
910 }
911
912 /* read extra data */
913 cmd->cmd = 0;
Channagoud Kadabi404a7062011-03-21 19:27:50 +0530914 cmd->src = NAND_FLASH_BUFFER + (512 - ((cwperpage - 1) << 2));
Dima Zavin03cf4312009-01-23 16:38:30 -0800915 cmd->dst = spareaddr;
916 cmd->len = 16;
917 cmd++;
918
919 /* restore saved ecc config */
920 cmd->cmd = CMD_OCU | CMD_LC;
921 cmd->src = paddr(&data->ecc_cfg_save);
922 cmd->dst = NAND_EBI2_ECC_BUF_CFG;
923 cmd->len = 4;
924
925 ptr[0] = (paddr(cmdlist) >> 3) | CMD_PTR_LP;
926
927 dmov_exec_cmdptr(DMOV_NAND_CHAN, ptr);
928
929#if VERBOSE
930 dprintf(INFO, "read page %d: status: %x %x %x %x\n",
931 page, data[5], data[6], data[7], data[8]);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800932 for (n = 0; n < 4; n++) {
933 ptr = (unsigned *)(addr + 512 * n);
934 dprintf(INFO, "data%d: %x %x %x %x\n", n, ptr[0], ptr[1],
935 ptr[2], ptr[3]);
936 ptr = (unsigned *)(spareaddr + 16 * n);
937 dprintf(INFO, "spare data%d %x %x %x %x\n", n, ptr[0],
938 ptr[1], ptr[2], ptr[3]);
Dima Zavin03cf4312009-01-23 16:38:30 -0800939 }
940#endif
941
942 /* if any of the writes failed (0x10), or there was a
943 ** protection violation (0x100), we lose
944 */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800945 for (n = 0; n < cwperpage; n++) {
Dima Zavin03cf4312009-01-23 16:38:30 -0800946 if (data->result[n].flash_status & 0x110) {
947 return -1;
948 }
949 }
950
951 return 0;
952}
953
Ajay Dudanib01e5062011-12-03 23:23:42 -0800954static int
955flash_nand_read_page_interleave(dmov_s * cmdlist, unsigned *ptrlist,
956 unsigned page, void *_addr, void *_spareaddr)
Murali Nalajalaa8c94c62010-03-05 20:24:30 +0530957{
958 dmov_s *cmd = cmdlist;
959 unsigned *ptr = ptrlist;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800960 struct interleave_data_flash_io *data = (void *)(ptrlist + 4);
961 unsigned addr = (unsigned)_addr;
962 unsigned spareaddr = (unsigned)_spareaddr;
Murali Nalajalaa8c94c62010-03-05 20:24:30 +0530963 unsigned n;
964 int isbad = 0;
965 unsigned cwperpage;
966 cwperpage = (flash_pagesize >> 9);
967
968 /* Check for bad block and read only from a good block */
969 isbad = flash_nand_block_isbad(cmdlist, ptrlist, page);
970 if (isbad)
971 return -2;
972
973 data->cmd = NAND_CMD_PAGE_READ_ECC;
974 data->addr0 = page << 16;
975 data->addr1 = (page >> 16) & 0xff;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800976 data->chipsel_cs0 = 0 | 4; /* flash0 + undoc bit */
977 data->chipsel_cs1 = 0 | 5; /* flash0 + undoc bit */
Murali Nalajalaa8c94c62010-03-05 20:24:30 +0530978 data->ebi2_chip_select_cfg0 = 0x00000805;
979 data->adm_mux_data_ack_req_nc01 = 0x00000A3C;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800980 data->adm_mux_cmd_ack_req_nc01 = 0x0000053C;
Murali Nalajalaa8c94c62010-03-05 20:24:30 +0530981 data->adm_mux_data_ack_req_nc10 = 0x00000F28;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800982 data->adm_mux_cmd_ack_req_nc10 = 0x00000F14;
Murali Nalajalaa8c94c62010-03-05 20:24:30 +0530983 data->adm_default_mux = 0x00000FC0;
984 data->default_ebi2_chip_select_cfg0 = 0x00000801;
985
986 /* GO bit for the EXEC register */
987 data->exec = 1;
988
989 data->cfg0 = CFG0;
990 data->cfg1 = CFG1;
991
992 data->ecc_cfg = 0x203;
993
994 for (n = 0; n < cwperpage; n++) {
995 /* flash + buffer status return words */
996 data->result[n].flash_status = 0xeeeeeeee;
997
998 if (n == 0) {
999 /* enable CS1 */
1000 cmd->cmd = CMD_OCB;
1001 cmd->src = paddr(&data->ebi2_chip_select_cfg0);
1002 cmd->dst = EBI2_CHIP_SELECT_CFG0;
1003 cmd->len = 4;
1004 cmd++;
1005
1006 /* save existing ecc config */
1007 cmd->cmd = 0;
1008 cmd->src = NAND_EBI2_ECC_BUF_CFG;
1009 cmd->dst = paddr(&data->ecc_cfg_save);
1010 cmd->len = 4;
1011 cmd++;
1012
1013 /* NC01, NC10 --> ADDR0/ADDR1 */
1014 cmd->cmd = 0;
1015 cmd->src = paddr(&data->addr0);
1016 cmd->dst = NC11(NAND_ADDR0);
1017 cmd->len = 8;
1018 cmd++;
1019
1020 /* Select the CS0,
1021 * for NC01!
1022 */
1023 cmd->cmd = 0;
1024 cmd->src = paddr(&data->chipsel_cs0);
1025 cmd->dst = NC01(NAND_FLASH_CHIP_SELECT);
1026 cmd->len = 4;
1027 cmd++;
1028
1029 /* Select the CS1,
1030 * for NC10!
1031 */
1032 cmd->cmd = 0;
Ajay Dudanib01e5062011-12-03 23:23:42 -08001033 cmd->src = paddr(&data->chipsel_cs1);
Murali Nalajalaa8c94c62010-03-05 20:24:30 +05301034 cmd->dst = NC10(NAND_FLASH_CHIP_SELECT);
1035 cmd->len = 4;
1036 cmd++;
1037
1038 cmd->cmd = 0;
1039 cmd->src = paddr(&data->cfg0);
1040 cmd->dst = NC01(NAND_DEV0_CFG0);
1041 cmd->len = 8;
1042 cmd++;
1043
1044 /* config DEV1 for CS1 */
1045 cmd->cmd = 0;
1046 cmd->src = paddr(&data->cfg0);
1047 cmd->dst = NC10(NAND_DEV1_CFG0);
1048 cmd->len = 8;
1049 cmd++;
1050
1051 cmd->cmd = 0;
1052 cmd->src = paddr(&data->ecc_cfg);
1053 cmd->dst = NC11(NAND_EBI2_ECC_BUF_CFG);
1054 cmd->len = 4;
1055 cmd++;
1056
1057 /* if 'only' the last code word */
1058 if (n == cwperpage - 1) {
Ajay Dudanib01e5062011-12-03 23:23:42 -08001059 /* MASK CMD ACK/REQ --> NC01 (0x53C) */
Murali Nalajalaa8c94c62010-03-05 20:24:30 +05301060 cmd->cmd = 0;
Ajay Dudanib01e5062011-12-03 23:23:42 -08001061 cmd->src =
1062 paddr(&data->adm_mux_cmd_ack_req_nc01);
Murali Nalajalaa8c94c62010-03-05 20:24:30 +05301063 cmd->dst = EBI2_NAND_ADM_MUX;
1064 cmd->len = 4;
1065 cmd++;
1066
1067 /* CMD */
1068 cmd->cmd = DST_CRCI_NAND_CMD;
1069 cmd->src = paddr(&data->cmd);
1070 cmd->dst = NC10(NAND_FLASH_CMD);
1071 cmd->len = 4;
1072 cmd++;
1073
1074 /* kick the execute register for NC10 */
1075 cmd->cmd = 0;
1076 cmd->src = paddr(&data->exec);
1077 cmd->dst = NC10(NAND_EXEC_CMD);
1078 cmd->len = 4;
1079 cmd++;
1080
Ajay Dudanib01e5062011-12-03 23:23:42 -08001081 /* MASK DATA ACK/REQ --> NC01 (0xA3C) */
Murali Nalajalaa8c94c62010-03-05 20:24:30 +05301082 cmd->cmd = 0;
Ajay Dudanib01e5062011-12-03 23:23:42 -08001083 cmd->src =
1084 paddr(&data->adm_mux_data_ack_req_nc01);
Murali Nalajalaa8c94c62010-03-05 20:24:30 +05301085 cmd->dst = EBI2_NAND_ADM_MUX;
1086 cmd->len = 4;
1087 cmd++;
1088
1089 /* block on data ready from NC10, then
1090 * read the status register
1091 */
1092 cmd->cmd = SRC_CRCI_NAND_DATA;
1093 cmd->src = NC10(NAND_FLASH_STATUS);
1094 cmd->dst = paddr(&data->result[n]);
1095 /* NAND_FLASH_STATUS +
1096 * NAND_BUFFER_STATUS
1097 */
1098 cmd->len = 4;
1099 cmd++;
1100 } else {
Ajay Dudanib01e5062011-12-03 23:23:42 -08001101 /* MASK CMD ACK/REQ --> NC10 (0xF14) */
Murali Nalajalaa8c94c62010-03-05 20:24:30 +05301102 cmd->cmd = 0;
Ajay Dudanib01e5062011-12-03 23:23:42 -08001103 cmd->src =
1104 paddr(&data->adm_mux_cmd_ack_req_nc10);
Murali Nalajalaa8c94c62010-03-05 20:24:30 +05301105 cmd->dst = EBI2_NAND_ADM_MUX;
1106 cmd->len = 4;
1107 cmd++;
1108
1109 /* CMD */
1110 cmd->cmd = DST_CRCI_NAND_CMD;
1111 cmd->src = paddr(&data->cmd);
1112 cmd->dst = NC01(NAND_FLASH_CMD);
1113 cmd->len = 4;
1114 cmd++;
1115
Ajay Dudanib01e5062011-12-03 23:23:42 -08001116 /* kick the execute register for NC01 */
Murali Nalajalaa8c94c62010-03-05 20:24:30 +05301117 cmd->cmd = 0;
1118 cmd->src = paddr(&data->exec);
1119 cmd->dst = NC01(NAND_EXEC_CMD);
1120 cmd->len = 4;
1121 cmd++;
1122 }
1123 }
1124
Murali Nalajalaa8c94c62010-03-05 20:24:30 +05301125 if (n % 2 == 0) {
Ajay Dudanib01e5062011-12-03 23:23:42 -08001126 /* MASK CMD ACK/REQ --> NC01 (0x53C) */
Murali Nalajalaa8c94c62010-03-05 20:24:30 +05301127 cmd->cmd = 0;
1128 cmd->src = paddr(&data->adm_mux_cmd_ack_req_nc01);
1129 cmd->dst = EBI2_NAND_ADM_MUX;
1130 cmd->len = 4;
1131 cmd++;
1132
1133 /* CMD */
1134 cmd->cmd = DST_CRCI_NAND_CMD;
1135 cmd->src = paddr(&data->cmd);
1136 cmd->dst = NC10(NAND_FLASH_CMD);
1137 cmd->len = 4;
1138 cmd++;
1139
1140 /* kick the execute register for NC10 */
1141 cmd->cmd = 0;
1142 cmd->src = paddr(&data->exec);
1143 cmd->dst = NC10(NAND_EXEC_CMD);
1144 cmd->len = 4;
1145 cmd++;
1146
Ajay Dudanib01e5062011-12-03 23:23:42 -08001147 /* MASK DATA ACK/REQ --> NC10 (0xF28) */
Murali Nalajalaa8c94c62010-03-05 20:24:30 +05301148 cmd->cmd = 0;
1149 cmd->src = paddr(&data->adm_mux_data_ack_req_nc10);
1150 cmd->dst = EBI2_NAND_ADM_MUX;
1151 cmd->len = 4;
1152 cmd++;
1153
1154 /* block on data ready from NC01, then
1155 * read the status register
1156 */
1157 cmd->cmd = SRC_CRCI_NAND_DATA;
1158 cmd->src = NC01(NAND_FLASH_STATUS);
1159 cmd->dst = paddr(&data->result[n]);
1160 /* NAND_FLASH_STATUS +
1161 * NAND_BUFFER_STATUS
1162 */
1163 cmd->len = 4;
1164 cmd++;
1165
1166 /* read data block */
1167 cmd->cmd = 0;
1168 cmd->src = NC01(NAND_FLASH_BUFFER);
1169 cmd->dst = addr + n * 516;
Ajay Dudanib01e5062011-12-03 23:23:42 -08001170 cmd->len =
1171 ((n <
1172 (cwperpage - 1)) ? 516 : (512 -
1173 ((cwperpage -
1174 1) << 2)));
Murali Nalajalaa8c94c62010-03-05 20:24:30 +05301175 cmd++;
1176 } else {
1177 if (n != cwperpage - 1) {
1178 /* MASK CMD ACK/REQ -->
1179 * NC10 (0xF14)
1180 */
1181 cmd->cmd = 0;
Ajay Dudanib01e5062011-12-03 23:23:42 -08001182 cmd->src =
1183 paddr(&data->adm_mux_cmd_ack_req_nc10);
Murali Nalajalaa8c94c62010-03-05 20:24:30 +05301184 cmd->dst = EBI2_NAND_ADM_MUX;
1185 cmd->len = 4;
1186 cmd++;
1187
1188 /* CMD */
1189 cmd->cmd = DST_CRCI_NAND_CMD;
1190 cmd->src = paddr(&data->cmd);
1191 cmd->dst = NC01(NAND_FLASH_CMD);
1192 cmd->len = 4;
1193 cmd++;
1194
1195 /* EXEC */
1196 cmd->cmd = 0;
1197 cmd->src = paddr(&data->exec);
1198 cmd->dst = NC01(NAND_EXEC_CMD);
1199 cmd->len = 4;
1200 cmd++;
1201
1202 /* MASK DATA ACK/REQ -->
1203 * NC01 (0xA3C)
1204 */
1205 cmd->cmd = 0;
Ajay Dudanib01e5062011-12-03 23:23:42 -08001206 cmd->src =
1207 paddr(&data->adm_mux_data_ack_req_nc01);
Murali Nalajalaa8c94c62010-03-05 20:24:30 +05301208 cmd->dst = EBI2_NAND_ADM_MUX;
1209 cmd->len = 4;
1210 cmd++;
1211
1212 /* block on data ready from NC10
1213 * then read the status register
1214 */
1215 cmd->cmd = SRC_CRCI_NAND_DATA;
1216 cmd->src = NC10(NAND_FLASH_STATUS);
1217 cmd->dst = paddr(&data->result[n]);
1218 /* NAND_FLASH_STATUS +
1219 * NAND_BUFFER_STATUS
1220 */
1221 cmd->len = 4;
1222 cmd++;
1223 } else {
1224 /* MASK DATA ACK/REQ ->
1225 * NC01 (0xA3C)
1226 */
1227 cmd->cmd = 0;
Ajay Dudanib01e5062011-12-03 23:23:42 -08001228 cmd->src =
1229 paddr(&data->adm_mux_data_ack_req_nc01);
Murali Nalajalaa8c94c62010-03-05 20:24:30 +05301230 cmd->dst = EBI2_NAND_ADM_MUX;
1231 cmd->len = 4;
1232 cmd++;
1233
1234 /* block on data ready from NC10
1235 * then read the status register
1236 */
1237 cmd->cmd = SRC_CRCI_NAND_DATA;
1238 cmd->src = NC10(NAND_FLASH_STATUS);
1239 cmd->dst = paddr(&data->result[n]);
1240 /* NAND_FLASH_STATUS +
1241 * NAND_BUFFER_STATUS
1242 */
1243 cmd->len = 4;
1244 cmd++;
1245 }
1246 /* read data block */
1247 cmd->cmd = 0;
1248 cmd->src = NC10(NAND_FLASH_BUFFER);
1249 cmd->dst = addr + n * 516;
Ajay Dudanib01e5062011-12-03 23:23:42 -08001250 cmd->len =
1251 ((n <
1252 (cwperpage - 1)) ? 516 : (512 -
1253 ((cwperpage -
1254 1) << 2)));
Murali Nalajalaa8c94c62010-03-05 20:24:30 +05301255 cmd++;
1256
1257 if (n == (cwperpage - 1)) {
1258 /* Use NC10 for reading the
1259 * last codeword!!!
1260 */
1261 cmd->cmd = 0;
1262 cmd->src = NC10(NAND_FLASH_BUFFER) +
Ajay Dudanib01e5062011-12-03 23:23:42 -08001263 (512 - ((cwperpage - 1) << 2));
Murali Nalajalaa8c94c62010-03-05 20:24:30 +05301264 cmd->dst = spareaddr;
1265 cmd->len = 16;
1266 cmd++;
1267 }
1268 }
1269 }
1270 /* restore saved ecc config */
1271 cmd->cmd = CMD_OCU | CMD_LC;
1272 cmd->src = paddr(&data->ecc_cfg_save);
1273 cmd->dst = NAND_EBI2_ECC_BUF_CFG;
1274 cmd->len = 4;
1275
1276 /* ADM --> Default mux state (0xFC0) */
1277 cmd->cmd = 0;
1278 cmd->src = paddr(&data->adm_default_mux);
1279 cmd->dst = EBI2_NAND_ADM_MUX;
1280 cmd->len = 4;
1281 cmd++;
1282
1283 /* disable CS1 */
1284 cmd->cmd = 0;
Ajay Dudanib01e5062011-12-03 23:23:42 -08001285 cmd->src = paddr(&data->default_ebi2_chip_select_cfg0);
Murali Nalajalaa8c94c62010-03-05 20:24:30 +05301286 cmd->dst = EBI2_CHIP_SELECT_CFG0;
1287 cmd->len = 4;
1288 cmd++;
1289
1290 ptr[0] = (paddr(cmdlist) >> 3) | CMD_PTR_LP;
1291
1292 dmov_exec_cmdptr(DMOV_NAND_CHAN, ptr);
1293
1294#if VERBOSE
1295 dprintf(INFO, "read page %d: status: %x %x %x %x %x %x %x %x \
Ajay Dudanib01e5062011-12-03 23:23:42 -08001296 %x %x %x %x %x %x %x %x \n", page, data->result[0].flash_status[0], data->result[1].flash_status[1], data->result[2].flash_status[2], data->result[3].flash_status[3], data->result[4].flash_status[4], data->result[5].flash_status[5], data->result[6].flash_status[6], data->result[7].flash_status[7], data->result[8].flash_status[8], data->result[9].flash_status[9], data->result[10].flash_status[10], data->result[11].flash_status[11], data->result[12].flash_status[12], data->result[13].flash_status[13], data->result[14].flash_status[14], data->result[15].flash_status[15]);
Murali Nalajalaa8c94c62010-03-05 20:24:30 +05301297
Ajay Dudanib01e5062011-12-03 23:23:42 -08001298 for (n = 0; n < 4; n++) {
1299 ptr = (unsigned *)(addr + 512 * n);
1300 dprintf(INFO, "data%d: %x %x %x %x\n", n, ptr[0], ptr[1],
1301 ptr[2], ptr[3]);
1302 ptr = (unsigned *)(spareaddr + 16 * n);
1303 dprintf(INFO, "spare data%d %x %x %x %x\n", n, ptr[0],
1304 ptr[1], ptr[2], ptr[3]);
Murali Nalajalaa8c94c62010-03-05 20:24:30 +05301305 }
1306#endif
1307
1308 /* if any of the writes failed (0x10), or there was a
1309 ** protection violation (0x100), we lose
1310 */
Ajay Dudanib01e5062011-12-03 23:23:42 -08001311 for (n = 0; n < cwperpage; n++) {
Murali Nalajalaa8c94c62010-03-05 20:24:30 +05301312 if (data->result[n].flash_status & 0x110) {
1313 return -1;
1314 }
1315 }
1316
1317 return 0;
1318}
1319
Ajay Dudanib01e5062011-12-03 23:23:42 -08001320static int
1321_flash_nand_write_page(dmov_s * cmdlist, unsigned *ptrlist, unsigned page,
1322 const void *_addr, const void *_spareaddr,
1323 unsigned raw_mode)
Dima Zavin03cf4312009-01-23 16:38:30 -08001324{
1325 dmov_s *cmd = cmdlist;
1326 unsigned *ptr = ptrlist;
Ajay Dudanib01e5062011-12-03 23:23:42 -08001327 struct data_flash_io *data = (void *)(ptrlist + 4);
1328 unsigned addr = (unsigned)_addr;
1329 unsigned spareaddr = (unsigned)_spareaddr;
Shashank Mittalc20b5a12009-11-18 19:35:30 -08001330 unsigned n;
Shashank Mittaldcc2e352009-11-19 19:11:16 -08001331 unsigned cwperpage;
1332 cwperpage = (flash_pagesize >> 9);
Shashank Mittal8e49dec2010-03-01 15:19:04 -08001333 unsigned modem_partition = 0;
Ajay Dudanib01e5062011-12-03 23:23:42 -08001334 if (CFG0 == CFG0_M) {
Shashank Mittal8e49dec2010-03-01 15:19:04 -08001335 modem_partition = 1;
1336 }
Dima Zavin03cf4312009-01-23 16:38:30 -08001337
1338 data->cmd = NAND_CMD_PRG_PAGE;
1339 data->addr0 = page << 16;
1340 data->addr1 = (page >> 16) & 0xff;
Ajay Dudanib01e5062011-12-03 23:23:42 -08001341 data->chipsel = 0 | 4; /* flash0 + undoc bit */
Murali Palnatic54d13a2010-01-15 19:50:19 +05301342 data->clrfstatus = 0x00000020;
1343 data->clrrstatus = 0x000000C0;
Dima Zavin03cf4312009-01-23 16:38:30 -08001344
Ajay Dudanib01e5062011-12-03 23:23:42 -08001345 if (!raw_mode) {
Shashank Mittald0c836d2009-11-20 10:31:18 -08001346 data->cfg0 = CFG0;
1347 data->cfg1 = CFG1;
Channagoud Kadabi404a7062011-03-21 19:27:50 +05301348 if (enable_bch_ecc) {
1349 data->ecc_bch_cfg = ECC_BCH_CFG;
1350 }
Ajay Dudanib01e5062011-12-03 23:23:42 -08001351 } else {
1352 data->cfg0 =
1353 (NAND_CFG0_RAW & ~(7 << 6)) | ((cwperpage - 1) << 6);
Shashank Mittald0c836d2009-11-20 10:31:18 -08001354 data->cfg1 = NAND_CFG1_RAW | (CFG1 & CFG1_WIDE_FLASH);
1355 }
Dima Zavin03cf4312009-01-23 16:38:30 -08001356
1357 /* GO bit for the EXEC register */
1358 data->exec = 1;
1359
Shashank Mittal8e49dec2010-03-01 15:19:04 -08001360 if (modem_partition)
1361 data->ecc_cfg = 0x1FF;
1362 else
1363 data->ecc_cfg = 0x203;
Dima Zavin03cf4312009-01-23 16:38:30 -08001364
1365 /* save existing ecc config */
1366 cmd->cmd = CMD_OCB;
1367 cmd->src = NAND_EBI2_ECC_BUF_CFG;
1368 cmd->dst = paddr(&data->ecc_cfg_save);
1369 cmd->len = 4;
1370 cmd++;
1371
Ajay Dudanib01e5062011-12-03 23:23:42 -08001372 for (n = 0; n < cwperpage; n++) {
1373 /* write CMD / ADDR0 / ADDR1 / CHIPSEL regs in a burst */
Dima Zavin03cf4312009-01-23 16:38:30 -08001374 cmd->cmd = DST_CRCI_NAND_CMD;
1375 cmd->src = paddr(&data->cmd);
1376 cmd->dst = NAND_FLASH_CMD;
1377 cmd->len = ((n == 0) ? 16 : 4);
1378 cmd++;
1379
1380 if (n == 0) {
1381 /* set configuration */
1382 cmd->cmd = 0;
1383 cmd->src = paddr(&data->cfg0);
1384 cmd->dst = NAND_DEV0_CFG0;
Channagoud Kadabi404a7062011-03-21 19:27:50 +05301385 if (enable_bch_ecc) {
1386 cmd->len = 12;
1387 } else {
1388 cmd->len = 8;
1389 }
1390
Dima Zavin03cf4312009-01-23 16:38:30 -08001391 cmd++;
1392
1393 /* set our ecc config */
1394 cmd->cmd = 0;
1395 cmd->src = paddr(&data->ecc_cfg);
1396 cmd->dst = NAND_EBI2_ECC_BUF_CFG;
1397 cmd->len = 4;
1398 cmd++;
1399 }
1400
1401 /* write data block */
1402 cmd->cmd = 0;
Dima Zavin03cf4312009-01-23 16:38:30 -08001403 cmd->dst = NAND_FLASH_BUFFER;
Ajay Dudanib01e5062011-12-03 23:23:42 -08001404 if (!raw_mode) {
1405 if (modem_partition) {
Shashank Mittal8e49dec2010-03-01 15:19:04 -08001406 cmd->src = addr + n * 512;
1407 cmd->len = 512;
Ajay Dudanib01e5062011-12-03 23:23:42 -08001408 } else {
Shashank Mittal8e49dec2010-03-01 15:19:04 -08001409 cmd->src = addr + n * 516;
Ajay Dudanib01e5062011-12-03 23:23:42 -08001410 cmd->len =
1411 ((n <
1412 (cwperpage - 1)) ? 516 : (512 -
1413 ((cwperpage -
1414 1) << 2)));
Shashank Mittal8e49dec2010-03-01 15:19:04 -08001415 }
Ajay Dudanib01e5062011-12-03 23:23:42 -08001416 } else {
Shashank Mittald0c836d2009-11-20 10:31:18 -08001417 cmd->src = addr;
Ajay Dudanib01e5062011-12-03 23:23:42 -08001418 cmd->len = 528;
Shashank Mittald0c836d2009-11-20 10:31:18 -08001419 }
Dima Zavin03cf4312009-01-23 16:38:30 -08001420 cmd++;
1421
Shashank Mittal8e49dec2010-03-01 15:19:04 -08001422 if ((n == (cwperpage - 1)) && (!raw_mode) && (!modem_partition)) {
Dima Zavin03cf4312009-01-23 16:38:30 -08001423 /* write extra data */
1424 cmd->cmd = 0;
1425 cmd->src = spareaddr;
Ajay Dudanib01e5062011-12-03 23:23:42 -08001426 cmd->dst =
1427 NAND_FLASH_BUFFER + (512 - ((cwperpage - 1) << 2));
Shashank Mittaldcc2e352009-11-19 19:11:16 -08001428 cmd->len = (cwperpage << 2);
Dima Zavin03cf4312009-01-23 16:38:30 -08001429 cmd++;
1430 }
1431
1432 /* kick the execute register */
1433 cmd->cmd = 0;
1434 cmd->src = paddr(&data->exec);
1435 cmd->dst = NAND_EXEC_CMD;
1436 cmd->len = 4;
1437 cmd++;
1438
1439 /* block on data ready, then read the status register */
1440 cmd->cmd = SRC_CRCI_NAND_DATA;
1441 cmd->src = NAND_FLASH_STATUS;
1442 cmd->dst = paddr(&data->result[n]);
1443 cmd->len = 8;
1444 cmd++;
Murali Palnatic54d13a2010-01-15 19:50:19 +05301445
1446 cmd->cmd = 0;
1447 cmd->src = paddr(&data->clrfstatus);
1448 cmd->dst = NAND_FLASH_STATUS;
1449 cmd->len = 4;
1450 cmd++;
1451
1452 cmd->cmd = 0;
1453 cmd->src = paddr(&data->clrrstatus);
1454 cmd->dst = NAND_READ_STATUS;
1455 cmd->len = 4;
1456 cmd++;
Dima Zavin03cf4312009-01-23 16:38:30 -08001457 }
1458
1459 /* restore saved ecc config */
1460 cmd->cmd = CMD_OCU | CMD_LC;
1461 cmd->src = paddr(&data->ecc_cfg_save);
1462 cmd->dst = NAND_EBI2_ECC_BUF_CFG;
1463 cmd->len = 4;
1464
1465 ptr[0] = (paddr(cmdlist) >> 3) | CMD_PTR_LP;
1466
1467 dmov_exec_cmdptr(DMOV_NAND_CHAN, ptr);
1468
1469#if VERBOSE
1470 dprintf(INFO, "write page %d: status: %x %x %x %x\n",
1471 page, data[5], data[6], data[7], data[8]);
1472#endif
1473
1474 /* if any of the writes failed (0x10), or there was a
1475 ** protection violation (0x100), or the program success
1476 ** bit (0x80) is unset, we lose
1477 */
Ajay Dudanib01e5062011-12-03 23:23:42 -08001478 for (n = 0; n < cwperpage; n++) {
1479 if (data->result[n].flash_status & 0x110)
1480 return -1;
1481 if (!(data->result[n].flash_status & 0x80))
1482 return -1;
Dima Zavin03cf4312009-01-23 16:38:30 -08001483 }
1484
Dima Zavin5582c7d2009-03-03 15:17:59 -08001485#if VERIFY_WRITE
1486 n = _flash_read_page(cmdlist, ptrlist, page, flash_data,
Ajay Dudanib01e5062011-12-03 23:23:42 -08001487 flash_data + 2048);
Dima Zavin5582c7d2009-03-03 15:17:59 -08001488 if (n != 0)
1489 return -1;
1490 if (memcmp(flash_data, _addr, 2048) ||
Ajay Dudanib01e5062011-12-03 23:23:42 -08001491 memcmp(flash_data + 2048, _spareaddr, 16)) {
Dima Zavin5582c7d2009-03-03 15:17:59 -08001492 dprintf(CRITICAL, "verify error @ page %d\n", page);
1493 return -1;
1494 }
1495#endif
Dima Zavin03cf4312009-01-23 16:38:30 -08001496 return 0;
1497}
Murali Nalajalaa8c94c62010-03-05 20:24:30 +05301498
Ajay Dudanib01e5062011-12-03 23:23:42 -08001499static int
1500flash_nand_write_page_interleave(dmov_s * cmdlist, unsigned *ptrlist,
1501 unsigned page, const void *_addr,
1502 const void *_spareaddr, unsigned raw_mode)
Murali Nalajalaa8c94c62010-03-05 20:24:30 +05301503{
1504 dmov_s *cmd = cmdlist;
1505 unsigned *ptr = ptrlist;
Ajay Dudanib01e5062011-12-03 23:23:42 -08001506 struct interleave_data_flash_io *data = (void *)(ptrlist + 4);
1507 unsigned addr = (unsigned)_addr;
1508 unsigned spareaddr = (unsigned)_spareaddr;
Murali Nalajalaa8c94c62010-03-05 20:24:30 +05301509 unsigned n;
1510 unsigned cwperpage, cwcount;
1511
Ajay Dudanib01e5062011-12-03 23:23:42 -08001512 cwperpage = (flash_pagesize >> 9) * 2; /* double for interleave mode */
Murali Nalajalaa8c94c62010-03-05 20:24:30 +05301513 cwcount = (cwperpage << 1);
1514
1515 data->cmd = NAND_CMD_PRG_PAGE;
1516 data->addr0 = page << 16;
1517 data->addr1 = (page >> 16) & 0xff;
Ajay Dudanib01e5062011-12-03 23:23:42 -08001518 data->chipsel_cs0 = 0 | 4; /* flash0 + undoc bit */
1519 data->chipsel_cs1 = 0 | 5; /* flash0 + undoc bit */
Murali Nalajalaa8c94c62010-03-05 20:24:30 +05301520 data->ebi2_chip_select_cfg0 = 0x00000805;
1521 data->adm_mux_data_ack_req_nc01 = 0x00000A3C;
Ajay Dudanib01e5062011-12-03 23:23:42 -08001522 data->adm_mux_cmd_ack_req_nc01 = 0x0000053C;
Murali Nalajalaa8c94c62010-03-05 20:24:30 +05301523 data->adm_mux_data_ack_req_nc10 = 0x00000F28;
Ajay Dudanib01e5062011-12-03 23:23:42 -08001524 data->adm_mux_cmd_ack_req_nc10 = 0x00000F14;
Murali Nalajalaa8c94c62010-03-05 20:24:30 +05301525 data->adm_default_mux = 0x00000FC0;
1526 data->default_ebi2_chip_select_cfg0 = 0x00000801;
1527
Ajay Dudanib01e5062011-12-03 23:23:42 -08001528 if (!raw_mode) {
Murali Nalajalaa8c94c62010-03-05 20:24:30 +05301529 data->cfg0 = CFG0;
1530 data->cfg1 = CFG1;
Ajay Dudanib01e5062011-12-03 23:23:42 -08001531 } else {
1532 data->cfg0 = (NAND_CFG0_RAW & ~(7 << 6)) | ((cwcount - 1) << 6);
Murali Nalajalaa8c94c62010-03-05 20:24:30 +05301533 data->cfg1 = NAND_CFG1_RAW | (CFG1 & CFG1_WIDE_FLASH);
1534 }
1535
1536 /* GO bit for the EXEC register */
1537 data->exec = 1;
1538 data->ecc_cfg = 0x203;
1539
1540 for (n = 0; n < cwperpage; n++) {
1541 /* status return words */
1542 data->result[n].flash_status = 0xeeeeeeee;
1543
1544 if (n == 0) {
1545 /* enable CS1 */
1546 cmd->cmd = CMD_OCB;
1547 cmd->src = paddr(&data->ebi2_chip_select_cfg0);
1548 cmd->dst = EBI2_CHIP_SELECT_CFG0;
1549 cmd->len = 4;
1550 cmd++;
1551
1552 /* save existing ecc config */
1553 cmd->cmd = 0;
1554 cmd->src = NC11(NAND_EBI2_ECC_BUF_CFG);
1555 cmd->dst = paddr(&data->ecc_cfg_save);
1556 cmd->len = 4;
1557 cmd++;
1558
1559 cmd->cmd = 0;
1560 cmd->src = paddr(&data->ecc_cfg);
1561 cmd->dst = NC11(NAND_EBI2_ECC_BUF_CFG);
1562 cmd->len = 4;
1563 cmd++;
1564
1565 cmd->cmd = 0;
1566 cmd->src = paddr(&data->addr0);
1567 cmd->dst = NC11(NAND_ADDR0);
1568 cmd->len = 8;
1569 cmd++;
1570
1571 /* enable CS0 */
1572 cmd->cmd = 0;
1573 cmd->src = paddr(&data->chipsel_cs0);
1574 cmd->dst = NC01(NAND_FLASH_CHIP_SELECT);
1575 cmd->len = 4;
1576 cmd++;
1577
1578 /* enable CS1 */
1579 cmd->cmd = 0;
1580 cmd->src = paddr(&data->chipsel_cs1);
1581 cmd->dst = NC10(NAND_FLASH_CHIP_SELECT);
1582 cmd->len = 4;
1583 cmd++;
1584
1585 cmd->cmd = 0;
Ajay Dudanib01e5062011-12-03 23:23:42 -08001586 cmd->src = paddr(&data->cfg0);
Murali Nalajalaa8c94c62010-03-05 20:24:30 +05301587 cmd->dst = NC01(NAND_DEV0_CFG0);
1588 cmd->len = 8;
1589 cmd++;
1590
1591 /* config CFG1 for CS1 */
1592 cmd->cmd = 0;
Ajay Dudanib01e5062011-12-03 23:23:42 -08001593 cmd->src = paddr(&data->cfg0);
Murali Nalajalaa8c94c62010-03-05 20:24:30 +05301594 cmd->dst = NC10(NAND_DEV1_CFG0);
1595 cmd->len = 8;
1596 cmd++;
1597 }
1598
1599 if (n % 2 == 0) {
Ajay Dudanib01e5062011-12-03 23:23:42 -08001600 /* MASK CMD ACK/REQ --> NC10 (0xF14) */
Murali Nalajalaa8c94c62010-03-05 20:24:30 +05301601 cmd->cmd = 0;
1602 cmd->src = paddr(&data->adm_mux_cmd_ack_req_nc10);
1603 cmd->dst = EBI2_NAND_ADM_MUX;
1604 cmd->len = 4;
1605 cmd++;
1606
1607 /* CMD */
1608 cmd->cmd = DST_CRCI_NAND_CMD;
1609 cmd->src = paddr(&data->cmd);
1610 cmd->dst = NC01(NAND_FLASH_CMD);
1611 cmd->len = 4;
1612 cmd++;
1613 } else {
Ajay Dudanib01e5062011-12-03 23:23:42 -08001614 /* MASK CMD ACK/REQ --> NC01 (0x53C) */
Murali Nalajalaa8c94c62010-03-05 20:24:30 +05301615 cmd->cmd = 0;
1616 cmd->src = paddr(&data->adm_mux_cmd_ack_req_nc01);
1617 cmd->dst = EBI2_NAND_ADM_MUX;
1618 cmd->len = 4;
1619 cmd++;
1620
1621 /* CMD */
1622 cmd->cmd = DST_CRCI_NAND_CMD;
1623 cmd->src = paddr(&data->cmd);
1624 cmd->dst = NC10(NAND_FLASH_CMD);
1625 cmd->len = 4;
1626 cmd++;
1627 }
1628
1629 cmd->cmd = 0;
Ajay Dudanib01e5062011-12-03 23:23:42 -08001630 if (!raw_mode) {
Murali Nalajalaa8c94c62010-03-05 20:24:30 +05301631 cmd->src = addr + n * 516;
Ajay Dudanib01e5062011-12-03 23:23:42 -08001632 cmd->len =
1633 ((n <
1634 (cwperpage - 1)) ? 516 : (512 -
1635 ((cwperpage -
1636 1) << 2)));
1637 } else {
Murali Nalajalaa8c94c62010-03-05 20:24:30 +05301638 cmd->src = addr;
Ajay Dudanib01e5062011-12-03 23:23:42 -08001639 cmd->len = 528;
Murali Nalajalaa8c94c62010-03-05 20:24:30 +05301640 }
1641
1642 if (n % 2 == 0)
1643 cmd->dst = NC01(NAND_FLASH_BUFFER);
1644 else
1645 cmd->dst = NC10(NAND_FLASH_BUFFER);
1646 cmd++;
1647
1648 if ((n == (cwperpage - 1)) && (!raw_mode)) {
1649 /* write extra data */
1650 cmd->cmd = 0;
1651 cmd->src = spareaddr;
Ajay Dudanib01e5062011-12-03 23:23:42 -08001652 cmd->dst =
1653 NC10(NAND_FLASH_BUFFER) + (512 -
1654 ((cwperpage - 1) << 2));
Murali Nalajalaa8c94c62010-03-05 20:24:30 +05301655 cmd->len = (cwperpage << 2);
1656 cmd++;
1657 }
1658
1659 if (n % 2 == 0) {
1660 /* kick the NC01 execute register */
1661 cmd->cmd = 0;
1662 cmd->src = paddr(&data->exec);
1663 cmd->dst = NC01(NAND_EXEC_CMD);
1664 cmd->len = 4;
1665 cmd++;
1666 if (n != 0) {
Ajay Dudanib01e5062011-12-03 23:23:42 -08001667 /* MASK DATA ACK/REQ --> NC01 (0xA3C) */
Murali Nalajalaa8c94c62010-03-05 20:24:30 +05301668 cmd->cmd = 0;
Ajay Dudanib01e5062011-12-03 23:23:42 -08001669 cmd->src =
1670 paddr(&data->adm_mux_data_ack_req_nc01);
Murali Nalajalaa8c94c62010-03-05 20:24:30 +05301671 cmd->dst = EBI2_NAND_ADM_MUX;
1672 cmd->len = 4;
1673 cmd++;
1674
1675 /* block on data ready from NC10, then
Ajay Dudanib01e5062011-12-03 23:23:42 -08001676 * read the status register
1677 */
Murali Nalajalaa8c94c62010-03-05 20:24:30 +05301678 cmd->cmd = SRC_CRCI_NAND_DATA;
1679 cmd->src = NC10(NAND_FLASH_STATUS);
Ajay Dudanib01e5062011-12-03 23:23:42 -08001680 cmd->dst = paddr(&data->result[n - 1]);
Murali Nalajalaa8c94c62010-03-05 20:24:30 +05301681 cmd->len = 4;
1682 cmd++;
1683 }
1684 } else {
1685 /* kick the execute register */
1686 cmd->cmd = 0;
1687 cmd->src = paddr(&data->exec);
1688 cmd->dst = NC10(NAND_EXEC_CMD);
1689 cmd->len = 4;
1690 cmd++;
1691
Ajay Dudanib01e5062011-12-03 23:23:42 -08001692 /* MASK DATA ACK/REQ --> NC10 (0xF28) */
Murali Nalajalaa8c94c62010-03-05 20:24:30 +05301693 cmd->cmd = 0;
1694 cmd->src = paddr(&data->adm_mux_data_ack_req_nc10);
1695 cmd->dst = EBI2_NAND_ADM_MUX;
1696 cmd->len = 4;
1697 cmd++;
1698
1699 /* block on data ready from NC01, then
1700 * read the status register
1701 */
1702 cmd->cmd = SRC_CRCI_NAND_DATA;
1703 cmd->src = NC01(NAND_FLASH_STATUS);
Ajay Dudanib01e5062011-12-03 23:23:42 -08001704 cmd->dst = paddr(&data->result[n - 1]);
Murali Nalajalaa8c94c62010-03-05 20:24:30 +05301705 cmd->len = 4;
1706 cmd++;
1707 }
1708 }
1709
Ajay Dudanib01e5062011-12-03 23:23:42 -08001710 /* MASK DATA ACK/REQ --> NC01 (0xA3C) */
Murali Nalajalaa8c94c62010-03-05 20:24:30 +05301711 cmd->cmd = 0;
1712 cmd->src = paddr(&data->adm_mux_data_ack_req_nc01);
1713 cmd->dst = EBI2_NAND_ADM_MUX;
1714 cmd->len = 4;
1715 cmd++;
1716
1717 /* we should process outstanding request */
1718 /* block on data ready, then
1719 * read the status register
1720 */
1721 cmd->cmd = SRC_CRCI_NAND_DATA;
1722 cmd->src = NC10(NAND_FLASH_STATUS);
Ajay Dudanib01e5062011-12-03 23:23:42 -08001723 cmd->dst = paddr(&data->result[n - 1]);
Murali Nalajalaa8c94c62010-03-05 20:24:30 +05301724 cmd->len = 4;
1725 cmd++;
1726
1727 /* restore saved ecc config */
1728 cmd->cmd = 0;
1729 cmd->src = paddr(&data->ecc_cfg_save);
1730 cmd->dst = NAND_EBI2_ECC_BUF_CFG;
1731 cmd->len = 4;
1732
Ajay Dudanib01e5062011-12-03 23:23:42 -08001733 /* MASK DATA ACK/REQ --> NC01 (0xFC0) */
Murali Nalajalaa8c94c62010-03-05 20:24:30 +05301734 cmd->cmd = 0;
1735 cmd->src = paddr(&data->adm_default_mux);
1736 cmd->dst = EBI2_NAND_ADM_MUX;
1737 cmd->len = 4;
1738 cmd++;
1739
1740 /* disable CS1 */
1741 cmd->cmd = CMD_OCU | CMD_LC;
1742 cmd->src = paddr(&data->default_ebi2_chip_select_cfg0);
1743 cmd->dst = EBI2_CHIP_SELECT_CFG0;
1744 cmd->len = 4;
1745 cmd++;
1746
1747 ptr[0] = (paddr(cmdlist) >> 3) | CMD_PTR_LP;
1748
1749 dmov_exec_cmdptr(DMOV_NAND_CHAN, ptr);
1750
1751#if VERBOSE
Ajay Dudanib01e5062011-12-03 23:23:42 -08001752 dprintf(INFO, "write page %d: status: %x %x %x %x %x %x %x %x \
1753 %x %x %x %x %x %x %x %x \n", page, data->result[0].flash_status[0], data->result[1].flash_status[1], data->result[2].flash_status[2], data->result[3].flash_status[3], data->result[4].flash_status[4], data->result[5].flash_status[5], data->result[6].flash_status[6], data->result[7].flash_status[7], data->result[8].flash_status[8], data->result[9].flash_status[9], data->result[10].flash_status[10], data->result[11].flash_status[11], data->result[12].flash_status[12], data->result[13].flash_status[13], data->result[14].flash_status[14], data->result[15].flash_status[15]);
Murali Nalajalaa8c94c62010-03-05 20:24:30 +05301754#endif
1755
1756 /* if any of the writes failed (0x10), or there was a
1757 ** protection violation (0x100), or the program success
1758 ** bit (0x80) is unset, we lose
1759 */
Ajay Dudanib01e5062011-12-03 23:23:42 -08001760 for (n = 0; n < cwperpage; n++) {
1761 if (data->result[n].flash_status & 0x110)
1762 return -1;
1763 if (!(data->result[n].flash_status & 0x80))
1764 return -1;
Murali Nalajalaa8c94c62010-03-05 20:24:30 +05301765 }
1766
1767#if VERIFY_WRITE
1768 n = _flash_read_page(cmdlist, ptrlist, page, flash_data,
Ajay Dudanib01e5062011-12-03 23:23:42 -08001769 flash_data + 2048);
Murali Nalajalaa8c94c62010-03-05 20:24:30 +05301770 if (n != 0)
1771 return -1;
1772 if (memcmp(flash_data, _addr, 2048) ||
Ajay Dudanib01e5062011-12-03 23:23:42 -08001773 memcmp(flash_data + 2048, _spareaddr, 16)) {
Murali Nalajalaa8c94c62010-03-05 20:24:30 +05301774 dprintf(CRITICAL, "verify error @ page %d\n", page);
1775 return -1;
1776 }
1777#endif
1778 return 0;
1779}
1780
Shashank Mittald0c836d2009-11-20 10:31:18 -08001781char empty_buf[528];
Ajay Dudanib01e5062011-12-03 23:23:42 -08001782static int
1783flash_nand_mark_badblock(dmov_s * cmdlist, unsigned *ptrlist, unsigned page)
Shashank Mittald0c836d2009-11-20 10:31:18 -08001784{
Ajay Dudanib01e5062011-12-03 23:23:42 -08001785 memset(empty_buf, 0, 528);
1786 /* Going to first page of the block */
1787 if (page & num_pages_per_blk_mask)
1788 page = page - (page & num_pages_per_blk_mask);
1789 return _flash_nand_write_page(cmdlist, ptrlist, page, empty_buf, 0, 1);
Shashank Mittald0c836d2009-11-20 10:31:18 -08001790}
Dima Zavin03cf4312009-01-23 16:38:30 -08001791
Shashank Mittal83d16d02009-11-18 16:54:42 -08001792unsigned nand_cfg0;
1793unsigned nand_cfg1;
1794
Ajay Dudanib01e5062011-12-03 23:23:42 -08001795static int flash_nand_read_config(dmov_s * cmdlist, unsigned *ptrlist)
Dima Zavin03cf4312009-01-23 16:38:30 -08001796{
Shashank Mittal8e49dec2010-03-01 15:19:04 -08001797 static unsigned CFG0_TMP, CFG1_TMP;
Dima Zavin03cf4312009-01-23 16:38:30 -08001798 cmdlist[0].cmd = CMD_OCB;
1799 cmdlist[0].src = NAND_DEV0_CFG0;
Shashank Mittal8e49dec2010-03-01 15:19:04 -08001800 cmdlist[0].dst = paddr(&CFG0_TMP);
Dima Zavin03cf4312009-01-23 16:38:30 -08001801 cmdlist[0].len = 4;
1802
1803 cmdlist[1].cmd = CMD_OCU | CMD_LC;
1804 cmdlist[1].src = NAND_DEV0_CFG1;
Shashank Mittal8e49dec2010-03-01 15:19:04 -08001805 cmdlist[1].dst = paddr(&CFG1_TMP);
Dima Zavin03cf4312009-01-23 16:38:30 -08001806 cmdlist[1].len = 4;
1807
1808 *ptrlist = (paddr(cmdlist) >> 3) | CMD_PTR_LP;
1809
1810 dmov_exec_cmdptr(DMOV_NAND_CHAN, ptrlist);
1811
Ajay Dudanib01e5062011-12-03 23:23:42 -08001812 if ((CFG0_TMP == 0) || (CFG1_TMP == 0)) {
Dima Zavin03cf4312009-01-23 16:38:30 -08001813 return -1;
1814 }
1815
Shashank Mittal8e49dec2010-03-01 15:19:04 -08001816 CFG0_A = CFG0_TMP;
1817 CFG1_A = CFG1_TMP;
Shashank Mittal83d16d02009-11-18 16:54:42 -08001818 if (flash_info.type == FLASH_16BIT_NAND_DEVICE) {
1819 nand_cfg1 |= CFG1_WIDE_FLASH;
1820 }
Dima Zavin03cf4312009-01-23 16:38:30 -08001821 dprintf(INFO, "nandcfg: %x %x (initial)\n", CFG0, CFG1);
1822
Ajay Dudanib01e5062011-12-03 23:23:42 -08001823 CFG0_A = (((flash_pagesize >> 9) - 1) << 6) /* 4/8 cw/pg for 2/4k */
1824 |(516 << 9) /* 516 user data bytes */
1825 |(10 << 19) /* 10 parity bytes */
1826 |(5 << 27) /* 5 address cycles */
1827 |(0 << 30) /* Do not read status before data */
1828 |(1 << 31)
1829 /* Send read cmd */
1830 /* 0 spare bytes for 16 bit nand or 1 spare bytes for 8 bit */
1831 |((nand_cfg1 & CFG1_WIDE_FLASH) ? (0 << 23) : (enable_bch_ecc ? (2 << 23) : (1 << 23))); /* 2 spare bytes for 8 bit bch ecc */
1832 CFG1_A = (0 << 0) /* Enable ecc */
1833 |(7 << 2) /* 8 recovery cycles */
1834 |(0 << 5) /* Allow CS deassertion */
1835 |((flash_pagesize - ((enable_bch_ecc ? 532 : 528) * ((flash_pagesize >> 9) - 1)) + 1) << 6) /* Bad block marker location */
1836 |(0 << 16) /* Bad block in user data area */
1837 |(2 << 17) /* 6 cycle tWB/tRB */
1838 |(nand_cfg1 & CFG1_WIDE_FLASH); /* preserve wide flash flag */
Dima Zavin03cf4312009-01-23 16:38:30 -08001839
Channagoud Kadabi404a7062011-03-21 19:27:50 +05301840 NAND_CFG0_RAW = CFG0_RAW;
1841 NAND_CFG1_RAW = CFG1_RAW;
1842
1843 if (enable_bch_ecc) {
Ajay Dudanib01e5062011-12-03 23:23:42 -08001844 CFG1_A |= (1 << 27); /* Enable BCH engine */
1845 ECC_BCH_CFG = (0 << 0) /* Enable ECC */
1846 |(0 << 1) /* Enable/Disable SW reset of ECC engine */
1847 |(1 << 4) /* 8bit ecc */
1848 |((nand_cfg1 & CFG1_WIDE_FLASH) ? (14 << 8) : (13 << 8)) /*parity bytes */
1849 |(516 << 16) /* 516 user data bytes */
1850 |(1 << 30); /* Turn on ECC engine clocks always */
1851 NAND_CFG0_RAW = CFG0_RAW_BCHECC; /* CW size is increased to 532B */
1852 }
Channagoud Kadabi404a7062011-03-21 19:27:50 +05301853
Shashank Mittal8e49dec2010-03-01 15:19:04 -08001854 dprintf(INFO, "nandcfg(Apps): %x %x (used)\n", CFG0_A, CFG1_A);
Dima Zavin03cf4312009-01-23 16:38:30 -08001855
Shashank Mittal8e49dec2010-03-01 15:19:04 -08001856 CFG0_M = CFG0_TMP;
1857 CFG1_M = CFG1_TMP;
1858 if (flash_info.type == FLASH_16BIT_NAND_DEVICE) {
1859 nand_cfg1 |= CFG1_WIDE_FLASH;
1860 }
Ajay Dudanib01e5062011-12-03 23:23:42 -08001861 CFG0_M = (((flash_pagesize >> 9) - 1) << 6) /* 4/8 cw/pg for 2/4k */
1862 |(512 << 9) /* 512 user data bytes */
1863 |(10 << 19) /* 10 parity bytes */
1864 |(5 << 27) /* 5 address cycles */
1865 |(0 << 30) /* Do not read status before data */
1866 |(1 << 31) /* Send read cmd */
1867 |((nand_cfg1 & CFG1_WIDE_FLASH) ? (4 << 23) : (5 << 23));
1868 CFG1_M = (0 << 0) /* Enable ecc */
1869 |(7 << 2) /* 8 recovery cycles */
1870 |(0 << 5) /* Allow CS deassertion */
1871 |((flash_pagesize - (528 * ((flash_pagesize >> 9) - 1)) + 1) << 6) /* Bad block marker location */
1872 |(0 << 16) /* Bad block in user data area */
1873 |(2 << 17) /* 6 cycle tWB/tRB */
1874 |(nand_cfg1 & CFG1_WIDE_FLASH); /* preserve wide flash flag */
Shashank Mittal8e49dec2010-03-01 15:19:04 -08001875 dprintf(INFO, "nandcfg(Modem): %x %x (used)\n", CFG0_M, CFG1_M);
Dima Zavin03cf4312009-01-23 16:38:30 -08001876 return 0;
1877}
1878
Shashank Mittalc20b5a12009-11-18 19:35:30 -08001879/* OneNAND programming functions */
1880
Ajay Dudanib01e5062011-12-03 23:23:42 -08001881static void flash_onenand_read_id(dmov_s * cmdlist, unsigned *ptrlist)
Shashank Mittalc20b5a12009-11-18 19:35:30 -08001882{
1883 dmov_s *cmd = cmdlist;
1884 unsigned *ptr = ptrlist;
1885 unsigned *data = ptrlist + 4;
1886
1887 data[0] = SFLASH_BCFG;
Ajay Dudanib01e5062011-12-03 23:23:42 -08001888 data[1] =
1889 SFLASH_PREPCMD(8, 0, 0, NAND_SFCMD_DATXS, NAND_SFCMD_ASYNC,
1890 NAND_SFCMD_REGRD);
Shashank Mittalc20b5a12009-11-18 19:35:30 -08001891 data[2] = (ONENAND_DEVICE_ID << 16) | (ONENAND_MANUFACTURER_ID);
1892 data[3] = (ONENAND_DATA_BUFFER_SIZE << 16) | (ONENAND_VERSION_ID);
Ajay Dudanib01e5062011-12-03 23:23:42 -08001893 data[4] =
1894 (ONENAND_AMOUNT_OF_BUFFERS << 16) | (ONENAND_BOOT_BUFFER_SIZE);
Shashank Mittalc20b5a12009-11-18 19:35:30 -08001895 data[5] = (CLEAN_DATA_16 << 16) | (ONENAND_TECHNOLOGY);
Ajay Dudanib01e5062011-12-03 23:23:42 -08001896 data[6] = CLEAN_DATA_32; //status
1897 data[7] = CLEAN_DATA_32; //register read
1898 data[8] = CLEAN_DATA_32; //register read
1899 data[9] = CLEAN_DATA_32; //register read
1900 data[10] = CLEAN_DATA_32; //register read
Shashank Mittalc20b5a12009-11-18 19:35:30 -08001901 data[11] = 1;
1902 data[12] = 0 | 4;
1903
1904 /* Setup controller in SFLASH mode */
1905 cmd[0].cmd = 0 | CMD_OCB;
1906 cmd[0].src = paddr(&data[0]);
1907 cmd[0].dst = NAND_SFLASHC_BURST_CFG;
1908 cmd[0].len = 4;
1909
1910 /* Enable data mover for controller */
1911 cmd[1].cmd = 0;
1912 cmd[1].src = paddr(&data[12]);
1913 cmd[1].dst = NAND_FLASH_CHIP_SELECT;
1914 cmd[1].len = 4;
1915
1916 /* Setup SFLASHC_CMD with xfers in async mode */
1917 cmd[2].cmd = DST_CRCI_NAND_CMD;
1918 cmd[2].src = paddr(&data[1]);
1919 cmd[2].dst = NAND_SFLASHC_CMD;
1920 cmd[2].len = 4;
1921
1922 /* Setup to read device information */
1923 cmd[3].cmd = 0;
1924 cmd[3].src = paddr(&data[2]);
1925 cmd[3].dst = NAND_ADDR0;
1926 cmd[3].len = 8;
1927
1928 cmd[4].cmd = 0;
1929 cmd[4].src = paddr(&data[4]);
1930 cmd[4].dst = NAND_ADDR2;
1931 cmd[4].len = 8;
1932
1933 /* Set execute bit */
1934 cmd[5].cmd = 0;
1935 cmd[5].src = paddr(&data[11]);
1936 cmd[5].dst = NAND_SFLASHC_EXEC_CMD;
1937 cmd[5].len = 4;
1938
1939 /* Check status */
1940 cmd[6].cmd = SRC_CRCI_NAND_DATA;
1941 cmd[6].src = NAND_SFLASHC_STATUS;
1942 cmd[6].dst = paddr(&data[6]);
1943 cmd[6].len = 4;
1944
1945 /* Read result device registers */
1946 cmd[7].cmd = 0 | CMD_OCU | CMD_LC;
1947 cmd[7].src = NAND_GENP_REG0;
1948 cmd[7].dst = paddr(&data[7]);
1949 cmd[7].len = 16;
1950
1951 ptr[0] = (paddr(cmd) >> 3) | CMD_PTR_LP;
1952
1953 dmov_exec_cmdptr(DMOV_NAND_CHAN, ptr);
1954
1955#if VERBOSE
1956 dprintf(INFO, "status: %x\n", data[6]);
1957#endif
1958
1959 flash_info.id = data[7];
1960 flash_info.vendor = data[7] & CLEAN_DATA_16;
Ajay Dudanib01e5062011-12-03 23:23:42 -08001961 flash_info.device = (data[7] >> 16) & CLEAN_DATA_16;
Shashank Mittalc20b5a12009-11-18 19:35:30 -08001962 return;
1963}
1964
Shashank Mittalc20b5a12009-11-18 19:35:30 -08001965struct data_onenand_erase {
1966 unsigned sfbcfg;
1967 unsigned sfcmd[4];
1968 unsigned sfexec;
1969 unsigned sfstat[4];
1970 unsigned addr0;
1971 unsigned addr1;
1972 unsigned addr2;
1973 unsigned addr3;
1974 unsigned addr4;
1975 unsigned addr5;
1976 unsigned addr6;
1977 unsigned data0;
1978 unsigned data1;
1979 unsigned data2;
1980 unsigned data3;
1981 unsigned data4;
1982 unsigned data5;
1983 unsigned data6;
1984};
1985
Ajay Dudanib01e5062011-12-03 23:23:42 -08001986static int _flash_onenand_read_page(dmov_s * cmdlist, unsigned *ptrlist,
1987 unsigned page, void *_addr,
1988 void *_spareaddr, unsigned raw_mode);
Shashank Mittalad3d05c2009-11-19 15:53:57 -08001989
Ajay Dudanib01e5062011-12-03 23:23:42 -08001990static int
1991flash_onenand_block_isbad(dmov_s * cmdlist, unsigned *ptrlist, unsigned page)
Shashank Mittalad3d05c2009-11-19 15:53:57 -08001992{
1993 unsigned char page_data[2112];
1994 unsigned char *oobptr = &(page_data[2048]);
1995
1996 /* Going to first page of the block */
Ajay Dudanib01e5062011-12-03 23:23:42 -08001997 if (page & num_pages_per_blk_mask)
Channagoud Kadabibeb17d52011-03-25 17:14:00 +05301998 page = page - (page & num_pages_per_blk_mask);
Shashank Mittalad3d05c2009-11-19 15:53:57 -08001999
2000 /* Reading page in raw mode */
Ajay Dudanib01e5062011-12-03 23:23:42 -08002001 if (_flash_onenand_read_page(cmdlist, ptrlist, page, page_data, 0, 1))
Shashank Mittalad3d05c2009-11-19 15:53:57 -08002002 return 1;
2003
2004 /* Checking if block is bad */
Ajay Dudanib01e5062011-12-03 23:23:42 -08002005 if ((oobptr[0] != 0xFF) || (oobptr[1] != 0xFF) ||
2006 (oobptr[16] != 0xFF) || (oobptr[17] != 0xFF) ||
2007 (oobptr[32] != 0xFF) || (oobptr[33] != 0xFF) ||
2008 (oobptr[48] != 0xFF) || (oobptr[49] != 0xFF)) {
Shashank Mittalad3d05c2009-11-19 15:53:57 -08002009 return 1;
2010 }
2011 return 0;
2012}
2013
Ajay Dudanib01e5062011-12-03 23:23:42 -08002014static int
2015flash_onenand_erase_block(dmov_s * cmdlist, unsigned *ptrlist, unsigned page)
Shashank Mittalc20b5a12009-11-18 19:35:30 -08002016{
2017 dmov_s *cmd = cmdlist;
2018 unsigned *ptr = ptrlist;
2019 struct data_onenand_erase *data = (void *)ptrlist + 4;
Shashank Mittalad3d05c2009-11-19 15:53:57 -08002020 int isbad = 0;
Channagoud Kadabibeb17d52011-03-25 17:14:00 +05302021 unsigned erasesize = (flash_pagesize * num_pages_per_blk);
Ajay Dudanib01e5062011-12-03 23:23:42 -08002022 unsigned onenand_startaddr1 =
2023 DEVICE_FLASHCORE_0 | (page * flash_pagesize) / erasesize;
Shashank Mittalc20b5a12009-11-18 19:35:30 -08002024 unsigned onenand_startaddr8 = 0x0000;
2025 unsigned onenand_startaddr2 = DEVICE_BUFFERRAM_0 << 15;
2026 unsigned onenand_startbuffer = DATARAM0_0 << 8;
2027
2028 unsigned controller_status;
2029 unsigned interrupt_status;
2030 unsigned ecc_status;
2031
Ajay Dudanib01e5062011-12-03 23:23:42 -08002032 if ((page * flash_pagesize) & (erasesize - 1))
2033 return -1;
Shashank Mittalc20b5a12009-11-18 19:35:30 -08002034
Shashank Mittalad3d05c2009-11-19 15:53:57 -08002035 /* Check for bad block and erase only if block is not marked bad */
2036 isbad = flash_onenand_block_isbad(cmdlist, ptrlist, page);
Ajay Dudanib01e5062011-12-03 23:23:42 -08002037 if (isbad) {
2038 dprintf(INFO, "skipping @ %d (bad block)\n",
2039 page / num_pages_per_blk);
Shashank Mittalad3d05c2009-11-19 15:53:57 -08002040 return -1;
2041 }
2042
Ajay Dudanib01e5062011-12-03 23:23:42 -08002043 /*Erase block */
Shashank Mittalc20b5a12009-11-18 19:35:30 -08002044 onenand_startaddr1 = DEVICE_FLASHCORE_0 |
Ajay Dudanib01e5062011-12-03 23:23:42 -08002045 ((page * flash_pagesize) / (erasesize));
Shashank Mittalc20b5a12009-11-18 19:35:30 -08002046 onenand_startaddr8 = 0x0000;
2047 onenand_startaddr2 = DEVICE_BUFFERRAM_0 << 15;
2048 onenand_startbuffer = DATARAM0_0 << 8;
2049
Shashank Mittalc20b5a12009-11-18 19:35:30 -08002050 data->sfbcfg = SFLASH_BCFG;
2051 data->sfcmd[0] = SFLASH_PREPCMD(7, 0, 0,
Ajay Dudanib01e5062011-12-03 23:23:42 -08002052 NAND_SFCMD_CMDXS,
2053 NAND_SFCMD_ASYNC, NAND_SFCMD_REGWR);
Shashank Mittalc20b5a12009-11-18 19:35:30 -08002054 data->sfcmd[1] = SFLASH_PREPCMD(0, 0, 32,
Ajay Dudanib01e5062011-12-03 23:23:42 -08002055 NAND_SFCMD_CMDXS,
2056 NAND_SFCMD_ASYNC, NAND_SFCMD_INTHI);
Shashank Mittalc20b5a12009-11-18 19:35:30 -08002057 data->sfcmd[2] = SFLASH_PREPCMD(3, 7, 0,
Ajay Dudanib01e5062011-12-03 23:23:42 -08002058 NAND_SFCMD_DATXS,
2059 NAND_SFCMD_ASYNC, NAND_SFCMD_REGRD);
Shashank Mittalc20b5a12009-11-18 19:35:30 -08002060 data->sfcmd[3] = SFLASH_PREPCMD(4, 10, 0,
Ajay Dudanib01e5062011-12-03 23:23:42 -08002061 NAND_SFCMD_CMDXS,
2062 NAND_SFCMD_ASYNC, NAND_SFCMD_REGWR);
Shashank Mittalc20b5a12009-11-18 19:35:30 -08002063 data->sfexec = 1;
2064 data->sfstat[0] = CLEAN_DATA_32;
2065 data->sfstat[1] = CLEAN_DATA_32;
2066 data->sfstat[2] = CLEAN_DATA_32;
2067 data->sfstat[3] = CLEAN_DATA_32;
Ajay Dudanib01e5062011-12-03 23:23:42 -08002068 data->addr0 =
2069 (ONENAND_INTERRUPT_STATUS << 16) | (ONENAND_SYSTEM_CONFIG_1);
2070 data->addr1 =
2071 (ONENAND_START_ADDRESS_8 << 16) | (ONENAND_START_ADDRESS_1);
2072 data->addr2 = (ONENAND_START_BUFFER << 16) | (ONENAND_START_ADDRESS_2);
2073 data->addr3 = (ONENAND_ECC_STATUS << 16) | (ONENAND_COMMAND);
Shashank Mittalc20b5a12009-11-18 19:35:30 -08002074 data->addr4 = (ONENAND_CONTROLLER_STATUS << 16) |
Ajay Dudanib01e5062011-12-03 23:23:42 -08002075 (ONENAND_INTERRUPT_STATUS);
2076 data->addr5 =
2077 (ONENAND_INTERRUPT_STATUS << 16) | (ONENAND_SYSTEM_CONFIG_1);
2078 data->addr6 =
2079 (ONENAND_START_ADDRESS_3 << 16) | (ONENAND_START_ADDRESS_1);
2080 data->data0 = (ONENAND_CLRINTR << 16) | (ONENAND_SYSCFG1_ECCENA);
2081 data->data1 = (onenand_startaddr8 << 16) | (onenand_startaddr1);
2082 data->data2 = (onenand_startbuffer << 16) | (onenand_startaddr2);
2083 data->data3 = (CLEAN_DATA_16 << 16) | (ONENAND_CMDERAS);
2084 data->data4 = (CLEAN_DATA_16 << 16) | (CLEAN_DATA_16);
2085 data->data5 = (ONENAND_CLRINTR << 16) | (ONENAND_SYSCFG1_ECCENA);
2086 data->data6 = (ONENAND_STARTADDR3_RES << 16) | (ONENAND_STARTADDR1_RES);
Shashank Mittalc20b5a12009-11-18 19:35:30 -08002087
2088 /***************************************************************/
2089 /* Write the necessary address registers in the onenand device */
2090 /***************************************************************/
2091
2092 /* Enable and configure the SFlash controller */
2093 cmd->cmd = 0 | CMD_OCB;
2094 cmd->src = paddr(&data->sfbcfg);
2095 cmd->dst = NAND_SFLASHC_BURST_CFG;
2096 cmd->len = 4;
2097 cmd++;
2098
2099 /* Block on cmd ready and write CMD register */
2100 cmd->cmd = DST_CRCI_NAND_CMD;
2101 cmd->src = paddr(&data->sfcmd[0]);
2102 cmd->dst = NAND_SFLASHC_CMD;
2103 cmd->len = 4;
2104 cmd++;
2105
2106 /* Write the ADDR0 and ADDR1 registers */
2107 cmd->cmd = 0;
2108 cmd->src = paddr(&data->addr0);
2109 cmd->dst = NAND_ADDR0;
2110 cmd->len = 8;
2111 cmd++;
2112
2113 /* Write the ADDR2 ADDR3 ADDR4 ADDR5 registers */
2114 cmd->cmd = 0;
2115 cmd->src = paddr(&data->addr2);
2116 cmd->dst = NAND_ADDR2;
2117 cmd->len = 16;
2118 cmd++;
2119
2120 /* Write the ADDR6 registers */
2121 cmd->cmd = 0;
2122 cmd->src = paddr(&data->addr6);
2123 cmd->dst = NAND_ADDR6;
2124 cmd->len = 4;
2125 cmd++;
2126
2127 /* Write the GENP0, GENP1, GENP2, GENP3, GENP4 registers */
2128 cmd->cmd = 0;
2129 cmd->src = paddr(&data->data0);
2130 cmd->dst = NAND_GENP_REG0;
2131 cmd->len = 16;
2132 cmd++;
2133
2134 /* Write the FLASH_DEV_CMD4,5,6 registers */
2135 cmd->cmd = 0;
2136 cmd->src = paddr(&data->data4);
2137 cmd->dst = NAND_DEV_CMD4;
2138 cmd->len = 12;
2139 cmd++;
2140
2141 /* Kick the execute command */
2142 cmd->cmd = 0;
2143 cmd->src = paddr(&data->sfexec);
2144 cmd->dst = NAND_SFLASHC_EXEC_CMD;
2145 cmd->len = 4;
2146 cmd++;
2147
2148 /* Block on data ready, and read the status register */
2149 cmd->cmd = SRC_CRCI_NAND_DATA;
2150 cmd->src = NAND_SFLASHC_STATUS;
2151 cmd->dst = paddr(&data->sfstat[0]);
2152 cmd->len = 4;
2153 cmd++;
2154
2155 /***************************************************************/
Ajay Dudanib01e5062011-12-03 23:23:42 -08002156 /* Wait for the interrupt from the Onenand device controller */
Shashank Mittalc20b5a12009-11-18 19:35:30 -08002157 /***************************************************************/
2158
2159 /* Block on cmd ready and write CMD register */
2160 cmd->cmd = DST_CRCI_NAND_CMD;
2161 cmd->src = paddr(&data->sfcmd[1]);
2162 cmd->dst = NAND_SFLASHC_CMD;
2163 cmd->len = 4;
2164 cmd++;
2165
2166 /* Kick the execute command */
2167 cmd->cmd = 0;
2168 cmd->src = paddr(&data->sfexec);
2169 cmd->dst = NAND_SFLASHC_EXEC_CMD;
2170 cmd->len = 4;
2171 cmd++;
2172
2173 /* Block on data ready, and read the status register */
2174 cmd->cmd = SRC_CRCI_NAND_DATA;
2175 cmd->src = NAND_SFLASHC_STATUS;
2176 cmd->dst = paddr(&data->sfstat[1]);
2177 cmd->len = 4;
2178 cmd++;
2179
2180 /***************************************************************/
2181 /* Read the necessary status registers from the onenand device */
2182 /***************************************************************/
2183
2184 /* Block on cmd ready and write CMD register */
2185 cmd->cmd = DST_CRCI_NAND_CMD;
2186 cmd->src = paddr(&data->sfcmd[2]);
2187 cmd->dst = NAND_SFLASHC_CMD;
2188 cmd->len = 4;
2189 cmd++;
2190
2191 /* Kick the execute command */
2192 cmd->cmd = 0;
2193 cmd->src = paddr(&data->sfexec);
2194 cmd->dst = NAND_SFLASHC_EXEC_CMD;
2195 cmd->len = 4;
2196 cmd++;
2197
2198 /* Block on data ready, and read the status register */
2199 cmd->cmd = SRC_CRCI_NAND_DATA;
2200 cmd->src = NAND_SFLASHC_STATUS;
2201 cmd->dst = paddr(&data->sfstat[2]);
2202 cmd->len = 4;
2203 cmd++;
2204
2205 /* Read the GENP3 register */
2206 cmd->cmd = 0;
2207 cmd->src = NAND_GENP_REG3;
2208 cmd->dst = paddr(&data->data3);
2209 cmd->len = 4;
2210 cmd++;
2211
2212 /* Read the DEVCMD4 register */
2213 cmd->cmd = 0;
2214 cmd->src = NAND_DEV_CMD4;
2215 cmd->dst = paddr(&data->data4);
2216 cmd->len = 4;
2217 cmd++;
2218
2219 /***************************************************************/
Ajay Dudanib01e5062011-12-03 23:23:42 -08002220 /* Restore the necessary registers to proper values */
Shashank Mittalc20b5a12009-11-18 19:35:30 -08002221 /***************************************************************/
2222
2223 /* Block on cmd ready and write CMD register */
2224 cmd->cmd = DST_CRCI_NAND_CMD;
2225 cmd->src = paddr(&data->sfcmd[3]);
2226 cmd->dst = NAND_SFLASHC_CMD;
2227 cmd->len = 4;
2228 cmd++;
2229
2230 /* Kick the execute command */
2231 cmd->cmd = 0;
2232 cmd->src = paddr(&data->sfexec);
2233 cmd->dst = NAND_SFLASHC_EXEC_CMD;
2234 cmd->len = 4;
2235 cmd++;
2236
2237 /* Block on data ready, and read the status register */
2238 cmd->cmd = SRC_CRCI_NAND_DATA | CMD_OCU | CMD_LC;
2239 cmd->src = NAND_SFLASHC_STATUS;
2240 cmd->dst = paddr(&data->sfstat[3]);
2241 cmd->len = 4;
2242 cmd++;
2243
2244 ptr[0] = (paddr(cmdlist) >> 3) | CMD_PTR_LP;
2245
2246 dmov_exec_cmdptr(DMOV_NAND_CHAN, ptr);
2247
2248 ecc_status = (data->data3 >> 16) & 0x0000FFFF;
2249 interrupt_status = (data->data4 >> 0) & 0x0000FFFF;
2250 controller_status = (data->data4 >> 16) & 0x0000FFFF;
2251
2252#if VERBOSE
2253 dprintf(INFO, "\n%s: sflash status %x %x %x %x\n", __func__,
Ajay Dudanib01e5062011-12-03 23:23:42 -08002254 data->sfstat[0],
2255 data->sfstat[1], data->sfstat[2], data->sfstat[3]);
Shashank Mittalc20b5a12009-11-18 19:35:30 -08002256
2257 dprintf(INFO, "%s: controller_status = %x\n", __func__,
Ajay Dudanib01e5062011-12-03 23:23:42 -08002258 controller_status);
Shashank Mittalc20b5a12009-11-18 19:35:30 -08002259 dprintf(INFO, "%s: interrupt_status = %x\n", __func__,
Ajay Dudanib01e5062011-12-03 23:23:42 -08002260 interrupt_status);
2261 dprintf(INFO, "%s: ecc_status = %x\n", __func__, ecc_status);
Shashank Mittalc20b5a12009-11-18 19:35:30 -08002262#endif
2263 /* Check for errors, protection violations etc */
2264 if ((controller_status != 0)
Ajay Dudanib01e5062011-12-03 23:23:42 -08002265 || (data->sfstat[0] & 0x110)
2266 || (data->sfstat[1] & 0x110)
2267 || (data->sfstat[2] & 0x110) || (data->sfstat[3] & 0x110)) {
2268 dprintf(CRITICAL, "%s: ECC/MPU/OP error\n", __func__);
2269 return -1;
Shashank Mittalc20b5a12009-11-18 19:35:30 -08002270 }
2271
Shashank Mittalc20b5a12009-11-18 19:35:30 -08002272#if VERBOSE
2273 dprintf(INFO, "status: %x\n", data[5]);
2274#endif
2275
2276 return 0;
2277}
2278
Shashank Mittalc20b5a12009-11-18 19:35:30 -08002279struct data_onenand_read {
Ajay Dudanib01e5062011-12-03 23:23:42 -08002280 unsigned sfbcfg;
2281 unsigned sfcmd[9];
2282 unsigned sfexec;
2283 unsigned sfstat[9];
2284 unsigned addr0;
2285 unsigned addr1;
2286 unsigned addr2;
2287 unsigned addr3;
2288 unsigned addr4;
2289 unsigned addr5;
2290 unsigned addr6;
2291 unsigned data0;
2292 unsigned data1;
2293 unsigned data2;
2294 unsigned data3;
2295 unsigned data4;
2296 unsigned data5;
2297 unsigned data6;
2298 unsigned macro[5];
Shashank Mittalc20b5a12009-11-18 19:35:30 -08002299};
2300
Ajay Dudanib01e5062011-12-03 23:23:42 -08002301static int
2302_flash_onenand_read_page(dmov_s * cmdlist, unsigned *ptrlist,
2303 unsigned page, void *_addr, void *_spareaddr,
2304 unsigned raw_mode)
Shashank Mittalc20b5a12009-11-18 19:35:30 -08002305{
2306 dmov_s *cmd = cmdlist;
2307 unsigned *ptr = ptrlist;
Ajay Dudanib01e5062011-12-03 23:23:42 -08002308 struct data_onenand_read *data = (void *)(ptrlist + 4);
2309 unsigned addr = (unsigned)_addr;
2310 unsigned curr_addr = (unsigned)_addr;
Greg Griscod2471ef2011-07-14 13:00:42 -07002311#if VERBOSE
Ajay Dudanib01e5062011-12-03 23:23:42 -08002312 unsigned spareaddr = (unsigned)_spareaddr;
Greg Griscod2471ef2011-07-14 13:00:42 -07002313#endif
Shashank Mittalc20b5a12009-11-18 19:35:30 -08002314 unsigned i;
Channagoud Kadabibeb17d52011-03-25 17:14:00 +05302315 unsigned erasesize = (flash_pagesize * num_pages_per_blk);
Shashank Mittaldcc2e352009-11-19 19:11:16 -08002316 unsigned writesize = flash_pagesize;
Shashank Mittalc20b5a12009-11-18 19:35:30 -08002317
2318 unsigned onenand_startaddr1 = DEVICE_FLASHCORE_0 |
Ajay Dudanib01e5062011-12-03 23:23:42 -08002319 ((unsigned)(page * flash_pagesize) / erasesize);
Shashank Mittaldcc2e352009-11-19 19:11:16 -08002320 unsigned onenand_startaddr8 = (((unsigned)(page * flash_pagesize) &
Ajay Dudanib01e5062011-12-03 23:23:42 -08002321 (erasesize - 1)) / writesize) << 2;
Shashank Mittalc20b5a12009-11-18 19:35:30 -08002322 unsigned onenand_startaddr2 = DEVICE_BUFFERRAM_0 << 15;
2323 unsigned onenand_startbuffer = DATARAM0_0 << 8;
Ajay Dudanib01e5062011-12-03 23:23:42 -08002324 unsigned onenand_sysconfig1 = (raw_mode == 1) ? ONENAND_SYSCFG1_ECCDIS :
2325 ONENAND_SYSCFG1_ECCENA;
Shashank Mittalc20b5a12009-11-18 19:35:30 -08002326
2327 unsigned controller_status;
2328 unsigned interrupt_status;
2329 unsigned ecc_status;
Ajay Dudanib01e5062011-12-03 23:23:42 -08002330 if (raw_mode != 1) {
Shashank Mittalad3d05c2009-11-19 15:53:57 -08002331 int isbad = 0;
2332 isbad = flash_onenand_block_isbad(cmdlist, ptrlist, page);
2333 if (isbad)
2334 return -2;
2335 }
Shashank Mittalc20b5a12009-11-18 19:35:30 -08002336 //static int oobfree_offset[8] = {2, 14, 18, 30, 34, 46, 50, 62};
2337 //static int oobfree_length[8] = {3, 2, 3, 2, 3, 2, 3, 2};
2338
2339 data->sfbcfg = SFLASH_BCFG;
Ajay Dudanib01e5062011-12-03 23:23:42 -08002340 data->sfcmd[0] = SFLASH_PREPCMD(7, 0, 0,
2341 NAND_SFCMD_CMDXS,
2342 NAND_SFCMD_ASYNC, NAND_SFCMD_REGWR);
2343 data->sfcmd[1] = SFLASH_PREPCMD(0, 0, 32,
2344 NAND_SFCMD_CMDXS,
2345 NAND_SFCMD_ASYNC, NAND_SFCMD_INTHI);
2346 data->sfcmd[2] = SFLASH_PREPCMD(3, 7, 0,
2347 NAND_SFCMD_DATXS,
2348 NAND_SFCMD_ASYNC, NAND_SFCMD_REGRD);
2349 data->sfcmd[3] = SFLASH_PREPCMD(256, 0, 0,
2350 NAND_SFCMD_DATXS,
2351 NAND_SFCMD_ASYNC, NAND_SFCMD_DATRD);
2352 data->sfcmd[4] = SFLASH_PREPCMD(256, 0, 0,
2353 NAND_SFCMD_DATXS,
2354 NAND_SFCMD_ASYNC, NAND_SFCMD_DATRD);
2355 data->sfcmd[5] = SFLASH_PREPCMD(256, 0, 0,
2356 NAND_SFCMD_DATXS,
2357 NAND_SFCMD_ASYNC, NAND_SFCMD_DATRD);
2358 data->sfcmd[6] = SFLASH_PREPCMD(256, 0, 0,
2359 NAND_SFCMD_DATXS,
2360 NAND_SFCMD_ASYNC, NAND_SFCMD_DATRD);
2361 data->sfcmd[7] = SFLASH_PREPCMD(32, 0, 0,
2362 NAND_SFCMD_DATXS,
2363 NAND_SFCMD_ASYNC, NAND_SFCMD_DATRD);
2364 data->sfcmd[8] = SFLASH_PREPCMD(4, 10, 0,
2365 NAND_SFCMD_CMDXS,
2366 NAND_SFCMD_ASYNC, NAND_SFCMD_REGWR);
Shashank Mittalc20b5a12009-11-18 19:35:30 -08002367 data->sfexec = 1;
2368 data->sfstat[0] = CLEAN_DATA_32;
2369 data->sfstat[1] = CLEAN_DATA_32;
2370 data->sfstat[2] = CLEAN_DATA_32;
2371 data->sfstat[3] = CLEAN_DATA_32;
2372 data->sfstat[4] = CLEAN_DATA_32;
2373 data->sfstat[5] = CLEAN_DATA_32;
2374 data->sfstat[6] = CLEAN_DATA_32;
2375 data->sfstat[7] = CLEAN_DATA_32;
2376 data->sfstat[8] = CLEAN_DATA_32;
2377
Ajay Dudanib01e5062011-12-03 23:23:42 -08002378 data->addr0 =
2379 (ONENAND_INTERRUPT_STATUS << 16) | (ONENAND_SYSTEM_CONFIG_1);
2380 data->addr1 =
2381 (ONENAND_START_ADDRESS_8 << 16) | (ONENAND_START_ADDRESS_1);
2382 data->addr2 = (ONENAND_START_BUFFER << 16) | (ONENAND_START_ADDRESS_2);
2383 data->addr3 = (ONENAND_ECC_STATUS << 16) | (ONENAND_COMMAND);
Shashank Mittalc20b5a12009-11-18 19:35:30 -08002384 data->addr4 = (ONENAND_CONTROLLER_STATUS << 16) |
Ajay Dudanib01e5062011-12-03 23:23:42 -08002385 (ONENAND_INTERRUPT_STATUS);
2386 data->addr5 =
2387 (ONENAND_INTERRUPT_STATUS << 16) | (ONENAND_SYSTEM_CONFIG_1);
2388 data->addr6 =
2389 (ONENAND_START_ADDRESS_3 << 16) | (ONENAND_START_ADDRESS_1);
2390 data->data0 = (ONENAND_CLRINTR << 16) | (onenand_sysconfig1);
2391 data->data1 = (onenand_startaddr8 << 16) | (onenand_startaddr1);
2392 data->data2 = (onenand_startbuffer << 16) | (onenand_startaddr2);
2393 data->data3 = (CLEAN_DATA_16 << 16) | (ONENAND_CMDLOADSPARE);
2394 data->data4 = (CLEAN_DATA_16 << 16) | (CLEAN_DATA_16);
2395 data->data5 = (ONENAND_CLRINTR << 16) | (ONENAND_SYSCFG1_ECCENA);
2396 data->data6 = (ONENAND_STARTADDR3_RES << 16) | (ONENAND_STARTADDR1_RES);
Shashank Mittalc20b5a12009-11-18 19:35:30 -08002397 data->macro[0] = 0x0200;
2398 data->macro[1] = 0x0300;
2399 data->macro[2] = 0x0400;
2400 data->macro[3] = 0x0500;
2401 data->macro[4] = 0x8010;
2402
2403 /*************************************************************/
Ajay Dudanib01e5062011-12-03 23:23:42 -08002404 /* Write necessary address registers in the onenand device */
Shashank Mittalc20b5a12009-11-18 19:35:30 -08002405 /*************************************************************/
2406
2407 /* Enable and configure the SFlash controller */
2408 cmd->cmd = 0 | CMD_OCB;
2409 cmd->src = paddr(&data->sfbcfg);
2410 cmd->dst = NAND_SFLASHC_BURST_CFG;
2411 cmd->len = 4;
2412 cmd++;
2413
2414 /* Block on cmd ready and write CMD register */
2415 cmd->cmd = DST_CRCI_NAND_CMD;
2416 cmd->src = paddr(&data->sfcmd[0]);
2417 cmd->dst = NAND_SFLASHC_CMD;
2418 cmd->len = 4;
2419 cmd++;
2420
2421 /* Write the ADDR0 and ADDR1 registers */
2422 cmd->cmd = 0;
2423 cmd->src = paddr(&data->addr0);
2424 cmd->dst = NAND_ADDR0;
2425 cmd->len = 8;
2426 cmd++;
2427
2428 /* Write the ADDR2 ADDR3 ADDR4 ADDR5 registers */
2429 cmd->cmd = 0;
2430 cmd->src = paddr(&data->addr2);
2431 cmd->dst = NAND_ADDR2;
2432 cmd->len = 16;
2433 cmd++;
2434
2435 /* Write the ADDR6 registers */
2436 cmd->cmd = 0;
2437 cmd->src = paddr(&data->addr6);
2438 cmd->dst = NAND_ADDR6;
2439 cmd->len = 4;
2440 cmd++;
2441
2442 /* Write the GENP0, GENP1, GENP2, GENP3 registers */
2443 cmd->cmd = 0;
2444 cmd->src = paddr(&data->data0);
2445 cmd->dst = NAND_GENP_REG0;
2446 cmd->len = 16;
2447 cmd++;
2448
2449 /* Write the FLASH_DEV_CMD4,5,6 registers */
2450 cmd->cmd = 0;
2451 cmd->src = paddr(&data->data4);
2452 cmd->dst = NAND_DEV_CMD4;
2453 cmd->len = 12;
2454 cmd++;
2455
2456 /* Kick the execute command */
2457 cmd->cmd = 0;
2458 cmd->src = paddr(&data->sfexec);
2459 cmd->dst = NAND_SFLASHC_EXEC_CMD;
2460 cmd->len = 4;
2461 cmd++;
2462
2463 /* Block on data ready, and read the status register */
2464 cmd->cmd = SRC_CRCI_NAND_DATA;
2465 cmd->src = NAND_SFLASHC_STATUS;
2466 cmd->dst = paddr(&data->sfstat[0]);
2467 cmd->len = 4;
2468 cmd++;
2469
2470 /*************************************************************/
2471 /* Wait for the interrupt from the Onenand device controller */
2472 /*************************************************************/
2473
2474 /* Block on cmd ready and write CMD register */
2475 cmd->cmd = DST_CRCI_NAND_CMD;
2476 cmd->src = paddr(&data->sfcmd[1]);
2477 cmd->dst = NAND_SFLASHC_CMD;
2478 cmd->len = 4;
2479 cmd++;
2480
2481 /* Kick the execute command */
2482 cmd->cmd = 0;
2483 cmd->src = paddr(&data->sfexec);
2484 cmd->dst = NAND_SFLASHC_EXEC_CMD;
2485 cmd->len = 4;
2486 cmd++;
2487
2488 /* Block on data ready, and read the status register */
2489 cmd->cmd = SRC_CRCI_NAND_DATA;
2490 cmd->src = NAND_SFLASHC_STATUS;
2491 cmd->dst = paddr(&data->sfstat[1]);
2492 cmd->len = 4;
2493 cmd++;
2494
Shashank Mittalc20b5a12009-11-18 19:35:30 -08002495 /*************************************************************/
Ajay Dudanib01e5062011-12-03 23:23:42 -08002496 /* Read necessary status registers from the onenand device */
Shashank Mittalc20b5a12009-11-18 19:35:30 -08002497 /*************************************************************/
2498
2499 /* Block on cmd ready and write CMD register */
2500 cmd->cmd = DST_CRCI_NAND_CMD;
2501 cmd->src = paddr(&data->sfcmd[2]);
2502 cmd->dst = NAND_SFLASHC_CMD;
2503 cmd->len = 4;
2504 cmd++;
2505
2506 /* Kick the execute command */
2507 cmd->cmd = 0;
2508 cmd->src = paddr(&data->sfexec);
2509 cmd->dst = NAND_SFLASHC_EXEC_CMD;
2510 cmd->len = 4;
2511 cmd++;
2512
2513 /* Block on data ready, and read the status register */
2514 cmd->cmd = SRC_CRCI_NAND_DATA;
2515 cmd->src = NAND_SFLASHC_STATUS;
2516 cmd->dst = paddr(&data->sfstat[2]);
2517 cmd->len = 4;
2518 cmd++;
2519
2520 /* Read the GENP3 register */
2521 cmd->cmd = 0;
2522 cmd->src = NAND_GENP_REG3;
2523 cmd->dst = paddr(&data->data3);
2524 cmd->len = 4;
2525 cmd++;
2526
2527 /* Read the DEVCMD4 register */
2528 cmd->cmd = 0;
2529 cmd->src = NAND_DEV_CMD4;
2530 cmd->dst = paddr(&data->data4);
2531 cmd->len = 4;
2532 cmd++;
2533
Shashank Mittalc20b5a12009-11-18 19:35:30 -08002534 /*************************************************************/
Ajay Dudanib01e5062011-12-03 23:23:42 -08002535 /* Read the data ram area from the onenand buffer ram */
Shashank Mittalc20b5a12009-11-18 19:35:30 -08002536 /*************************************************************/
2537
2538 if (addr) {
2539
Ajay Dudanib01e5062011-12-03 23:23:42 -08002540 data->data3 = (CLEAN_DATA_16 << 16) | (ONENAND_CMDLOAD);
Shashank Mittalc20b5a12009-11-18 19:35:30 -08002541
2542 for (i = 0; i < 4; i++) {
2543
Ajay Dudanib01e5062011-12-03 23:23:42 -08002544 /* Block on cmd ready and write CMD register */
2545 cmd->cmd = DST_CRCI_NAND_CMD;
2546 cmd->src = paddr(&data->sfcmd[3 + i]);
2547 cmd->dst = NAND_SFLASHC_CMD;
2548 cmd->len = 4;
2549 cmd++;
Shashank Mittalc20b5a12009-11-18 19:35:30 -08002550
Ajay Dudanib01e5062011-12-03 23:23:42 -08002551 /* Write the MACRO1 register */
2552 cmd->cmd = 0;
2553 cmd->src = paddr(&data->macro[i]);
2554 cmd->dst = NAND_MACRO1_REG;
2555 cmd->len = 4;
2556 cmd++;
Shashank Mittalc20b5a12009-11-18 19:35:30 -08002557
Ajay Dudanib01e5062011-12-03 23:23:42 -08002558 /* Kick the execute command */
2559 cmd->cmd = 0;
2560 cmd->src = paddr(&data->sfexec);
2561 cmd->dst = NAND_SFLASHC_EXEC_CMD;
2562 cmd->len = 4;
2563 cmd++;
Shashank Mittalc20b5a12009-11-18 19:35:30 -08002564
Ajay Dudanib01e5062011-12-03 23:23:42 -08002565 /* Block on data rdy, & read status register */
2566 cmd->cmd = SRC_CRCI_NAND_DATA;
2567 cmd->src = NAND_SFLASHC_STATUS;
2568 cmd->dst = paddr(&data->sfstat[3 + i]);
2569 cmd->len = 4;
2570 cmd++;
Shashank Mittalc20b5a12009-11-18 19:35:30 -08002571
Ajay Dudanib01e5062011-12-03 23:23:42 -08002572 /* Transfer nand ctlr buf contents to usr buf */
2573 cmd->cmd = 0;
2574 cmd->src = NAND_FLASH_BUFFER;
2575 cmd->dst = curr_addr;
2576 cmd->len = 512;
2577 curr_addr += 512;
2578 cmd++;
Shashank Mittalc20b5a12009-11-18 19:35:30 -08002579 }
2580 }
2581
Shashank Mittalad3d05c2009-11-19 15:53:57 -08002582 /* Read oob bytes in Raw Mode */
Ajay Dudanib01e5062011-12-03 23:23:42 -08002583 if (raw_mode == 1) {
2584 /* Block on cmd ready and write CMD register */
2585 cmd->cmd = DST_CRCI_NAND_CMD;
2586 cmd->src = paddr(&data->sfcmd[7]);
2587 cmd->dst = NAND_SFLASHC_CMD;
2588 cmd->len = 4;
2589 cmd++;
Shashank Mittalad3d05c2009-11-19 15:53:57 -08002590
Ajay Dudanib01e5062011-12-03 23:23:42 -08002591 /* Write the MACRO1 register */
2592 cmd->cmd = 0;
2593 cmd->src = paddr(&data->macro[4]);
2594 cmd->dst = NAND_MACRO1_REG;
2595 cmd->len = 4;
2596 cmd++;
Shashank Mittalad3d05c2009-11-19 15:53:57 -08002597
Ajay Dudanib01e5062011-12-03 23:23:42 -08002598 /* Kick the execute command */
2599 cmd->cmd = 0;
2600 cmd->src = paddr(&data->sfexec);
2601 cmd->dst = NAND_SFLASHC_EXEC_CMD;
2602 cmd->len = 4;
2603 cmd++;
Shashank Mittalad3d05c2009-11-19 15:53:57 -08002604
Ajay Dudanib01e5062011-12-03 23:23:42 -08002605 /* Block on data rdy, & read status register */
2606 cmd->cmd = SRC_CRCI_NAND_DATA;
2607 cmd->src = NAND_SFLASHC_STATUS;
2608 cmd->dst = paddr(&data->sfstat[7]);
2609 cmd->len = 4;
2610 cmd++;
Shashank Mittalad3d05c2009-11-19 15:53:57 -08002611
Ajay Dudanib01e5062011-12-03 23:23:42 -08002612 /* Transfer nand ctlr buf contents to usr buf */
2613 cmd->cmd = 0;
2614 cmd->src = NAND_FLASH_BUFFER;
2615 cmd->dst = curr_addr;
2616 cmd->len = 64;
2617 curr_addr += 64;
2618 cmd++;
Shashank Mittalad3d05c2009-11-19 15:53:57 -08002619 }
2620
Shashank Mittalc20b5a12009-11-18 19:35:30 -08002621 /*************************************************************/
Ajay Dudanib01e5062011-12-03 23:23:42 -08002622 /* Restore the necessary registers to proper values */
Shashank Mittalc20b5a12009-11-18 19:35:30 -08002623 /*************************************************************/
2624
2625 /* Block on cmd ready and write CMD register */
2626 cmd->cmd = DST_CRCI_NAND_CMD;
2627 cmd->src = paddr(&data->sfcmd[8]);
2628 cmd->dst = NAND_SFLASHC_CMD;
2629 cmd->len = 4;
2630 cmd++;
2631
2632 /* Kick the execute command */
2633 cmd->cmd = 0;
2634 cmd->src = paddr(&data->sfexec);
2635 cmd->dst = NAND_SFLASHC_EXEC_CMD;
2636 cmd->len = 4;
2637 cmd++;
2638
2639 /* Block on data ready, and read the status register */
2640 cmd->cmd = SRC_CRCI_NAND_DATA | CMD_OCU | CMD_LC;
2641 cmd->src = NAND_SFLASHC_STATUS;
2642 cmd->dst = paddr(&data->sfstat[8]);
2643 cmd->len = 4;
2644 cmd++;
2645
Ajay Dudanib01e5062011-12-03 23:23:42 -08002646 ptr[0] = (paddr(cmdlist) >> 3) | CMD_PTR_LP;
Shashank Mittalc20b5a12009-11-18 19:35:30 -08002647
Ajay Dudanib01e5062011-12-03 23:23:42 -08002648 dmov_exec_cmdptr(DMOV_NAND_CHAN, ptr);
Shashank Mittalc20b5a12009-11-18 19:35:30 -08002649
Ajay Dudanib01e5062011-12-03 23:23:42 -08002650 ecc_status = (data->data3 >> 16) & 0x0000FFFF;
2651 interrupt_status = (data->data4 >> 0) & 0x0000FFFF;
2652 controller_status = (data->data4 >> 16) & 0x0000FFFF;
Shashank Mittalc20b5a12009-11-18 19:35:30 -08002653
2654#if VERBOSE
Ajay Dudanib01e5062011-12-03 23:23:42 -08002655 dprintf(INFO, "\n%s: sflash status %x %x %x %x %x %x %x"
2656 "%x %x\n", __func__,
2657 data->sfstat[0],
2658 data->sfstat[1],
2659 data->sfstat[2],
2660 data->sfstat[3],
2661 data->sfstat[4],
2662 data->sfstat[5], data->sfstat[6], data->sfstat[7]);
Shashank Mittalc20b5a12009-11-18 19:35:30 -08002663
Ajay Dudanib01e5062011-12-03 23:23:42 -08002664 dprintf(INFO, "%s: controller_status = %x\n", __func__,
2665 controller_status);
2666 dprintf(INFO, "%s: interrupt_status = %x\n", __func__,
2667 interrupt_status);
2668 dprintf(INFO, "%s: ecc_status = %x\n", __func__, ecc_status);
Shashank Mittalc20b5a12009-11-18 19:35:30 -08002669#endif
Ajay Dudanib01e5062011-12-03 23:23:42 -08002670 /* Check for errors, protection violations etc */
2671 if ((controller_status != 0)
2672 || (data->sfstat[0] & 0x110)
2673 || (data->sfstat[1] & 0x110)
2674 || (data->sfstat[2] & 0x110)
2675 || ((data->sfstat[3] & 0x110) && (addr))
2676 || ((data->sfstat[4] & 0x110) && (addr))
2677 || ((data->sfstat[5] & 0x110) &&
2678 (addr)) || ((data->sfstat[6] & 0x110) && (addr))) {
2679 dprintf(INFO, "%s: ECC/MPU/OP error\n", __func__);
2680 return -1;
2681 }
Shashank Mittalc20b5a12009-11-18 19:35:30 -08002682#if VERBOSE
2683 dprintf(INFO, "read page %d: status: %x %x %x %x\n",
Ajay Dudanib01e5062011-12-03 23:23:42 -08002684 page, data[5], data[6], data[7], data[8]);
2685 for (n = 0; n < 4; n++) {
2686 ptr = (unsigned *)(addr + 512 * n);
2687 dprintf(INFO, "data%d: %x %x %x %x\n", n, ptr[0], ptr[1],
2688 ptr[2], ptr[3]);
2689 ptr = (unsigned *)(spareaddr + 16 * n);
2690 dprintf(INFO, "spare data%d %x %x %x %x\n", n, ptr[0],
2691 ptr[1], ptr[2], ptr[3]);
Shashank Mittalc20b5a12009-11-18 19:35:30 -08002692 }
2693#endif
2694
2695 return 0;
2696}
2697
Shashank Mittalc20b5a12009-11-18 19:35:30 -08002698struct data_onenand_write {
2699 unsigned sfbcfg;
2700 unsigned sfcmd[9];
2701 unsigned sfexec;
2702 unsigned sfstat[9];
2703 unsigned addr0;
2704 unsigned addr1;
2705 unsigned addr2;
2706 unsigned addr3;
2707 unsigned addr4;
2708 unsigned addr5;
2709 unsigned addr6;
2710 unsigned data0;
2711 unsigned data1;
2712 unsigned data2;
2713 unsigned data3;
2714 unsigned data4;
2715 unsigned data5;
2716 unsigned data6;
2717 unsigned macro[5];
2718};
2719
Ajay Dudanib01e5062011-12-03 23:23:42 -08002720static int
2721_flash_onenand_write_page(dmov_s * cmdlist, unsigned *ptrlist,
2722 unsigned page, const void *_addr,
2723 const void *_spareaddr, unsigned raw_mode)
Shashank Mittalc20b5a12009-11-18 19:35:30 -08002724{
2725 dmov_s *cmd = cmdlist;
2726 unsigned *ptr = ptrlist;
Ajay Dudanib01e5062011-12-03 23:23:42 -08002727 struct data_onenand_write *data = (void *)(ptrlist + 4);
2728 unsigned addr = (unsigned)_addr;
2729 unsigned addr_curr = (unsigned)_addr;
2730 char *spareaddr = (char *)_spareaddr;
Shashank Mittalc20b5a12009-11-18 19:35:30 -08002731 unsigned i, j, k;
2732
Channagoud Kadabibeb17d52011-03-25 17:14:00 +05302733 unsigned erasesize = (flash_pagesize * num_pages_per_blk);
Shashank Mittaldcc2e352009-11-19 19:11:16 -08002734 unsigned writesize = flash_pagesize;
Shashank Mittalc20b5a12009-11-18 19:35:30 -08002735
Shashank Mittaldcc2e352009-11-19 19:11:16 -08002736 unsigned onenand_startaddr1 = (page * flash_pagesize) / erasesize;
2737 unsigned onenand_startaddr8 = (((unsigned)(page * flash_pagesize) &
Ajay Dudanib01e5062011-12-03 23:23:42 -08002738 (erasesize - 1)) / writesize) << 2;
Shashank Mittalc20b5a12009-11-18 19:35:30 -08002739 unsigned onenand_startaddr2 = DEVICE_BUFFERRAM_0 << 15;
2740 unsigned onenand_startbuffer = DATARAM0_0 << 8;
Ajay Dudanib01e5062011-12-03 23:23:42 -08002741 unsigned onenand_sysconfig1 = (raw_mode == 1) ? ONENAND_SYSCFG1_ECCDIS :
2742 ONENAND_SYSCFG1_ECCENA;
Shashank Mittalc20b5a12009-11-18 19:35:30 -08002743
2744 unsigned controller_status;
2745 unsigned interrupt_status;
2746 unsigned ecc_status;
2747
2748 char flash_oob[64];
2749
Ajay Dudanib01e5062011-12-03 23:23:42 -08002750 unsigned oobfree_offset[8] = { 2, 14, 18, 30, 34, 46, 50, 62 };
2751 unsigned oobfree_length[8] = { 3, 2, 3, 2, 3, 2, 3, 2 };
Shashank Mittalc20b5a12009-11-18 19:35:30 -08002752
2753 for (i = 0; i < 64; i++)
2754 flash_oob[i] = 0xFF;
2755
2756 data->sfbcfg = SFLASH_BCFG;
Ajay Dudanib01e5062011-12-03 23:23:42 -08002757 data->sfcmd[0] = SFLASH_PREPCMD(256, 0, 0,
Shashank Mittalc20b5a12009-11-18 19:35:30 -08002758 NAND_SFCMD_CMDXS,
Ajay Dudanib01e5062011-12-03 23:23:42 -08002759 NAND_SFCMD_ASYNC, NAND_SFCMD_DATWR);
2760 data->sfcmd[1] = SFLASH_PREPCMD(256, 0, 0,
Shashank Mittalc20b5a12009-11-18 19:35:30 -08002761 NAND_SFCMD_CMDXS,
Ajay Dudanib01e5062011-12-03 23:23:42 -08002762 NAND_SFCMD_ASYNC, NAND_SFCMD_DATWR);
2763 data->sfcmd[2] = SFLASH_PREPCMD(256, 0, 0,
Shashank Mittalc20b5a12009-11-18 19:35:30 -08002764 NAND_SFCMD_CMDXS,
Ajay Dudanib01e5062011-12-03 23:23:42 -08002765 NAND_SFCMD_ASYNC, NAND_SFCMD_DATWR);
2766 data->sfcmd[3] = SFLASH_PREPCMD(256, 0, 0,
Shashank Mittalc20b5a12009-11-18 19:35:30 -08002767 NAND_SFCMD_CMDXS,
Ajay Dudanib01e5062011-12-03 23:23:42 -08002768 NAND_SFCMD_ASYNC, NAND_SFCMD_DATWR);
2769 data->sfcmd[4] = SFLASH_PREPCMD(32, 0, 0,
Shashank Mittalc20b5a12009-11-18 19:35:30 -08002770 NAND_SFCMD_CMDXS,
Ajay Dudanib01e5062011-12-03 23:23:42 -08002771 NAND_SFCMD_ASYNC, NAND_SFCMD_DATWR);
2772 data->sfcmd[5] = SFLASH_PREPCMD(7, 0, 0,
Shashank Mittalc20b5a12009-11-18 19:35:30 -08002773 NAND_SFCMD_CMDXS,
Ajay Dudanib01e5062011-12-03 23:23:42 -08002774 NAND_SFCMD_ASYNC, NAND_SFCMD_REGWR);
2775 data->sfcmd[6] = SFLASH_PREPCMD(0, 0, 32,
Shashank Mittalc20b5a12009-11-18 19:35:30 -08002776 NAND_SFCMD_CMDXS,
Ajay Dudanib01e5062011-12-03 23:23:42 -08002777 NAND_SFCMD_ASYNC, NAND_SFCMD_INTHI);
2778 data->sfcmd[7] = SFLASH_PREPCMD(3, 7, 0,
Shashank Mittalc20b5a12009-11-18 19:35:30 -08002779 NAND_SFCMD_DATXS,
Ajay Dudanib01e5062011-12-03 23:23:42 -08002780 NAND_SFCMD_ASYNC, NAND_SFCMD_REGRD);
2781 data->sfcmd[8] = SFLASH_PREPCMD(4, 10, 0,
Shashank Mittalc20b5a12009-11-18 19:35:30 -08002782 NAND_SFCMD_CMDXS,
Ajay Dudanib01e5062011-12-03 23:23:42 -08002783 NAND_SFCMD_ASYNC, NAND_SFCMD_REGWR);
Shashank Mittalc20b5a12009-11-18 19:35:30 -08002784 data->sfexec = 1;
2785
2786 data->sfstat[0] = CLEAN_DATA_32;
2787 data->sfstat[1] = CLEAN_DATA_32;
2788 data->sfstat[2] = CLEAN_DATA_32;
2789 data->sfstat[3] = CLEAN_DATA_32;
2790 data->sfstat[4] = CLEAN_DATA_32;
2791 data->sfstat[5] = CLEAN_DATA_32;
2792 data->sfstat[6] = CLEAN_DATA_32;
2793 data->sfstat[7] = CLEAN_DATA_32;
2794 data->sfstat[8] = CLEAN_DATA_32;
Ajay Dudanib01e5062011-12-03 23:23:42 -08002795 data->addr0 =
2796 (ONENAND_INTERRUPT_STATUS << 16) | (ONENAND_SYSTEM_CONFIG_1);
2797 data->addr1 =
2798 (ONENAND_START_ADDRESS_8 << 16) | (ONENAND_START_ADDRESS_1);
2799 data->addr2 = (ONENAND_START_BUFFER << 16) | (ONENAND_START_ADDRESS_2);
2800 data->addr3 = (ONENAND_ECC_STATUS << 16) | (ONENAND_COMMAND);
Shashank Mittalc20b5a12009-11-18 19:35:30 -08002801 data->addr4 = (ONENAND_CONTROLLER_STATUS << 16) |
Ajay Dudanib01e5062011-12-03 23:23:42 -08002802 (ONENAND_INTERRUPT_STATUS);
2803 data->addr5 =
2804 (ONENAND_INTERRUPT_STATUS << 16) | (ONENAND_SYSTEM_CONFIG_1);
2805 data->addr6 =
2806 (ONENAND_START_ADDRESS_3 << 16) | (ONENAND_START_ADDRESS_1);
2807 data->data0 = (ONENAND_CLRINTR << 16) | (onenand_sysconfig1);
2808 data->data1 = (onenand_startaddr8 << 16) | (onenand_startaddr1);
2809 data->data2 = (onenand_startbuffer << 16) | (onenand_startaddr2);
2810 data->data3 = (CLEAN_DATA_16 << 16) | (ONENAND_CMDPROGSPARE);
2811 data->data3 = (CLEAN_DATA_16 << 16) | (ONENAND_CMDPROGSPARE);
2812 data->data4 = (CLEAN_DATA_16 << 16) | (CLEAN_DATA_16);
2813 data->data5 = (ONENAND_CLRINTR << 16) | (ONENAND_SYSCFG1_ECCENA);
2814 data->data6 = (ONENAND_STARTADDR3_RES << 16) | (ONENAND_STARTADDR1_RES);
Shashank Mittalc20b5a12009-11-18 19:35:30 -08002815 data->macro[0] = 0x0200;
2816 data->macro[1] = 0x0300;
2817 data->macro[2] = 0x0400;
2818 data->macro[3] = 0x0500;
2819 data->macro[4] = 0x8010;
2820
Shashank Mittalc20b5a12009-11-18 19:35:30 -08002821 /*************************************************************/
Ajay Dudanib01e5062011-12-03 23:23:42 -08002822 /* Write the data ram area in the onenand buffer ram */
Shashank Mittalc20b5a12009-11-18 19:35:30 -08002823 /*************************************************************/
2824
2825 /* Enable and configure the SFlash controller */
2826 cmd->cmd = 0 | CMD_OCB;
2827 cmd->src = paddr(&data->sfbcfg);
2828 cmd->dst = NAND_SFLASHC_BURST_CFG;
2829 cmd->len = 4;
2830 cmd++;
2831
2832 if (addr) {
Ajay Dudanib01e5062011-12-03 23:23:42 -08002833 data->data3 = (CLEAN_DATA_16 << 16) | (ONENAND_CMDPROG);
Shashank Mittalc20b5a12009-11-18 19:35:30 -08002834
2835 for (i = 0; i < 4; i++) {
2836
Ajay Dudanib01e5062011-12-03 23:23:42 -08002837 /* Block on cmd ready and write CMD register */
2838 cmd->cmd = DST_CRCI_NAND_CMD;
2839 cmd->src = paddr(&data->sfcmd[i]);
2840 cmd->dst = NAND_SFLASHC_CMD;
2841 cmd->len = 4;
2842 cmd++;
Shashank Mittalc20b5a12009-11-18 19:35:30 -08002843
Ajay Dudanib01e5062011-12-03 23:23:42 -08002844 /* Trnsfr usr buf contents to nand ctlr buf */
2845 cmd->cmd = 0;
2846 cmd->src = paddr(addr_curr);
2847 cmd->dst = NAND_FLASH_BUFFER;
2848 cmd->len = 512;
2849 if (!raw_mode)
2850 addr_curr += 512;
2851 cmd++;
Shashank Mittalc20b5a12009-11-18 19:35:30 -08002852
Ajay Dudanib01e5062011-12-03 23:23:42 -08002853 /* Write the MACRO1 register */
2854 cmd->cmd = 0;
2855 cmd->src = paddr(&data->macro[i]);
2856 cmd->dst = NAND_MACRO1_REG;
2857 cmd->len = 4;
2858 cmd++;
Shashank Mittalc20b5a12009-11-18 19:35:30 -08002859
Ajay Dudanib01e5062011-12-03 23:23:42 -08002860 /* Kick the execute command */
2861 cmd->cmd = 0;
2862 cmd->src = paddr(&data->sfexec);
2863 cmd->dst = NAND_SFLASHC_EXEC_CMD;
2864 cmd->len = 4;
2865 cmd++;
Shashank Mittalc20b5a12009-11-18 19:35:30 -08002866
Ajay Dudanib01e5062011-12-03 23:23:42 -08002867 /* Block on data rdy, & read status register */
2868 cmd->cmd = SRC_CRCI_NAND_DATA;
2869 cmd->src = NAND_SFLASHC_STATUS;
2870 cmd->dst = paddr(&data->sfstat[i]);
2871 cmd->len = 4;
2872 cmd++;
Shashank Mittalc20b5a12009-11-18 19:35:30 -08002873
2874 }
2875 }
2876
2877 /* Block on cmd ready and write CMD register */
2878 cmd->cmd = DST_CRCI_NAND_CMD;
2879 cmd->src = paddr(&data->sfcmd[4]);
2880 cmd->dst = NAND_SFLASHC_CMD;
2881 cmd->len = 4;
2882 cmd++;
2883
Ajay Dudanib01e5062011-12-03 23:23:42 -08002884 if (spareaddr) {
2885 // Auto mode
2886 for (i = 0, k = 0; i < 8; i++) {
2887 for (j = 0; j < oobfree_length[i]; j++) {
2888 flash_oob[j + oobfree_offset[i]] = spareaddr[k];
2889 k++;
2890 }
2891 }
Shashank Mittalc20b5a12009-11-18 19:35:30 -08002892
Ajay Dudanib01e5062011-12-03 23:23:42 -08002893 cmd->cmd = 0;
2894 cmd->src = paddr(&flash_oob);
2895 cmd->dst = NAND_FLASH_BUFFER;
2896 cmd->len = 64;
2897 cmd++;
Shashank Mittalc20b5a12009-11-18 19:35:30 -08002898 }
2899
Ajay Dudanib01e5062011-12-03 23:23:42 -08002900 if (raw_mode) {
Shashank Mittald0c836d2009-11-20 10:31:18 -08002901 cmd->cmd = 0;
2902 cmd->src = paddr(addr_curr);
2903 cmd->dst = NAND_FLASH_BUFFER;
2904 cmd->len = 64;
2905 cmd++;
2906 }
2907
Shashank Mittalc20b5a12009-11-18 19:35:30 -08002908 /* Write the MACRO1 register */
2909 cmd->cmd = 0;
2910 cmd->src = paddr(&data->macro[4]);
2911 cmd->dst = NAND_MACRO1_REG;
2912 cmd->len = 4;
2913 cmd++;
2914
2915 /* Kick the execute command */
2916 cmd->cmd = 0;
2917 cmd->src = paddr(&data->sfexec);
2918 cmd->dst = NAND_SFLASHC_EXEC_CMD;
2919 cmd->len = 4;
2920 cmd++;
2921
2922 /* Block on data ready, and read the status register */
2923 cmd->cmd = SRC_CRCI_NAND_DATA;
2924 cmd->src = NAND_SFLASHC_STATUS;
2925 cmd->dst = paddr(&data->sfstat[4]);
2926 cmd->len = 4;
2927 cmd++;
2928
2929 /*************************************************************/
Ajay Dudanib01e5062011-12-03 23:23:42 -08002930 /* Write necessary address registers in the onenand device */
Shashank Mittalc20b5a12009-11-18 19:35:30 -08002931 /*************************************************************/
2932
2933 /* Block on cmd ready and write CMD register */
2934 cmd->cmd = DST_CRCI_NAND_CMD;
2935 cmd->src = paddr(&data->sfcmd[5]);
2936 cmd->dst = NAND_SFLASHC_CMD;
2937 cmd->len = 4;
2938 cmd++;
2939
2940 /* Write the ADDR0 and ADDR1 registers */
2941 cmd->cmd = 0;
2942 cmd->src = paddr(&data->addr0);
2943 cmd->dst = NAND_ADDR0;
2944 cmd->len = 8;
2945 cmd++;
2946
2947 /* Write the ADDR2 ADDR3 ADDR4 ADDR5 registers */
2948 cmd->cmd = 0;
2949 cmd->src = paddr(&data->addr2);
2950 cmd->dst = NAND_ADDR2;
2951 cmd->len = 16;
2952 cmd++;
2953
2954 /* Write the ADDR6 registers */
2955 cmd->cmd = 0;
2956 cmd->src = paddr(&data->addr6);
2957 cmd->dst = NAND_ADDR6;
2958 cmd->len = 4;
2959 cmd++;
2960
2961 /* Write the GENP0, GENP1, GENP2, GENP3 registers */
2962 cmd->cmd = 0;
2963 cmd->src = paddr(&data->data0);
2964 cmd->dst = NAND_GENP_REG0;
2965 cmd->len = 16;
2966 cmd++;
2967
2968 /* Write the FLASH_DEV_CMD4,5,6 registers */
2969 cmd->cmd = 0;
2970 cmd->src = paddr(&data->data4);
2971 cmd->dst = NAND_DEV_CMD4;
2972 cmd->len = 12;
2973 cmd++;
2974
2975 /* Kick the execute command */
2976 cmd->cmd = 0;
2977 cmd->src = paddr(&data->sfexec);
2978 cmd->dst = NAND_SFLASHC_EXEC_CMD;
2979 cmd->len = 4;
2980 cmd++;
2981
2982 /* Block on data ready, and read the status register */
2983 cmd->cmd = SRC_CRCI_NAND_DATA;
2984 cmd->src = NAND_SFLASHC_STATUS;
2985 cmd->dst = paddr(&data->sfstat[5]);
2986 cmd->len = 4;
2987 cmd++;
2988
2989 /*************************************************************/
2990 /* Wait for the interrupt from the Onenand device controller */
2991 /*************************************************************/
2992
2993 /* Block on cmd ready and write CMD register */
2994 cmd->cmd = DST_CRCI_NAND_CMD;
2995 cmd->src = paddr(&data->sfcmd[6]);
2996 cmd->dst = NAND_SFLASHC_CMD;
2997 cmd->len = 4;
2998 cmd++;
2999
3000 /* Kick the execute command */
3001 cmd->cmd = 0;
3002 cmd->src = paddr(&data->sfexec);
3003 cmd->dst = NAND_SFLASHC_EXEC_CMD;
3004 cmd->len = 4;
3005 cmd++;
3006
3007 /* Block on data ready, and read the status register */
3008 cmd->cmd = SRC_CRCI_NAND_DATA;
3009 cmd->src = NAND_SFLASHC_STATUS;
3010 cmd->dst = paddr(&data->sfstat[6]);
3011 cmd->len = 4;
3012 cmd++;
3013
3014 /*************************************************************/
Ajay Dudanib01e5062011-12-03 23:23:42 -08003015 /* Read necessary status registers from the onenand device */
Shashank Mittalc20b5a12009-11-18 19:35:30 -08003016 /*************************************************************/
3017
3018 /* Block on cmd ready and write CMD register */
3019 cmd->cmd = DST_CRCI_NAND_CMD;
3020 cmd->src = paddr(&data->sfcmd[7]);
3021 cmd->dst = NAND_SFLASHC_CMD;
3022 cmd->len = 4;
3023 cmd++;
3024
3025 /* Kick the execute command */
3026 cmd->cmd = 0;
3027 cmd->src = paddr(&data->sfexec);
3028 cmd->dst = NAND_SFLASHC_EXEC_CMD;
3029 cmd->len = 4;
3030 cmd++;
3031
3032 /* Block on data ready, and read the status register */
3033 cmd->cmd = SRC_CRCI_NAND_DATA;
3034 cmd->src = NAND_SFLASHC_STATUS;
3035 cmd->dst = paddr(&data->sfstat[7]);
3036 cmd->len = 4;
3037 cmd++;
3038
3039 /* Read the GENP3 register */
3040 cmd->cmd = 0;
3041 cmd->src = NAND_GENP_REG3;
3042 cmd->dst = paddr(&data->data3);
3043 cmd->len = 4;
3044 cmd++;
3045
3046 /* Read the DEVCMD4 register */
3047 cmd->cmd = 0;
3048 cmd->src = NAND_DEV_CMD4;
3049 cmd->dst = paddr(&data->data4);
3050 cmd->len = 4;
3051 cmd++;
3052
Shashank Mittalc20b5a12009-11-18 19:35:30 -08003053 /*************************************************************/
Ajay Dudanib01e5062011-12-03 23:23:42 -08003054 /* Restore the necessary registers to proper values */
Shashank Mittalc20b5a12009-11-18 19:35:30 -08003055 /*************************************************************/
3056
3057 /* Block on cmd ready and write CMD register */
3058 cmd->cmd = DST_CRCI_NAND_CMD;
3059 cmd->src = paddr(&data->sfcmd[8]);
3060 cmd->dst = NAND_SFLASHC_CMD;
3061 cmd->len = 4;
3062 cmd++;
3063
3064 /* Kick the execute command */
3065 cmd->cmd = 0;
3066 cmd->src = paddr(&data->sfexec);
3067 cmd->dst = NAND_SFLASHC_EXEC_CMD;
3068 cmd->len = 4;
3069 cmd++;
3070
3071 /* Block on data ready, and read the status register */
3072 cmd->cmd = SRC_CRCI_NAND_DATA | CMD_OCU | CMD_LC;
3073 cmd->src = NAND_SFLASHC_STATUS;
3074 cmd->dst = paddr(&data->sfstat[8]);
3075 cmd->len = 4;
3076 cmd++;
3077
Shashank Mittalc20b5a12009-11-18 19:35:30 -08003078 ptr[0] = (paddr(cmdlist) >> 3) | CMD_PTR_LP;
3079
3080 dmov_exec_cmdptr(DMOV_NAND_CHAN, ptr);
3081
3082 ecc_status = (data->data3 >> 16) & 0x0000FFFF;
Ajay Dudanib01e5062011-12-03 23:23:42 -08003083 interrupt_status = (data->data4 >> 0) & 0x0000FFFF;
3084 controller_status = (data->data4 >> 16) & 0x0000FFFF;
Shashank Mittalc20b5a12009-11-18 19:35:30 -08003085
3086#if VERBOSE
Ajay Dudanib01e5062011-12-03 23:23:42 -08003087 dprintf(INFO, "\n%s: sflash status %x %x %x %x %x %x %x %x %x\n",
3088 __func__, data->sfstat[0], data->sfstat[1], data->sfstat[2],
3089 data->sfstat[3], data->sfstat[4], data->sfstat[5],
3090 data->sfstat[6], data->sfstat[7], data->sfstat[8]);
Shashank Mittalc20b5a12009-11-18 19:35:30 -08003091
3092 dprintf(INFO, "%s: controller_status = %x\n", __func__,
Ajay Dudanib01e5062011-12-03 23:23:42 -08003093 controller_status);
Shashank Mittalc20b5a12009-11-18 19:35:30 -08003094 dprintf(INFO, "%s: interrupt_status = %x\n", __func__,
Ajay Dudanib01e5062011-12-03 23:23:42 -08003095 interrupt_status);
3096 dprintf(INFO, "%s: ecc_status = %x\n", __func__, ecc_status);
Shashank Mittalc20b5a12009-11-18 19:35:30 -08003097#endif
3098 /* Check for errors, protection violations etc */
3099 if ((controller_status != 0)
Ajay Dudanib01e5062011-12-03 23:23:42 -08003100 || (data->sfstat[5] & 0x110)
3101 || (data->sfstat[6] & 0x110)
3102 || (data->sfstat[7] & 0x110)
3103 || (data->sfstat[8] & 0x110)
3104 || ((data->sfstat[0] & 0x110) && (addr))
3105 || ((data->sfstat[1] & 0x110) && (addr))
3106 || ((data->sfstat[2] & 0x110) &&
3107 (addr)) || ((data->sfstat[3] & 0x110) && (addr))) {
Shashank Mittalc20b5a12009-11-18 19:35:30 -08003108 dprintf(CRITICAL, "%s: ECC/MPU/OP error\n", __func__);
3109 return -1;
3110 }
3111
Shashank Mittalc20b5a12009-11-18 19:35:30 -08003112 return 0;
3113}
Shashank Mittald0c836d2009-11-20 10:31:18 -08003114
Ajay Dudanib01e5062011-12-03 23:23:42 -08003115static int
3116flash_onenand_mark_badblock(dmov_s * cmdlist, unsigned *ptrlist, unsigned page)
Shashank Mittald0c836d2009-11-20 10:31:18 -08003117{
Ajay Dudanib01e5062011-12-03 23:23:42 -08003118 memset(empty_buf, 0, 528);
3119 /* Going to first page of the block */
3120 if (page & num_pages_per_blk_mask)
3121 page = page - (page & num_pages_per_blk_mask);
3122 return _flash_onenand_write_page(cmdlist, ptrlist, page, empty_buf, 0,
3123 1);
Shashank Mittald0c836d2009-11-20 10:31:18 -08003124}
3125
Ajay Dudanib01e5062011-12-03 23:23:42 -08003126static int
3127flash_mark_badblock(dmov_s * cmdlist, unsigned *ptrlist, unsigned page)
Shashank Mittald0c836d2009-11-20 10:31:18 -08003128{
Ajay Dudanib01e5062011-12-03 23:23:42 -08003129 switch (flash_info.type) {
3130 case FLASH_8BIT_NAND_DEVICE:
3131 case FLASH_16BIT_NAND_DEVICE:
3132 return flash_nand_mark_badblock(cmdlist, ptrlist, page);
3133 case FLASH_ONENAND_DEVICE:
3134 return flash_onenand_mark_badblock(cmdlist, ptrlist, page);
3135 default:
3136 return -1;
Shashank Mittald0c836d2009-11-20 10:31:18 -08003137 }
3138}
3139
Ajay Dudanib01e5062011-12-03 23:23:42 -08003140unsigned flash_ctrl_hwinfo(dmov_s * cmdlist, unsigned *ptrlist)
Channagoud Kadabi404a7062011-03-21 19:27:50 +05303141{
3142 dmov_s *cmd = cmdlist;
3143 unsigned *ptr = ptrlist;
3144 unsigned *data = ptrlist + 4;
3145
3146 unsigned rv;
3147
3148 data[0] = 0xeeeeeeee;
Channagoud Kadabi404a7062011-03-21 19:27:50 +05303149
Ajay Dudanib01e5062011-12-03 23:23:42 -08003150 cmd[0].cmd = CMD_LC | CMD_OCB | CMD_OCU;
Channagoud Kadabi404a7062011-03-21 19:27:50 +05303151 cmd[0].src = NAND_HW_INFO;
3152 cmd[0].dst = paddr(&data[0]);
3153 cmd[0].len = 4;
3154
Channagoud Kadabi404a7062011-03-21 19:27:50 +05303155 ptr[0] = (paddr(cmd) >> 3) | CMD_PTR_LP;
3156 dmov_exec_cmdptr(DMOV_NAND_CHAN, ptr);
3157 rv = data[0];
3158
3159 return rv;
3160}
3161
Shashank Mittalc20b5a12009-11-18 19:35:30 -08003162/* Wrapper functions */
Ajay Dudanib01e5062011-12-03 23:23:42 -08003163static void flash_read_id(dmov_s * cmdlist, unsigned *ptrlist)
Shashank Mittalc20b5a12009-11-18 19:35:30 -08003164{
3165 int dev_found = 0;
3166 unsigned index;
Deepa Dinamanib67326d2012-11-26 11:57:22 -08003167 uint32_t hwinfo;
Shashank Mittalc20b5a12009-11-18 19:35:30 -08003168
3169 // Try to read id
3170 flash_nand_read_id(cmdlist, ptrlist);
3171 // Check if we support the device
Ajay Dudanib01e5062011-12-03 23:23:42 -08003172 for (index = 1;
3173 index <
3174 (sizeof(supported_flash) / sizeof(struct flash_identification));
3175 index++) {
Shashank Mittalc20b5a12009-11-18 19:35:30 -08003176 if ((flash_info.id & supported_flash[index].mask) ==
Ajay Dudanib01e5062011-12-03 23:23:42 -08003177 (supported_flash[index].
3178 flash_id & (supported_flash[index].mask))) {
Shashank Mittalc20b5a12009-11-18 19:35:30 -08003179 dev_found = 1;
3180 break;
3181 }
3182 }
3183
Ajay Dudanib01e5062011-12-03 23:23:42 -08003184 if (!dev_found) {
Shashank Mittalc20b5a12009-11-18 19:35:30 -08003185 flash_onenand_read_id(cmdlist, ptrlist);
Ajay Dudanib01e5062011-12-03 23:23:42 -08003186 for (index = 1;
3187 index <
3188 (sizeof(supported_flash) /
3189 sizeof(struct flash_identification)); index++) {
Shashank Mittalc20b5a12009-11-18 19:35:30 -08003190 if ((flash_info.id & supported_flash[index].mask) ==
Ajay Dudanib01e5062011-12-03 23:23:42 -08003191 (supported_flash[index].
3192 flash_id & (supported_flash[index].mask))) {
3193 dev_found = 1;
3194 break;
Shashank Mittalc20b5a12009-11-18 19:35:30 -08003195 }
3196 }
3197 }
3198
Ajay Dudanib01e5062011-12-03 23:23:42 -08003199 if (dev_found) {
Shashank Mittalc20b5a12009-11-18 19:35:30 -08003200 if (supported_flash[index].widebus)
3201 flash_info.type = FLASH_16BIT_NAND_DEVICE;
3202 else
3203 flash_info.type = FLASH_8BIT_NAND_DEVICE;
3204 if (supported_flash[index].onenand)
3205 flash_info.type = FLASH_ONENAND_DEVICE;
3206 flash_info.page_size = supported_flash[index].pagesize;
Shashank Mittaldcc2e352009-11-19 19:11:16 -08003207 flash_pagesize = flash_info.page_size;
Shashank Mittalc20b5a12009-11-18 19:35:30 -08003208 flash_info.block_size = supported_flash[index].blksize;
3209 flash_info.spare_size = supported_flash[index].oobsize;
Ajay Dudanib01e5062011-12-03 23:23:42 -08003210 if (flash_info.block_size && flash_info.page_size) {
Shashank Mittalc20b5a12009-11-18 19:35:30 -08003211 flash_info.num_blocks = supported_flash[index].density;
Chandan Uddaraju40605112010-08-09 14:25:08 -07003212 flash_info.num_blocks /= (flash_info.block_size);
Ajay Dudanib01e5062011-12-03 23:23:42 -08003213 } else {
Shashank Mittalc20b5a12009-11-18 19:35:30 -08003214 flash_info.num_blocks = 0;
3215 }
3216 ASSERT(flash_info.num_blocks);
Channagoud Kadabibeb17d52011-03-25 17:14:00 +05303217 // Use this for getting the next/current blocks
3218 num_pages_per_blk = flash_info.block_size / flash_pagesize;
3219 num_pages_per_blk_mask = num_pages_per_blk - 1;
Deepa Dinamanib67326d2012-11-26 11:57:22 -08003220
3221 hwinfo = flash_ctrl_hwinfo(cmdlist, ptrlist);
3222
Ajay Dudanib01e5062011-12-03 23:23:42 -08003223 //Look for 8bit BCH ECC Nand, TODO: ECC Correctability >= 8
Deepa Dinamanib67326d2012-11-26 11:57:22 -08003224 if (((hwinfo == 0x307) || (hwinfo == 0x4030))
Ajay Dudanib01e5062011-12-03 23:23:42 -08003225 && flash_info.id == 0x2600482c) {
Channagoud Kadabi404a7062011-03-21 19:27:50 +05303226 enable_bch_ecc = 1;
3227 }
Shashank Mittalc20b5a12009-11-18 19:35:30 -08003228 return;
3229 }
Channagoud Kadabi7cecb842011-12-22 18:18:21 +05303230 // Flash device is not supported, print flash device info and halt
Shashank Mittalc20b5a12009-11-18 19:35:30 -08003231 if (dev_found == 0) {
Channagoud Kadabi7cecb842011-12-22 18:18:21 +05303232 dprintf(CRITICAL, "NAND device is not supported: nandid: 0x%x \
3233 maker=0x%02x device=0x%02x\n", flash_info.id,
3234 flash_info.vendor, flash_info.device);
3235 ASSERT(0);
Shashank Mittalc20b5a12009-11-18 19:35:30 -08003236 }
3237 dprintf(INFO, "nandid: 0x%x maker=0x%02x device=0x%02x page_size=%d\n",
3238 flash_info.id, flash_info.vendor, flash_info.device,
3239 flash_info.page_size);
3240 dprintf(INFO, " spare_size=%d block_size=%d num_blocks=%d\n",
3241 flash_info.spare_size, flash_info.block_size,
3242 flash_info.num_blocks);
3243}
3244
Ajay Dudanib01e5062011-12-03 23:23:42 -08003245static int flash_erase_block(dmov_s * cmdlist, unsigned *ptrlist, unsigned page)
Shashank Mittalc20b5a12009-11-18 19:35:30 -08003246{
Ajay Dudanib01e5062011-12-03 23:23:42 -08003247 switch (flash_info.type) {
3248 case FLASH_8BIT_NAND_DEVICE:
3249 case FLASH_16BIT_NAND_DEVICE:
3250 return flash_nand_erase_block(cmdlist, ptrlist, page);
3251 case FLASH_ONENAND_DEVICE:
3252 return flash_onenand_erase_block(cmdlist, ptrlist, page);
3253 default:
3254 return -1;
Shashank Mittalc20b5a12009-11-18 19:35:30 -08003255 }
3256}
3257
Ajay Dudanib01e5062011-12-03 23:23:42 -08003258static int
3259_flash_read_page(dmov_s * cmdlist, unsigned *ptrlist,
3260 unsigned page, void *_addr, void *_spareaddr)
Shashank Mittalc20b5a12009-11-18 19:35:30 -08003261{
Ajay Dudanib01e5062011-12-03 23:23:42 -08003262 switch (flash_info.type) {
3263 case FLASH_8BIT_NAND_DEVICE:
3264 case FLASH_16BIT_NAND_DEVICE:
3265 if (interleaved_mode)
3266 return flash_nand_read_page_interleave(cmdlist, ptrlist,
3267 page, _addr,
3268 _spareaddr);
3269 else
3270 return _flash_nand_read_page(cmdlist, ptrlist, page,
3271 _addr, _spareaddr);
3272 case FLASH_ONENAND_DEVICE:
3273 return _flash_onenand_read_page(cmdlist, ptrlist, page, _addr,
3274 _spareaddr, 0);
3275 default:
3276 return -1;
Shashank Mittalc20b5a12009-11-18 19:35:30 -08003277 }
3278}
3279
Ajay Dudanib01e5062011-12-03 23:23:42 -08003280static int
3281_flash_block_isbad(dmov_s * cmdlist, unsigned *ptrlist, unsigned page)
Shashank Mittalad3d05c2009-11-19 15:53:57 -08003282{
Ajay Dudanib01e5062011-12-03 23:23:42 -08003283 switch (flash_info.type) {
3284 case FLASH_8BIT_NAND_DEVICE:
3285 case FLASH_16BIT_NAND_DEVICE:
3286 return flash_nand_block_isbad(cmdlist, ptrlist, page);
3287 case FLASH_ONENAND_DEVICE:
3288 return flash_onenand_block_isbad(cmdlist, ptrlist, page);
3289 default:
3290 return -1;
Shashank Mittalad3d05c2009-11-19 15:53:57 -08003291 }
3292}
Shashank Mittalc20b5a12009-11-18 19:35:30 -08003293
Ajay Dudanib01e5062011-12-03 23:23:42 -08003294static int
3295_flash_write_page(dmov_s * cmdlist, unsigned *ptrlist,
3296 unsigned page, const void *_addr, const void *_spareaddr)
Shashank Mittalc20b5a12009-11-18 19:35:30 -08003297{
Ajay Dudanib01e5062011-12-03 23:23:42 -08003298 switch (flash_info.type) {
3299 case FLASH_8BIT_NAND_DEVICE:
3300 case FLASH_16BIT_NAND_DEVICE:
3301 if (interleaved_mode)
3302 return flash_nand_write_page_interleave(cmdlist,
3303 ptrlist, page,
3304 _addr,
3305 _spareaddr, 0);
3306 else
3307 return _flash_nand_write_page(cmdlist, ptrlist, page,
3308 _addr, _spareaddr, 0);
3309 case FLASH_ONENAND_DEVICE:
3310 return _flash_onenand_write_page(cmdlist, ptrlist, page, _addr,
3311 _spareaddr, 0);
3312 default:
3313 return -1;
Shashank Mittalc20b5a12009-11-18 19:35:30 -08003314 }
3315}
3316
Dima Zavin03cf4312009-01-23 16:38:30 -08003317static unsigned *flash_ptrlist;
3318static dmov_s *flash_cmdlist;
Dima Zavin03cf4312009-01-23 16:38:30 -08003319
3320static struct ptable *flash_ptable = NULL;
3321
Dima Zavine5f64352009-03-02 16:04:20 -08003322void flash_init(void)
Dima Zavin03cf4312009-01-23 16:38:30 -08003323{
Channagoud Kadabib2fb6ba2011-07-29 19:19:01 +05303324 int i = 0;
Dima Zavine5f64352009-03-02 16:04:20 -08003325 ASSERT(flash_ptable == NULL);
Dima Zavin03cf4312009-01-23 16:38:30 -08003326
3327 flash_ptrlist = memalign(32, 1024);
3328 flash_cmdlist = memalign(32, 1024);
Ajay Dudani232ce812009-12-02 00:14:11 -08003329 flash_data = memalign(32, 4096 + 128);
3330 flash_spare = memalign(32, 128);
Dima Zavin03cf4312009-01-23 16:38:30 -08003331
Aparna Mallavarapuc5946f22013-04-08 21:44:51 +05303332 if (flash_ptrlist == NULL || flash_cmdlist == NULL
3333 || flash_data == NULL || flash_spare == NULL)
3334 ASSERT(0);
3335
Dima Zavin03cf4312009-01-23 16:38:30 -08003336 flash_read_id(flash_cmdlist, flash_ptrlist);
Ajay Dudanib01e5062011-12-03 23:23:42 -08003337 if ((FLASH_8BIT_NAND_DEVICE == flash_info.type)
3338 || (FLASH_16BIT_NAND_DEVICE == flash_info.type)) {
3339 if (flash_nand_read_config(flash_cmdlist, flash_ptrlist)) {
3340 dprintf(CRITICAL,
3341 "ERROR: could not read CFG0/CFG1 state\n");
Shashank Mittal83d16d02009-11-18 16:54:42 -08003342 ASSERT(0);
3343 }
3344 }
Channagoud Kadabib2fb6ba2011-07-29 19:19:01 +05303345 /* Create a bad block table */
Ajay Dudanib01e5062011-12-03 23:23:42 -08003346 bbtbl =
3347 (unsigned int *)malloc(sizeof(unsigned int) *
3348 flash_info.num_blocks);
3349 for (i = 0; i < flash_info.num_blocks; i++)
3350 bbtbl[i] = -1;
Dima Zavin03cf4312009-01-23 16:38:30 -08003351}
3352
3353struct ptable *flash_get_ptable(void)
3354{
3355 return flash_ptable;
3356}
3357
Dima Zavine5f64352009-03-02 16:04:20 -08003358void flash_set_ptable(struct ptable *new_ptable)
3359{
3360 ASSERT(flash_ptable == NULL && new_ptable != NULL);
3361 flash_ptable = new_ptable;
3362}
3363
Dima Zavinca337f52009-03-02 16:41:44 -08003364struct flash_info *flash_get_info(void)
3365{
3366 return &flash_info;
3367}
3368
Dima Zavin03cf4312009-01-23 16:38:30 -08003369int flash_erase(struct ptentry *ptn)
3370{
3371 unsigned block = ptn->start;
3372 unsigned count = ptn->length;
3373
Shashank Mittal8e49dec2010-03-01 15:19:04 -08003374 set_nand_configuration(ptn->type);
Ajay Dudanib01e5062011-12-03 23:23:42 -08003375 while (count-- > 0) {
3376 if (flash_erase_block
3377 (flash_cmdlist, flash_ptrlist, block * num_pages_per_blk)) {
3378 dprintf(INFO, "cannot erase @ %d (bad block?)\n",
3379 block);
Dima Zavin03cf4312009-01-23 16:38:30 -08003380 }
3381 block++;
3382 }
3383 return 0;
3384}
3385
Ajay Dudanib01e5062011-12-03 23:23:42 -08003386int
3387flash_read_ext(struct ptentry *ptn, unsigned extra_per_page,
3388 unsigned offset, void *data, unsigned bytes)
Dima Zavin03cf4312009-01-23 16:38:30 -08003389{
Ajay Dudanib01e5062011-12-03 23:23:42 -08003390 unsigned page =
3391 (ptn->start * num_pages_per_blk) + (offset / flash_pagesize);
Channagoud Kadabibeb17d52011-03-25 17:14:00 +05303392 unsigned lastpage = (ptn->start + ptn->length) * num_pages_per_blk;
Ajay Dudanib01e5062011-12-03 23:23:42 -08003393 unsigned count =
3394 (bytes + flash_pagesize - 1 + extra_per_page) / (flash_pagesize +
3395 extra_per_page);
3396 unsigned *spare = (unsigned *)flash_spare;
Dima Zavin03cf4312009-01-23 16:38:30 -08003397 unsigned errors = 0;
3398 unsigned char *image = data;
Ajay Dudanib01e5062011-12-03 23:23:42 -08003399 unsigned current_block =
3400 (page - (page & num_pages_per_blk_mask)) / num_pages_per_blk;
Shashank Mittalad3d05c2009-11-19 15:53:57 -08003401 unsigned start_block = ptn->start;
3402 int result = 0;
3403 int isbad = 0;
Shashank Mittalfd1f04f2010-08-03 17:38:48 -07003404 int start_block_count = 0;
Dima Zavin03cf4312009-01-23 16:38:30 -08003405
Shashank Mittal8e49dec2010-03-01 15:19:04 -08003406 set_nand_configuration(TYPE_APPS_PARTITION);
3407
Ajay Dudanib01e5062011-12-03 23:23:42 -08003408 if (offset & (flash_pagesize - 1))
Dima Zavin03cf4312009-01-23 16:38:30 -08003409 return -1;
3410
Shashank Mittalfd1f04f2010-08-03 17:38:48 -07003411// Adjust page offset based on number of bad blocks from start to current page
Ajay Dudanib01e5062011-12-03 23:23:42 -08003412 if (start_block < current_block) {
Shashank Mittalfd1f04f2010-08-03 17:38:48 -07003413 start_block_count = (current_block - start_block);
Ajay Dudanib01e5062011-12-03 23:23:42 -08003414 while (start_block_count
3415 && (start_block < (ptn->start + ptn->length))) {
3416 isbad =
3417 _flash_block_isbad(flash_cmdlist, flash_ptrlist,
3418 start_block * num_pages_per_blk);
Shashank Mittalfd1f04f2010-08-03 17:38:48 -07003419 if (isbad)
Channagoud Kadabibeb17d52011-03-25 17:14:00 +05303420 page += num_pages_per_blk;
Shashank Mittalfd1f04f2010-08-03 17:38:48 -07003421 else
3422 start_block_count--;
3423 start_block++;
3424 }
Shashank Mittalad3d05c2009-11-19 15:53:57 -08003425 }
3426
Ajay Dudanib01e5062011-12-03 23:23:42 -08003427 while ((page < lastpage) && !start_block_count) {
3428 if (count == 0) {
3429 dprintf(INFO, "flash_read_image: success (%d errors)\n",
3430 errors);
Dima Zavin03cf4312009-01-23 16:38:30 -08003431 return 0;
3432 }
3433
Ajay Dudanib01e5062011-12-03 23:23:42 -08003434 result =
3435 _flash_read_page(flash_cmdlist, flash_ptrlist, page, image,
3436 spare);
Shashank Mittalad3d05c2009-11-19 15:53:57 -08003437
3438 if (result == -1) {
3439 // bad page, go to next page
3440 page++;
Dima Zavin03cf4312009-01-23 16:38:30 -08003441 errors++;
3442 continue;
Ajay Dudanib01e5062011-12-03 23:23:42 -08003443 } else if (result == -2) {
Shashank Mittalad3d05c2009-11-19 15:53:57 -08003444 // bad block, go to next block same offset
Channagoud Kadabibeb17d52011-03-25 17:14:00 +05303445 page += num_pages_per_blk;
Shashank Mittalad3d05c2009-11-19 15:53:57 -08003446 errors++;
3447 continue;
3448 }
3449
3450 page++;
Shashank Mittaldcc2e352009-11-19 19:11:16 -08003451 image += flash_pagesize;
Dima Zavin03cf4312009-01-23 16:38:30 -08003452 memcpy(image, spare, extra_per_page);
3453 image += extra_per_page;
3454 count -= 1;
3455 }
3456
3457 /* could not find enough valid pages before we hit the end */
3458 dprintf(INFO, "flash_read_image: failed (%d errors)\n", errors);
3459 return 0xffffffff;
3460}
3461
Ajay Dudanib01e5062011-12-03 23:23:42 -08003462int
3463flash_write(struct ptentry *ptn, unsigned extra_per_page, const void *data,
3464 unsigned bytes)
Dima Zavin03cf4312009-01-23 16:38:30 -08003465{
Channagoud Kadabibeb17d52011-03-25 17:14:00 +05303466 unsigned page = ptn->start * num_pages_per_blk;
3467 unsigned lastpage = (ptn->start + ptn->length) * num_pages_per_blk;
Ajay Dudanib01e5062011-12-03 23:23:42 -08003468 unsigned *spare = (unsigned *)flash_spare;
Dima Zavin03cf4312009-01-23 16:38:30 -08003469 const unsigned char *image = data;
Shashank Mittaldcc2e352009-11-19 19:11:16 -08003470 unsigned wsize = flash_pagesize + extra_per_page;
Dima Zavin03cf4312009-01-23 16:38:30 -08003471 unsigned n;
3472 int r;
3473
Ajay Dudanib01e5062011-12-03 23:23:42 -08003474 if ((flash_info.type == FLASH_ONENAND_DEVICE)
3475 && (ptn->type == TYPE_MODEM_PARTITION)) {
Shashank Mittal8e49dec2010-03-01 15:19:04 -08003476 dprintf(CRITICAL, "flash_write_image: feature not supported\n");
3477 return -1;
3478 }
3479
3480 set_nand_configuration(ptn->type);
Ajay Dudanib01e5062011-12-03 23:23:42 -08003481 for (n = 0; n < 16; n++)
3482 spare[n] = 0xffffffff;
Dima Zavin03cf4312009-01-23 16:38:30 -08003483
Ajay Dudanib01e5062011-12-03 23:23:42 -08003484 while (bytes > 0) {
3485 if (bytes < wsize) {
3486 dprintf(CRITICAL,
3487 "flash_write_image: image undersized (%d < %d)\n",
3488 bytes, wsize);
Dima Zavin03cf4312009-01-23 16:38:30 -08003489 return -1;
3490 }
Ajay Dudanib01e5062011-12-03 23:23:42 -08003491 if (page >= lastpage) {
Dima Zavin03cf4312009-01-23 16:38:30 -08003492 dprintf(CRITICAL, "flash_write_image: out of space\n");
3493 return -1;
3494 }
3495
Ajay Dudanib01e5062011-12-03 23:23:42 -08003496 if ((page & num_pages_per_blk_mask) == 0) {
3497 if (flash_erase_block
3498 (flash_cmdlist, flash_ptrlist, page)) {
3499 dprintf(INFO,
3500 "flash_write_image: bad block @ %d\n",
3501 page / num_pages_per_blk);
Channagoud Kadabibeb17d52011-03-25 17:14:00 +05303502 page += num_pages_per_blk;
Dima Zavin03cf4312009-01-23 16:38:30 -08003503 continue;
3504 }
3505 }
3506
Ajay Dudanib01e5062011-12-03 23:23:42 -08003507 if (extra_per_page) {
3508 r = _flash_write_page(flash_cmdlist, flash_ptrlist,
3509 page, image,
3510 image + flash_pagesize);
Dima Zavin03cf4312009-01-23 16:38:30 -08003511 } else {
Ajay Dudanib01e5062011-12-03 23:23:42 -08003512 r = _flash_write_page(flash_cmdlist, flash_ptrlist,
3513 page, image, spare);
Dima Zavin03cf4312009-01-23 16:38:30 -08003514 }
Ajay Dudanib01e5062011-12-03 23:23:42 -08003515 if (r) {
3516 dprintf(INFO,
3517 "flash_write_image: write failure @ page %d (src %d)\n",
3518 page, image - (const unsigned char *)data);
Channagoud Kadabibeb17d52011-03-25 17:14:00 +05303519 image -= (page & num_pages_per_blk_mask) * wsize;
3520 bytes += (page & num_pages_per_blk_mask) * wsize;
3521 page &= ~num_pages_per_blk_mask;
Ajay Dudanib01e5062011-12-03 23:23:42 -08003522 if (flash_erase_block
3523 (flash_cmdlist, flash_ptrlist, page)) {
3524 dprintf(INFO,
3525 "flash_write_image: erase failure @ page %d\n",
3526 page);
Dima Zavin03cf4312009-01-23 16:38:30 -08003527 }
Shashank Mittal8e49dec2010-03-01 15:19:04 -08003528 if (ptn->type != TYPE_MODEM_PARTITION) {
Ajay Dudanib01e5062011-12-03 23:23:42 -08003529 flash_mark_badblock(flash_cmdlist,
3530 flash_ptrlist, page);
Shashank Mittal8e49dec2010-03-01 15:19:04 -08003531 }
Ajay Dudanib01e5062011-12-03 23:23:42 -08003532 dprintf(INFO,
3533 "flash_write_image: restart write @ page %d (src %d)\n",
3534 page, image - (const unsigned char *)data);
Channagoud Kadabibeb17d52011-03-25 17:14:00 +05303535 page += num_pages_per_blk;
Dima Zavin03cf4312009-01-23 16:38:30 -08003536 continue;
3537 }
Shashank Mittald0c836d2009-11-20 10:31:18 -08003538 page++;
Dima Zavin03cf4312009-01-23 16:38:30 -08003539 image += wsize;
3540 bytes -= wsize;
3541 }
3542
3543 /* erase any remaining pages in the partition */
Channagoud Kadabibeb17d52011-03-25 17:14:00 +05303544 page = (page + num_pages_per_blk_mask) & (~num_pages_per_blk_mask);
Ajay Dudanib01e5062011-12-03 23:23:42 -08003545 while (page < lastpage) {
3546 if (flash_erase_block(flash_cmdlist, flash_ptrlist, page)) {
3547 dprintf(INFO, "flash_write_image: bad block @ %d\n",
3548 page / num_pages_per_blk);
Dima Zavin03cf4312009-01-23 16:38:30 -08003549 }
Channagoud Kadabibeb17d52011-03-25 17:14:00 +05303550 page += num_pages_per_blk;
Dima Zavin03cf4312009-01-23 16:38:30 -08003551 }
3552
3553 dprintf(INFO, "flash_write_image: success\n");
3554 return 0;
3555}
3556
3557#if 0
3558static int flash_read_page(unsigned page, void *data, void *extra)
3559{
Ajay Dudanib01e5062011-12-03 23:23:42 -08003560 return _flash_read_page(flash_cmdlist, flash_ptrlist, page, data,
3561 extra);
Dima Zavin03cf4312009-01-23 16:38:30 -08003562}
3563#endif
Shashank Mittaldcc2e352009-11-19 19:11:16 -08003564
3565unsigned flash_page_size(void)
3566{
3567 return flash_pagesize;
3568}
Chandan Uddaraju14e57eb2010-06-28 12:11:06 -07003569
3570void enable_interleave_mode(int status)
3571{
Ajay Dudanib01e5062011-12-03 23:23:42 -08003572 interleaved_mode = status;
3573 if (status) {
3574 flash_pagesize *= 2;
3575 platform_config_interleaved_mode_gpios();
3576 }
3577 return;
Chandan Uddaraju14e57eb2010-06-28 12:11:06 -07003578}
Channagoud Kadabi404a7062011-03-21 19:27:50 +05303579
3580int flash_ecc_bch_enabled()
3581{
Ajay Dudanib01e5062011-12-03 23:23:42 -08003582 return enable_bch_ecc;
Channagoud Kadabi404a7062011-03-21 19:27:50 +05303583}