uboot/nand_spl/nand_boot_fsl_nfc.c
<<
>>
Prefs
   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/arch/imx-regs.h>
  30#include <asm/io.h>
  31#include <fsl_nfc.h>
  32
  33static struct fsl_nfc_regs *const nfc = (void *)NFC_BASE_ADDR;
  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
  48void nfc_nand_init(void)
  49{
  50#if defined(MXC_NFC_V1_1)
  51        int ecc_per_page  = CONFIG_SYS_NAND_PAGE_SIZE / 512;
  52        int config1;
  53
  54        writew(CONFIG_SYS_NAND_SPARE_SIZE / 2, &nfc->spare_area_size);
  55
  56        /* unlocking RAM Buff */
  57        writew(0x2, &nfc->configuration);
  58
  59        /* hardware ECC checking and correct */
  60        config1 = readw(&nfc->nand_flash_config1) | NFC_ECC_EN | 0x800;
  61        /*
  62         * if spare size is larger that 16 bytes per 512 byte hunk
  63         * then use 8 symbol correction instead of 4
  64         */
  65        if ((CONFIG_SYS_NAND_SPARE_SIZE / ecc_per_page) > 16)
  66                config1 &= ~NFC_4_8N_ECC;
  67        else
  68                config1 |= NFC_4_8N_ECC;
  69        writew(config1, &nfc->nand_flash_config1);
  70#elif defined(MXC_NFC_V1)
  71        /* unlocking RAM Buff */
  72        writew(0x2, &nfc->configuration);
  73
  74        /* hardware ECC checking and correct */
  75        writew(NFC_ECC_EN, &nfc->nand_flash_config1);
  76#endif
  77}
  78
  79static void nfc_nand_command(unsigned short command)
  80{
  81        writew(command, &nfc->flash_cmd);
  82        writew(NFC_CMD, &nfc->nand_flash_config2);
  83        nfc_wait_ready();
  84}
  85
  86static void nfc_nand_page_address(unsigned int page_address)
  87{
  88        unsigned int page_count;
  89
  90        writew(0x00, &nfc->flash_add);
  91        writew(NFC_ADDR, &nfc->nand_flash_config2);
  92        nfc_wait_ready();
  93
  94        /* code only for large page flash */
  95        if (CONFIG_SYS_NAND_PAGE_SIZE > 512) {
  96                writew(0x00, &nfc->flash_add);
  97                writew(NFC_ADDR, &nfc->nand_flash_config2);
  98                nfc_wait_ready();
  99        }
 100
 101        page_count = CONFIG_SYS_NAND_SIZE / CONFIG_SYS_NAND_PAGE_SIZE;
 102
 103        if (page_address <= page_count) {
 104                page_count--; /* transform 0x01000000 to 0x00ffffff */
 105                do {
 106                        writew(page_address & 0xff, &nfc->flash_add);
 107                        writew(NFC_ADDR, &nfc->nand_flash_config2);
 108                        nfc_wait_ready();
 109                        page_address = page_address >> 8;
 110                        page_count = page_count >> 8;
 111                } while (page_count);
 112        }
 113
 114        writew(0x00, &nfc->flash_add);
 115        writew(NFC_ADDR, &nfc->nand_flash_config2);
 116        nfc_wait_ready();
 117}
 118
 119static void nfc_nand_data_output(void)
 120{
 121        int config1 = readw(&nfc->nand_flash_config1);
 122#ifdef NAND_MXC_2K_MULTI_CYCLE
 123        int i;
 124#endif
 125
 126        config1 |= NFC_ECC_EN | NFC_INT_MSK;
 127        writew(config1, &nfc->nand_flash_config1);
 128        writew(0, &nfc->buffer_address);
 129        writew(NFC_OUTPUT, &nfc->nand_flash_config2);
 130        nfc_wait_ready();
 131#ifdef NAND_MXC_2K_MULTI_CYCLE
 132        /*
 133         * This NAND controller requires multiple input commands
 134         * for pages larger than 512 bytes.
 135         */
 136        for (i = 1; i < (CONFIG_SYS_NAND_PAGE_SIZE / 512); i++) {
 137                config1 = readw(&nfc->nand_flash_config1);
 138                config1 |= NFC_ECC_EN | NFC_INT_MSK;
 139                writew(config1, &nfc->nand_flash_config1);
 140                writew(i, &nfc->buffer_address);
 141                writew(NFC_OUTPUT, &nfc->nand_flash_config2);
 142                nfc_wait_ready();
 143        }
 144#endif
 145}
 146
 147static int nfc_nand_check_ecc(void)
 148{
 149        return readw(&nfc->ecc_status_result);
 150}
 151
 152static int nfc_read_page(unsigned int page_address, unsigned char *buf)
 153{
 154        int i;
 155        u32 *src;
 156        u32 *dst;
 157
 158        writew(0, &nfc->buffer_address); /* read in first 0 buffer */
 159        nfc_nand_command(NAND_CMD_READ0);
 160        nfc_nand_page_address(page_address);
 161
 162        if (CONFIG_SYS_NAND_PAGE_SIZE > 512)
 163                nfc_nand_command(NAND_CMD_READSTART);
 164
 165        nfc_nand_data_output(); /* fill the main buffer 0 */
 166
 167        if (nfc_nand_check_ecc())
 168                return -1;
 169
 170        src = &nfc->main_area[0][0];
 171        dst = (u32 *)buf;
 172
 173        /* main copy loop from NAND-buffer to SDRAM memory */
 174        for (i = 0; i < (CONFIG_SYS_NAND_PAGE_SIZE / 4); i++) {
 175                writel(readl(src), dst);
 176                src++;
 177                dst++;
 178        }
 179
 180        return 0;
 181}
 182
 183static int is_badblock(int pagenumber)
 184{
 185        int page = pagenumber;
 186        u32 badblock;
 187        u32 *src;
 188
 189        /* Check the first two pages for bad block markers */
 190        for (page = pagenumber; page < pagenumber + 2; page++) {
 191                writew(0, &nfc->buffer_address); /* read in first 0 buffer */
 192                nfc_nand_command(NAND_CMD_READ0);
 193                nfc_nand_page_address(page);
 194
 195                if (CONFIG_SYS_NAND_PAGE_SIZE > 512)
 196                        nfc_nand_command(NAND_CMD_READSTART);
 197
 198                nfc_nand_data_output(); /* fill the main buffer 0 */
 199
 200                src = &nfc->spare_area[0][0];
 201
 202                /*
 203                 * IMPORTANT NOTE: The nand flash controller uses a non-
 204                 * standard layout for large page devices. This can
 205                 * affect the position of the bad block marker.
 206                 */
 207                /* Get the bad block marker */
 208                badblock = readl(&src[CONFIG_SYS_NAND_BAD_BLOCK_POS / 4]);
 209                badblock >>= 8 * (CONFIG_SYS_NAND_BAD_BLOCK_POS % 4);
 210                badblock &= 0xff;
 211
 212                /* bad block marker verify */
 213                if (badblock != 0xff)
 214                        return 1; /* potential bad block */
 215        }
 216
 217        return 0;
 218}
 219
 220static int nand_load(unsigned int from, unsigned int size, unsigned char *buf)
 221{
 222        int i;
 223        unsigned int page;
 224        unsigned int maxpages = CONFIG_SYS_NAND_SIZE /
 225                                CONFIG_SYS_NAND_PAGE_SIZE;
 226
 227        nfc_nand_init();
 228
 229        /* Convert to page number */
 230        page = from / CONFIG_SYS_NAND_PAGE_SIZE;
 231        i = 0;
 232
 233        while (i < (size / CONFIG_SYS_NAND_PAGE_SIZE)) {
 234                if (nfc_read_page(page, buf) < 0)
 235                        return -1;
 236
 237                page++;
 238                i++;
 239                buf = buf + CONFIG_SYS_NAND_PAGE_SIZE;
 240
 241                /*
 242                 * Check if we have crossed a block boundary, and if so
 243                 * check for bad block.
 244                 */
 245                if (!(page % CONFIG_SYS_NAND_PAGE_COUNT)) {
 246                        /*
 247                         * Yes, new block. See if this block is good. If not,
 248                         * loop until we find a good block.
 249                         */
 250                        while (is_badblock(page)) {
 251                                page = page + CONFIG_SYS_NAND_PAGE_COUNT;
 252                                /* Check i we've reached the end of flash. */
 253                                if (page >= maxpages)
 254                                        return -1;
 255                        }
 256                }
 257        }
 258
 259        return 0;
 260}
 261
 262#if defined(CONFIG_ARM)
 263void board_init_f (ulong bootflag)
 264{
 265        relocate_code (CONFIG_SYS_TEXT_BASE - TOTAL_MALLOC_LEN, NULL,
 266                       CONFIG_SYS_TEXT_BASE);
 267}
 268#endif
 269
 270/*
 271 * The main entry for NAND booting. It's necessary that SDRAM is already
 272 * configured and available since this code loads the main U-Boot image
 273 * from NAND into SDRAM and starts it from there.
 274 */
 275void nand_boot(void)
 276{
 277        __attribute__((noreturn)) void (*uboot)(void);
 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 */
 297void hang(void)
 298{
 299        /* Loop forever */
 300        while (1) ;
 301}
 302