Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 | // SPDX-License-Identifier: GPL-2.0+ /* * NAND boot for Freescale Enhanced Local Bus Controller, Flash Control Machine * * (C) Copyright 2006-2008 * Stefan Roese, DENX Software Engineering, sr@denx.de. * * Copyright (c) 2008 Freescale Semiconductor, Inc. * Author: Scott Wood <scottwood@freescale.com> */ #include <config.h> #include <cpu_func.h> #include <linux/mtd/rawnand.h> #include <asm/io.h> #include <asm/fsl_lbc.h> #include <nand.h> #ifdef CONFIG_MPC83xx #include "../../../arch/powerpc/cpu/mpc83xx/elbc/elbc.h" #endif #define WINDOW_SIZE 8192 static void nand_wait(void) { fsl_lbc_t *regs = LBC_BASE_ADDR; for (;;) { uint32_t status = in_be32(®s->ltesr); if (status == 1) return; if (status & 1) { puts("read failed (ltesr)\n"); for (;;); } } } #ifdef CONFIG_TPL_BUILD int nand_spl_load_image(uint32_t offs, unsigned int uboot_size, void *vdst) #else static int nand_load_image(uint32_t offs, unsigned int uboot_size, void *vdst) #endif { fsl_lbc_t *regs = LBC_BASE_ADDR; uchar *buf = (uchar *)CFG_SYS_NAND_BASE; const int large = CFG_SYS_NAND_OR_PRELIM & OR_FCM_PGS; const int block_shift = large ? 17 : 14; const int block_size = 1 << block_shift; const int page_size = large ? 2048 : 512; const int bad_marker = large ? page_size + 0 : page_size + 5; int fmr = (15 << FMR_CWTO_SHIFT) | (2 << FMR_AL_SHIFT) | 2; int pos = 0; char *dst = vdst; if (offs & (block_size - 1)) { puts("bad offset\n"); for (;;); } if (large) { fmr |= FMR_ECCM; out_be32(®s->fcr, (NAND_CMD_READ0 << FCR_CMD0_SHIFT) | (NAND_CMD_READSTART << FCR_CMD1_SHIFT)); out_be32(®s->fir, (FIR_OP_CW0 << FIR_OP0_SHIFT) | (FIR_OP_CA << FIR_OP1_SHIFT) | (FIR_OP_PA << FIR_OP2_SHIFT) | (FIR_OP_CW1 << FIR_OP3_SHIFT) | (FIR_OP_RBW << FIR_OP4_SHIFT)); } else { out_be32(®s->fcr, NAND_CMD_READ0 << FCR_CMD0_SHIFT); out_be32(®s->fir, (FIR_OP_CW0 << FIR_OP0_SHIFT) | (FIR_OP_CA << FIR_OP1_SHIFT) | (FIR_OP_PA << FIR_OP2_SHIFT) | (FIR_OP_RBW << FIR_OP3_SHIFT)); } out_be32(®s->fbcr, 0); clrsetbits_be32(®s->bank[0].br, BR_DECC, BR_DECC_CHK_GEN); while (pos < uboot_size) { int i = 0; out_be32(®s->fbar, offs >> block_shift); do { int j; unsigned int page_offs = (offs & (block_size - 1)) << 1; out_be32(®s->ltesr, ~0); out_be32(®s->lteatr, 0); out_be32(®s->fpar, page_offs); out_be32(®s->fmr, fmr); out_be32(®s->lsor, 0); nand_wait(); page_offs %= WINDOW_SIZE; /* * If either of the first two pages are marked bad, * continue to the next block. */ if (i++ < 2 && buf[page_offs + bad_marker] != 0xff) { puts("skipping\n"); offs = (offs + block_size) & ~(block_size - 1); pos &= ~(block_size - 1); break; } for (j = 0; j < page_size; j++) dst[pos + j] = buf[page_offs + j]; pos += page_size; offs += page_size; } while ((offs & (block_size - 1)) && (pos < uboot_size)); } return 0; } /* * Defines a static function nand_load_image() here, because non-static makes * the code too large for certain SPLs(minimal SPL, maximum size <= 4Kbytes) */ #ifndef CONFIG_TPL_BUILD #define nand_spl_load_image(offs, uboot_size, vdst) \ nand_load_image(offs, uboot_size, vdst) #endif /* * The main entry for NAND booting. It's necessary that SDRAM is already * configured and available since this code loads the main U-Boot image * from NAND into SDRAM and starts it from there. */ void nand_boot(void) { __attribute__((noreturn)) void (*uboot)(void); /* * Load U-Boot image from NAND into RAM */ nand_spl_load_image(CONFIG_SYS_NAND_U_BOOT_OFFS, CFG_SYS_NAND_U_BOOT_SIZE, (void *)CFG_SYS_NAND_U_BOOT_DST); #ifdef CONFIG_NAND_ENV_DST nand_spl_load_image(CONFIG_ENV_OFFSET, CONFIG_ENV_SIZE, (void *)CONFIG_NAND_ENV_DST); #ifdef CONFIG_ENV_OFFSET_REDUND nand_spl_load_image(CONFIG_ENV_OFFSET_REDUND, CONFIG_ENV_SIZE, (void *)CONFIG_NAND_ENV_DST + CONFIG_ENV_SIZE); #endif #endif #ifdef CONFIG_SPL_FLUSH_IMAGE /* * Clean d-cache and invalidate i-cache, to * make sure that no stale data is executed. */ flush_cache(CFG_SYS_NAND_U_BOOT_DST, CFG_SYS_NAND_U_BOOT_SIZE); #endif puts("transfering control\n"); /* * Jump to U-Boot image */ uboot = (void *)CFG_SYS_NAND_U_BOOT_START; (*uboot)(); } |