This article only discusses the code relocation process when s3c6410 starts u-boot from nand flash
reference:
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/s3c64xx/start.S
u-boot-x.x.x/cpu/s3c64xx/nand_cp.c
A brief description of the code relocation process
Since the code cannot be run in nand flash, when the development board boots from nand flash, we need to move the u-boot code stored in the peripheral nand flash to sdram for execution. How to complete this task? This requires the help of a stepping stone, which is a built-in sram of s3c6410. When the development board is powered on, the nand flash controller automatically copies the first 8K of nand flash to sram and executes it. In addition to initializing the hardware, the most important task of this small startup code is to copy (i.e. relocate) all the u-boot codes in nand flash to the specified address of sdram, and then jump to sdram for execution.
Relocation code analysis:
1) NAND interface initialization
When u-boot starts, it first executes start.S of the corresponding hardware platform. In start.S, lowlevel_init is called to initialize the underlying hardware such as clock, uart, nand, mmu, etc.
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 booting 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, and r2 stores the address where u-boot will run in sdram. If the two addresses are equal, it means that u-boot is already running in sdram and there is no need to copy data from nand to sdram. Otherwise, u-boot is still executing in its temporary residence sram, where it cannot stay for long. It is necessary to execute copy_from_nand to copy the u-boot code completely to sdram, and then jump to sdram to execute the rest of the 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_nand
copy_from_nand:
mov r10, lr /* save return address */
move 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 */
move r9, #0x1000
bl copy_uboot_to_ram
3: tst r0, #0x0
bne copy_failed
ldr r0, =0x0c000000
ldr r1, _TEXT_PHY_BASE
1: ldr r3, [r0], #4
ldr r4, [r1], #4
teq r3, r4
bne compare_failed /* not matched */
subs r9, r9, #4
bne 1b
4: mov lr, r10 /* all is OK */
mov pc, lr
copy_failed:
nop /* copy from nand failed */
b copy_failed
compare_failed:
nop /* compare failed */
b compare_failed
The function that actually performs the copy operation is copy_uboot_to_ram, which is defined in u-boot-xxx/cpu/s3c64xx/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 = 0, the page size is 512 bytes, and when large_block = 1, the page size is 2KB. nandll_read_blocks copies the data of size 0x3c00 (240KB) of NAND flash starting from page 0 to the CFG_PHY_UBOOT_BASE address of SDRAM.
/*
* Read data from NAND.
*/
static int nandll_read_blocks (ulong dst_addr, ulong size, int large_block)
{
fly *buf = (fly *)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<
nandll_read_page(buf, i, large_block);
}
return 0;
}
First, the size of a nand flash page is determined based on large_block, and the number of pages that need to be copied is calculated, that is, (0x3c000>>page_shift) pages need to be copied, and nandll_read_page only copies one page of data each 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 of reading data from nand flash is chip select (NAND_ENABLE_CE) -> send read command (NFCMD_REG) -> send address (NFADDR_REG) -> send read command (NFCMD_REG) -> wait for data to be readable (NF_TRANSRnB) -> read data (NFDATA8_REG). Since only 1 byte of data can be read from NFDATA8_REG each time, it takes 512 or 2048 times to copy one page.
When copy_uboot_to_ram is executed and returns to start.S, the code relocation in nand flash is completed. After that, the program jumps to sdram for execution, and the stepping stone's responsibility ends.
Previous article:s3c6410_MMU address mapping process details
Next article:s3c6410_uart initialization and reading and writing
Recommended ReadingLatest update time:2024-11-15 17:19
Professor at Beihang University, dedicated to promoting microcontrollers and embedded systems for over 20 years.
- LED chemical incompatibility test to see which chemicals LEDs can be used with
- Application of ARM9 hardware coprocessor on WinCE embedded motherboard
- What are the key points for selecting rotor flowmeter?
- LM317 high power charger circuit
- A brief analysis of Embest's application and development of embedded medical devices
- Single-phase RC protection circuit
- stm32 PVD programmable voltage monitor
- Introduction and measurement of edge trigger and level trigger of 51 single chip microcomputer
- Improved design of Linux system software shell protection technology
- What to do if the ABB robot protection device stops
- Huawei's Strategic Department Director Gai Gang: The cumulative installed base of open source Euler operating system exceeds 10 million sets
- Download from the Internet--ARM Getting Started Notes
- Learn ARM development(22)
- Learn ARM development(21)
- Learn ARM development(20)
- Learn ARM development(19)
- Learn ARM development(14)
- Learn ARM development(15)
- Analysis of the application of several common contact parts in high-voltage connectors of new energy vehicles
- Wiring harness durability test and contact voltage drop test method
- Some bytes of code in the application memory area of MSP430FR5949IDAR FRAM are tampered
- Overview of RFID Anti-collision Technology
- MSP430 low power mode - while loop fails
- [MM32 eMiniBoard Review] Give feedback on this board
- IWR6843 Smart mmWave Sensor Antenna-Package Evaluation Module
- Three designs of constant current circuit
- How can an outdoor Bluetooth speaker output the same power as a 12V lead-acid battery using two 7.4V lithium batteries?
- 【GD32F307E-START】+I2C driver problem
- Essential survival skills for power engineers - 20 classic analog circuits
- Please recommend a power IC with 12V input and 48V/1.2A output