]> git.ipfire.org Git - people/ms/u-boot.git/blame - nand_spl/nand_boot_fsl_nfc.c
Merge branch 'master' into next
[people/ms/u-boot.git] / nand_spl / nand_boot_fsl_nfc.c
CommitLineData
40c642bc
ML
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#include <asm-arm/arch/mx31-regs.h>
30#include <asm/io.h>
31#include <fsl_nfc.h>
32
33static struct fsl_nfc_regs *nfc;
34
35static void nfc_wait_ready(void)
36{
37 uint32_t tmp;
38
39 while (!(readw(&nfc->nand_flash_config2) & NFC_INT))
40 ;
41
42 /* Reset interrupt flag */
43 tmp = readw(&nfc->nand_flash_config2);
44 tmp &= ~NFC_INT;
45 writew(tmp, &nfc->nand_flash_config2);
46}
47
48static void nfc_nand_init(void)
49{
50 /* unlocking RAM Buff */
51 writew(0x2, &nfc->configuration);
52
53 /* hardware ECC checking and correct */
54 writew(NFC_ECC_EN, &nfc->nand_flash_config1);
55}
56
57static void nfc_nand_command(unsigned short command)
58{
59 writew(command, &nfc->flash_cmd);
60 writew(NFC_CMD, &nfc->nand_flash_config2);
61 nfc_wait_ready();
62}
63
64static void nfc_nand_page_address(unsigned int page_address)
65{
66 unsigned int page_count;
67
68 writew(0x00, &nfc->flash_cmd);
69 writew(NFC_ADDR, &nfc->nand_flash_config2);
70 nfc_wait_ready();
71
72 /* code only for 2kb flash */
73 if (CONFIG_SYS_NAND_PAGE_SIZE == 0x800) {
74 writew(0x00, &nfc->flash_add);
75 writew(NFC_ADDR, &nfc->nand_flash_config2);
76 nfc_wait_ready();
77 }
78
79 page_count = CONFIG_SYS_NAND_SIZE / CONFIG_SYS_NAND_PAGE_SIZE;
80
81 if (page_address <= page_count) {
82 page_count--; /* transform 0x01000000 to 0x00ffffff */
83 do {
84 writew(page_address & 0xff, &nfc->flash_add);
85 writew(NFC_ADDR, &nfc->nand_flash_config2);
86 nfc_wait_ready();
87 page_address = page_address >> 8;
88 page_count = page_count >> 8;
89 } while (page_count);
90 }
91}
92
93static void nfc_nand_data_output(void)
94{
95 int i;
96
97 /*
98 * The NAND controller requires four output commands for
99 * large page devices.
100 */
101 for (i = 0; i < (CONFIG_SYS_NAND_PAGE_SIZE / 512); i++) {
102 writew(NFC_ECC_EN, &nfc->nand_flash_config1);
103 writew(i, &nfc->buffer_address); /* read in i:th buffer */
104 writew(NFC_OUTPUT, &nfc->nand_flash_config2);
105 nfc_wait_ready();
106 }
107}
108
109static int nfc_nand_check_ecc(void)
110{
111 return readw(&nfc->ecc_status_result);
112}
113
114static int nfc_read_page(unsigned int page_address, unsigned char *buf)
115{
116 int i;
117 u32 *src;
118 u32 *dst;
119
120 writew(0, &nfc->buffer_address); /* read in first 0 buffer */
121 nfc_nand_command(NAND_CMD_READ0);
122 nfc_nand_page_address(page_address);
123
124 if (CONFIG_SYS_NAND_PAGE_SIZE == 0x800)
125 nfc_nand_command(NAND_CMD_READSTART);
126
127 nfc_nand_data_output(); /* fill the main buffer 0 */
128
129 if (nfc_nand_check_ecc())
130 return -1;
131
132 src = &nfc->main_area0[0];
133 dst = (u32 *)buf;
134
135 /* main copy loop from NAND-buffer to SDRAM memory */
136 for (i = 0; i < (CONFIG_SYS_NAND_PAGE_SIZE / 4); i++) {
137 writel(readl(src), dst);
138 src++;
139 dst++;
140 }
141
142 return 0;
143}
144
145static int is_badblock(int pagenumber)
146{
147 int page = pagenumber;
148 u32 badblock;
149 u32 *src;
150
151 /* Check the first two pages for bad block markers */
152 for (page = pagenumber; page < pagenumber + 2; page++) {
153 writew(0, &nfc->buffer_address); /* read in first 0 buffer */
154 nfc_nand_command(NAND_CMD_READ0);
155 nfc_nand_page_address(page);
156
157 if (CONFIG_SYS_NAND_PAGE_SIZE == 0x800)
158 nfc_nand_command(NAND_CMD_READSTART);
159
160 nfc_nand_data_output(); /* fill the main buffer 0 */
161
162 src = &nfc->spare_area0[0];
163
164 /*
165 * IMPORTANT NOTE: The nand flash controller uses a non-
166 * standard layout for large page devices. This can
167 * affect the position of the bad block marker.
168 */
169 /* Get the bad block marker */
170 badblock = readl(&src[CONFIG_SYS_NAND_BAD_BLOCK_POS / 4]);
171 badblock >>= 8 * (CONFIG_SYS_NAND_BAD_BLOCK_POS % 4);
172 badblock &= 0xff;
173
174 /* bad block marker verify */
175 if (badblock != 0xff)
176 return 1; /* potential bad block */
177 }
178
179 return 0;
180}
181
182static int nand_load(unsigned int from, unsigned int size, unsigned char *buf)
183{
184 int i;
185 unsigned int page;
186 unsigned int maxpages = CONFIG_SYS_NAND_SIZE /
187 CONFIG_SYS_NAND_PAGE_SIZE;
188
189 nfc = (void *)NFC_BASE_ADDR;
190
191 nfc_nand_init();
192
193 /* Convert to page number */
194 page = from / CONFIG_SYS_NAND_PAGE_SIZE;
195 i = 0;
196
197 while (i < (size / CONFIG_SYS_NAND_PAGE_SIZE)) {
198 if (nfc_read_page(page, buf) < 0)
199 return -1;
200
201 page++;
202 i++;
203 buf = buf + CONFIG_SYS_NAND_PAGE_SIZE;
204
205 /*
206 * Check if we have crossed a block boundary, and if so
207 * check for bad block.
208 */
209 if (!(page % CONFIG_SYS_NAND_PAGE_COUNT)) {
210 /*
211 * Yes, new block. See if this block is good. If not,
212 * loop until we find i good block.
213 */
214 while (is_badblock(page)) {
215 page = page + CONFIG_SYS_NAND_PAGE_COUNT;
216 /* Check i we've reached the end of flash. */
217 if (page >= maxpages)
218 return -1;
219 }
220 }
221 }
222
223 return 0;
224}
225
226/*
227 * The main entry for NAND booting. It's necessary that SDRAM is already
228 * configured and available since this code loads the main U-Boot image
229 * from NAND into SDRAM and starts it from there.
230 */
231void nand_boot(void)
232{
233 __attribute__((noreturn)) void (*uboot)(void);
234
235 nfc = (void *)NFC_BASE_ADDR;
236
237 /*
238 * CONFIG_SYS_NAND_U_BOOT_OFFS and CONFIG_SYS_NAND_U_BOOT_SIZE must
239 * be aligned to full pages
240 */
241 if (!nand_load(CONFIG_SYS_NAND_U_BOOT_OFFS, CONFIG_SYS_NAND_U_BOOT_SIZE,
242 (uchar *)CONFIG_SYS_NAND_U_BOOT_DST)) {
243 /* Copy from NAND successful, start U-boot */
244 uboot = (void *)CONFIG_SYS_NAND_U_BOOT_START;
245 uboot();
246 } else {
247 /* Unrecoverable error when copying from NAND */
248 hang();
249 }
250}
251
252/*
253 * Called in case of an exception.
254 */
255void hang(void)
256{
257 /* Loop forever */
258 while (1) ;
259}