Merge branch 'master' of git://git.denx.de/u-boot-net
[platform/kernel/u-boot.git] / nand_spl / nand_boot_fsl_nfc.c
1 /*
2  * (C) Copyright 2009
3  * Magnus Lilja <lilja.magnus@gmail.com>
4  *
5  * (C) Copyright 2008
6  * Maxim Artamonov, <scn1874 at yandex.ru>
7  *
8  * (C) Copyright 2006-2008
9  * Stefan Roese, DENX Software Engineering, sr at denx.de.
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License as
13  * published by the Free Software Foundation; either version 2 of
14  * the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
24  * MA 02111-1307 USA
25  */
26
27 #include <common.h>
28 #include <nand.h>
29 #ifdef CONFIG_MX31
30 #include <asm-arm/arch/mx31-regs.h>
31 #else
32 #include <asm-arm/arch/imx-regs.h>
33 #endif
34 #include <asm/io.h>
35 #include <fsl_nfc.h>
36
37 struct fsl_nfc_regs *nfc;
38
39 static void nfc_wait_ready(void)
40 {
41         uint32_t tmp;
42
43         while (!(readw(&nfc->nand_flash_config2) & NFC_INT))
44                 ;
45
46         /* Reset interrupt flag */
47         tmp = readw(&nfc->nand_flash_config2);
48         tmp &= ~NFC_INT;
49         writew(tmp, &nfc->nand_flash_config2);
50 }
51
52 void nfc_nand_init(void)
53 {
54 #if defined(MXC_NFC_V1_1)
55         int ecc_per_page  = CONFIG_SYS_NAND_PAGE_SIZE / 512;
56         int config1;
57
58         writew(CONFIG_SYS_NAND_SPARE_SIZE / 2, &nfc->spare_area_size);
59
60         /* unlocking RAM Buff */
61         writew(0x2, &nfc->configuration);
62
63         /* hardware ECC checking and correct */
64         config1 = readw(&nfc->nand_flash_config1) | NFC_ECC_EN | 0x800;
65         /*
66          * if spare size is larger that 16 bytes per 512 byte hunk
67          * then use 8 symbol correction instead of 4
68          */
69         if ((CONFIG_SYS_NAND_SPARE_SIZE / ecc_per_page) > 16)
70                 config1 &= ~NFC_4_8N_ECC;
71         else
72                 config1 |= NFC_4_8N_ECC;
73         writew(config1, &nfc->nand_flash_config1);
74 #elif defined(MXC_NFC_V1)
75         /* unlocking RAM Buff */
76         writew(0x2, &nfc->configuration);
77
78         /* hardware ECC checking and correct */
79         writew(NFC_ECC_EN, &nfc->nand_flash_config1);
80 #endif
81 }
82
83 static void nfc_nand_command(unsigned short command)
84 {
85         writew(command, &nfc->flash_cmd);
86         writew(NFC_CMD, &nfc->nand_flash_config2);
87         nfc_wait_ready();
88 }
89
90 static void nfc_nand_page_address(unsigned int page_address)
91 {
92         unsigned int page_count;
93
94         writew(0x00, &nfc->flash_add);
95         writew(NFC_ADDR, &nfc->nand_flash_config2);
96         nfc_wait_ready();
97
98         /* code only for large page flash */
99         if (CONFIG_SYS_NAND_PAGE_SIZE > 512) {
100                 writew(0x00, &nfc->flash_add);
101                 writew(NFC_ADDR, &nfc->nand_flash_config2);
102                 nfc_wait_ready();
103         }
104
105         page_count = CONFIG_SYS_NAND_SIZE / CONFIG_SYS_NAND_PAGE_SIZE;
106
107         if (page_address <= page_count) {
108                 page_count--; /* transform 0x01000000 to 0x00ffffff */
109                 do {
110                         writew(page_address & 0xff, &nfc->flash_add);
111                         writew(NFC_ADDR, &nfc->nand_flash_config2);
112                         nfc_wait_ready();
113                         page_address = page_address >> 8;
114                         page_count = page_count >> 8;
115                 } while (page_count);
116         }
117
118         writew(0x00, &nfc->flash_add);
119         writew(NFC_ADDR, &nfc->nand_flash_config2);
120         nfc_wait_ready();
121 }
122
123 static void nfc_nand_data_output(void)
124 {
125         int config1 = readw(&nfc->nand_flash_config1);
126 #ifdef NAND_MXC_2K_MULTI_CYCLE
127         int i;
128 #endif
129
130         config1 |= NFC_ECC_EN | NFC_INT_MSK;
131         writew(config1, &nfc->nand_flash_config1);
132         writew(0, &nfc->buffer_address);
133         writew(NFC_OUTPUT, &nfc->nand_flash_config2);
134         nfc_wait_ready();
135 #ifdef NAND_MXC_2K_MULTI_CYCLE
136         /*
137          * This NAND controller requires multiple input commands
138          * for pages larger than 512 bytes.
139          */
140         for (i = 1; i < (CONFIG_SYS_NAND_PAGE_SIZE / 512); i++) {
141                 config1 = readw(&nfc->nand_flash_config1);
142                 config1 |= NFC_ECC_EN | NFC_INT_MSK;
143                 writew(config1, &nfc->nand_flash_config1);
144                 writew(i, &nfc->buffer_address);
145                 writew(NFC_OUTPUT, &nfc->nand_flash_config2);
146                 nfc_wait_ready();
147         }
148 #endif
149 }
150
151 static int nfc_nand_check_ecc(void)
152 {
153         return readw(&nfc->ecc_status_result);
154 }
155
156 static int nfc_read_page(unsigned int page_address, unsigned char *buf)
157 {
158         int i;
159         u32 *src;
160         u32 *dst;
161
162         writew(0, &nfc->buffer_address); /* read in first 0 buffer */
163         nfc_nand_command(NAND_CMD_READ0);
164         nfc_nand_page_address(page_address);
165
166         if (CONFIG_SYS_NAND_PAGE_SIZE > 512)
167                 nfc_nand_command(NAND_CMD_READSTART);
168
169         nfc_nand_data_output(); /* fill the main buffer 0 */
170
171         if (nfc_nand_check_ecc())
172                 return -1;
173
174         src = &nfc->main_area[0][0];
175         dst = (u32 *)buf;
176
177         /* main copy loop from NAND-buffer to SDRAM memory */
178         for (i = 0; i < (CONFIG_SYS_NAND_PAGE_SIZE / 4); i++) {
179                 writel(readl(src), dst);
180                 src++;
181                 dst++;
182         }
183
184         return 0;
185 }
186
187 static int is_badblock(int pagenumber)
188 {
189         int page = pagenumber;
190         u32 badblock;
191         u32 *src;
192
193         /* Check the first two pages for bad block markers */
194         for (page = pagenumber; page < pagenumber + 2; page++) {
195                 writew(0, &nfc->buffer_address); /* read in first 0 buffer */
196                 nfc_nand_command(NAND_CMD_READ0);
197                 nfc_nand_page_address(page);
198
199                 if (CONFIG_SYS_NAND_PAGE_SIZE > 512)
200                         nfc_nand_command(NAND_CMD_READSTART);
201
202                 nfc_nand_data_output(); /* fill the main buffer 0 */
203
204                 src = &nfc->spare_area[0][0];
205
206                 /*
207                  * IMPORTANT NOTE: The nand flash controller uses a non-
208                  * standard layout for large page devices. This can
209                  * affect the position of the bad block marker.
210                  */
211                 /* Get the bad block marker */
212                 badblock = readl(&src[CONFIG_SYS_NAND_BAD_BLOCK_POS / 4]);
213                 badblock >>= 8 * (CONFIG_SYS_NAND_BAD_BLOCK_POS % 4);
214                 badblock &= 0xff;
215
216                 /* bad block marker verify */
217                 if (badblock != 0xff)
218                         return 1; /* potential bad block */
219         }
220
221         return 0;
222 }
223
224 static int nand_load(unsigned int from, unsigned int size, unsigned char *buf)
225 {
226         int i;
227         unsigned int page;
228         unsigned int maxpages = CONFIG_SYS_NAND_SIZE /
229                                 CONFIG_SYS_NAND_PAGE_SIZE;
230
231         nfc = (void *)NFC_BASE_ADDR;
232
233         nfc_nand_init();
234
235         /* Convert to page number */
236         page = from / CONFIG_SYS_NAND_PAGE_SIZE;
237         i = 0;
238
239         while (i < (size / CONFIG_SYS_NAND_PAGE_SIZE)) {
240                 if (nfc_read_page(page, buf) < 0)
241                         return -1;
242
243                 page++;
244                 i++;
245                 buf = buf + CONFIG_SYS_NAND_PAGE_SIZE;
246
247                 /*
248                  * Check if we have crossed a block boundary, and if so
249                  * check for bad block.
250                  */
251                 if (!(page % CONFIG_SYS_NAND_PAGE_COUNT)) {
252                         /*
253                          * Yes, new block. See if this block is good. If not,
254                          * loop until we find a good block.
255                          */
256                         while (is_badblock(page)) {
257                                 page = page + CONFIG_SYS_NAND_PAGE_COUNT;
258                                 /* Check i we've reached the end of flash. */
259                                 if (page >= maxpages)
260                                         return -1;
261                         }
262                 }
263         }
264
265         return 0;
266 }
267
268 /*
269  * The main entry for NAND booting. It's necessary that SDRAM is already
270  * configured and available since this code loads the main U-Boot image
271  * from NAND into SDRAM and starts it from there.
272  */
273 void nand_boot(void)
274 {
275         __attribute__((noreturn)) void (*uboot)(void);
276
277         nfc = (void *)NFC_BASE_ADDR;
278
279         /*
280          * CONFIG_SYS_NAND_U_BOOT_OFFS and CONFIG_SYS_NAND_U_BOOT_SIZE must
281          * be aligned to full pages
282          */
283         if (!nand_load(CONFIG_SYS_NAND_U_BOOT_OFFS, CONFIG_SYS_NAND_U_BOOT_SIZE,
284                        (uchar *)CONFIG_SYS_NAND_U_BOOT_DST)) {
285                 /* Copy from NAND successful, start U-boot */
286                 uboot = (void *)CONFIG_SYS_NAND_U_BOOT_START;
287                 uboot();
288         } else {
289                 /* Unrecoverable error when copying from NAND */
290                 hang();
291         }
292 }
293
294 /*
295  * Called in case of an exception.
296  */
297 void hang(void)
298 {
299         /* Loop forever */
300         while (1) ;
301 }