mirror of
https://github.com/brain-hackers/u-boot-brain
synced 2024-08-30 05:48:51 +09:00
![Tom Rini](/assets/img/avatar_default.png)
When U-Boot started using SPDX tags we were among the early adopters and there weren't a lot of other examples to borrow from. So we picked the area of the file that usually had a full license text and replaced it with an appropriate SPDX-License-Identifier: entry. Since then, the Linux Kernel has adopted SPDX tags and they place it as the very first line in a file (except where shebangs are used, then it's second line) and with slightly different comment styles than us. In part due to community overlap, in part due to better tag visibility and in part for other minor reasons, switch over to that style. This commit changes all instances where we have a single declared license in the tag as both the before and after are identical in tag contents. There's also a few places where I found we did not have a tag and have introduced one. Signed-off-by: Tom Rini <trini@konsulko.com>
168 lines
4.1 KiB
C
168 lines
4.1 KiB
C
// 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 <common.h>
|
|
#include <asm/io.h>
|
|
#include <asm/fsl_lbc.h>
|
|
#include <nand.h>
|
|
|
|
#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 *)CONFIG_SYS_NAND_BASE;
|
|
const int large = CONFIG_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,
|
|
CONFIG_SYS_NAND_U_BOOT_SIZE,
|
|
(void *)CONFIG_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(CONFIG_SYS_NAND_U_BOOT_DST, CONFIG_SYS_NAND_U_BOOT_SIZE);
|
|
#endif
|
|
|
|
puts("transfering control\n");
|
|
/*
|
|
* Jump to U-Boot image
|
|
*/
|
|
uboot = (void *)CONFIG_SYS_NAND_U_BOOT_START;
|
|
(*uboot)();
|
|
}
|