This article only discusses the code re-location process for starting U-boot from NAND Flash
Refer:
1) "user's MANUAL-S3C6410X" Chapter 2 memory map Chapter 8 NAND Flash Controller
2) U-boot source code:
U-boot-x.x.x/board/samsumg/smdk6410/lowlevel_init.s
U-boot-x.x.x/CPU/89c64xx/start. s
U-boot-x.x.x/CPU/89c64xx/nand_cp.c
Brief description of code relocation process
Since Code cannot be run in NAND Flash, when the Development Board starts from NAND Flash, we need to move the U-Boot Code stored in the peripheral NAND flash to the SDRAM for running, how can we complete the handling? This requires the use of a stepping stone, that is, "stepping stone", which is a piece of built-in sram of the initi6410. When the Development Board is powered on, the NAND Flash Controller automatically copies the first 8 K content of the NAND flash to the SRAM and executes the Code. In addition to initializing the hardware, one of the most important tasks is to copy (I .e. relocate) All the U-boot code in NAND flash to the specified address of the SDRAM, and then jump to the SDRAM for execution.
Relocation code parsing:
1) nand interface Initialization
When u-boot is started, lowlevel_init is called in start. s and start. s of the corresponding hardware platform to initialize the underlying hardware such as clock, UART, Nand, and MMU.
Start. S:
...bl lowlevel_init /* go setup pll,mux,memory */...
Lowlevel_init.s:
...
/* * Nand Interface Init for SMDK6400 */nand_asm_init: ldr r0, =ELFIN_NAND_BASE ldr r1, [r0, #NFCONF_OFFSET] orr r1, r1, #0x70 orr r1, r1, #0x7700 str r1, [r0, #NFCONF_OFFSET] ldr r1, [r0, #NFCONT_OFFSET] orr r1, r1, #0x03 str r1, [r0, #NFCONT_OFFSET] mov pc, lr
...
2) code relocation
When starting from NAND Flash, the relocation code is as follows:
Start. S:
/* when we already run in ram, we don‘t need to relocate U-Boot. * and actually, memory controller must be configured before U-Boot * is running in ram. */ ldr r0, =0xff000fff bic r1, pc, r0 /* r0 <- current base addr of code */ ldr r2, _TEXT_BASE /* r1 <- original base addr in ram */ bic r2, r2, r0 /* r0 <- current base addr of code */ cmp r1, r2 /* compare r0, r1 */ beq after_copy /* r0 == r1 then skip flash copy */#ifdef CONFIG_BOOT_NAND mov r0, #0x1000 bl copy_from_nand#endif
R1 stores the starting address of the current Code, R2 stores the address where u-boot is about to run in SDRAM. If the two addresses are equal, U-boot is already running in SDRAM, you do not need to copy data from NAND to SDRAM; otherwise, U-boot is still executed in its temporary residence SRAM, which cannot be kept for a long time, run copy_from_nand to completely copy the U-boot code to the SDRAM, and then jump to the SDRAM to execute the remaining code.
/* * copy U-Boot to SDRAM and jump to ram (from NAND or OneNAND) * r0: size to be compared * Load 1‘st 2blocks to RAM because U-boot‘s size is larger than 1block(128k) size */ .globl copy_from_nandcopy_from_nand: mov r10, lr /* save return address */ mov r9, r0 /* get ready to call C functions */ ldr sp, _TEXT_PHY_BASE /* setup temp stack pointer */ sub sp, sp, #12 mov fp, #0 /* no previous frame, so fp=0 */ mov r9, #0x1000 bl copy_uboot_to_ram3: tst r0, #0x0 bne copy_failed ldr r0, =0x0c000000 ldr r1, _TEXT_PHY_BASE1: ldr r3, [r0], #4 ldr r4, [r1], #4 teq r3, r4 bne compare_failed /* not matched */ subs r9, r9, #4 bne 1b4: mov lr, r10 /* all is OK */ mov pc, lrcopy_failed: nop /* copy from nand failed */ b copy_failedcompare_failed: nop /* compare failed */ b compare_failed
The copy_uboot_to_ram function is used to really execute the copy action, which is defined in the u-boot-x.x.x/CPU/s364xx/nand_cp.c,
int copy_uboot_to_ram (void){ int large_block = 0; int i; vu_char id; NAND_ENABLE_CE(); NFCMD_REG = NAND_CMD_READID; NFADDR_REG = 0x00; /* wait for a while */ for (i=0; i<200; i++); id = NFDATA8_REG; id = NFDATA8_REG; if (id > 0x80) large_block = 1; /* read NAND Block. * 128KB ->240KB because of U-Boot size increase. by scsuh * So, read 0x3c000 bytes not 0x20000(128KB). */ return nandll_read_blocks(CFG_PHY_UBOOT_BASE, 0x3c000, large_block);}
NAND Flash supports two page sizes: 512b and 2kb. When large_block is 0, the page size is 512 bytes. When large_block is 1, the page size is 2 K bytes. Nandll_read_blocks: copy the data in 0x3c00 (0th K) size starting from page 1 of NAND flash to the mongo_phy_uboot_base address of SDRAM.
/* * Read data from NAND. */static int nandll_read_blocks (ulong dst_addr, ulong size, int large_block){ uchar *buf = (uchar *)dst_addr; int i; uint page_shift = 9; if (large_block) page_shift = 11; /* Read pages */ for (i = 0; i < (0x3c000>>page_shift); i++, buf+=(1<<page_shift)) { nandll_read_page(buf, i, large_block); } return 0;}
First, determine the size of a page in nand flash based on large_block, and then calculate the number of pages to be copied, that is, pages to be copied (0x3c000> page_shift, nandll_read_page copies data of only one page at a time.
/* * address format * 17 16 9 8 0 * -------------------------------------------- * | block(12bit) | page(5bit) | offset(9bit) | * -------------------------------------------- */static int nandll_read_page (uchar *buf, ulong addr, int large_block){ int i; int page_size = 512; if (large_block) page_size = 2048; NAND_ENABLE_CE(); NFCMD_REG = NAND_CMD_READ0; /* Write Address */ NFADDR_REG = 0; if (large_block) NFADDR_REG = 0; NFADDR_REG = (addr) & 0xff; NFADDR_REG = (addr >> 8) & 0xff; NFADDR_REG = (addr >> 16) & 0xff; if (large_block) NFCMD_REG = NAND_CMD_READSTART; NF_TRANSRnB(); /* for compatibility(2460). u32 cannot be used. by scsuh */ for(i=0; i < page_size; i++) { *buf++ = NFDATA8_REG; } NAND_DISABLE_CE(); return 0;}
The process for reading data from NAND Flash is to select (nand_enable_ce)-> send READ command (nf1__reg)-> send address (nfaddr_reg)-> send READ command (nf1__reg) -> Read data (nf_transrnb)-> Read data (nfdata8_reg ). Since only one byte of data can be read from nfdata8_reg each time, you need to read 512 or 2048 times to copy a page.
After copy_uboot_to_ram is executed and return to start. S, code relocation in NAND Flash is completed. After that, the program jumps to SDRAM for execution, and stepping stone's responsibility ends.