In the previous article, we will focus on the differences between k9gag08u0d and k9gag08u0e. In addition to these differences, there is also a place to focus on. Next we will explain in detail.
The first step for uboot to start from nandflash is to copy the first 8 K code of nandflash to the internal SRAM of, and then run the command, the 8 K code will copy the complete uboot code from nandflash to the off-board memory of the 6410 Development Board. Here I use the 256m DDR and the uboot storage address is 0x5fe00000, the virtual address is 0xcfe00000.
Note: The key 8 K code is not stored on the first two pages of u0d (4 K per page), nor on the first page of u0e (8 K per page, instead, it is stored in the first four pages of u0e or u0d. The first four pages are divided into 2 kb for each page, a total of 8 KB, which is defined by the processor. The data after 8 K bytes is stored according to the actual page number. u0d stores 4 K bytes per page, and u0e stores 8 K bytes per page.
You can enable the uboot function from the SD card. the binfile is written to nandflash. You can take a closer look at the NAND write in uboot. the uboot command writes data to the first four pages of nandflash. After successful writing, you can start uboot from nandflash.
The key code of NAND write. uboot is located in the uboot1.1.6/common/cmd_nand.c file:
If (! Read & S! = NULL &&(! Strcmp (S, ". uboot") & NAND-> writesize = 4096) // u0d
{
Size = 4096;
Nand_write (nand, off, & size, (u_char *) ADDR );
Off + = 4096;
ADDR ++ = 2048;
Nand_write (nand, off, & size, (u_char *) ADDR );
Off + = 4096;
ADDR ++ = 2048;
Nand_write (nand, off, & size, (u_char *) ADDR );
Off + = 4096;
ADDR ++ = 2048;
Nand_write (nand, off, & size, (u_char *) ADDR );
Off + = 4096;
ADDR ++ = 2048;
Size = 1024*1024-4*4096;
Ret = nand_write (nand, off, & size, (u_char *) ADDR );
} Else if (! Read & S! = NULL &&(! Strcmp (S, ". uboot") & NAND-> writesize = 8192) // u0e
{
Size = 8192;
Ret = nand_write (nand, off, & size, (u_char *) ADDR );
Off + = 8192;
ADDR ++ = 2048;
Ret = nand_write (nand, off, & size, (u_char *) ADDR );
Off + = 8192;
ADDR ++ = 2048;
Ret = nand_write (nand, off, & size, (u_char *) ADDR );
Off + = 8192;
ADDR ++ = 2048;
Ret = nand_write (nand, off, & size, (u_char *) ADDR );
Off + = 8192;
ADDR ++ = 2048;
// Write the remaining page. uboot occupies 1 MB of nandflash address space and occupies 128 pages (128 pages = 1 MB) in u0e. Four pages have been written on it, the remaining 124 pages are written here. The remaining 124 pages are enough to store valid uboot data.
Size = 1024*1024-4*8192;
Ret = nand_write (nand, off, & size, (u_char *) ADDR );
}
Now we should focus on the uboot code, uboot1.1.6/CPU/cloud64xx/nand_cp.c file:
// This function is in the first 8 K code of uboot. bin. This function copies uboot from nandflash to the external memory, which is the key for uboot to start from nandflash.
Int copy_uboot_to_ram (void)
{
Int large_block = 0;
Int I;
Vu_char ID;
Nand_enable_ce ();
Nf1__reg = nand_1__reset;
Nf_transrnb ();
Nf1__reg = nand_1__readid;
Nfaddr_reg = 0x00;
Nf_transrnb ();
/* Wait for a while */
For (I = 0; I <200; I ++ );
Int factory = nfdata8_reg;
Id = nfdata8_reg;
Int cellinfo = nfdata8_reg;
Int TMP = nfdata8_reg;
Int childtype = TMP & 0x03; // page size
If (ID> 0x80)
{
Large_block = 1;
}
If (ID = 0xd5 & childtype = 0x01) // k9gag08u0d
{
Large_block = 2;
} Else if (ID = 0xd5 & childtype = 0x02 )//K9gag08u0d
{
Large_block = 3;
}
/* Read NAND block.
* 128kb-> 240kb because of U-boot size increase. By scsuh
* So, read 0x3c000 bytes not 0x20000 (128kb ).
*/
Return nandll_read_blocks (pai_phy_uboot_base, 0x3c000, large_block );
}
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 = 1)
Page_shift = 11;
If (large_block = 2)
Page_shift = 12;
If (large_block = 3)
Page_shift = 13;
If (large_block = 2) // k9gag08u0d
{
/* Read pages */
For (I = 0; I <4; I ++, BUF + = (1 <(page_shift-1 )))
{
Nandll_read_page (BUF, I, large_block );
}
/* Read pages */
For (I = 4; I <(0x3c000> page_shift); I ++, BUF + = (1 <page_shift ))
{
Nandll_read_page (BUF, I, large_block );
}
} Else if (large_block = 3) // k9gag08u0e
{
/* Read pages */
For (I = 0; I <4; I ++, BUF + = (1 <(page_shift-2 )))
{
Nandll_read_page (BUF, I, large_block );
}
/* Read pages */
For (I = 4; I <(0x3c000> page_shift); I ++, BUF + = (1 <page_shift ))
{
Nandll_read_page (BUF, I, large_block );
}
}
Else
{
For (I = 0; I <(0x3c000> page_shift); I ++, BUF + = (1 <page_shift ))
{
Nandll_read_page (BUF, I, large_block );
}
}
Return 0;
}
Static int nandll_read_page (uchar * Buf, ulong ADDR, int large_block)
{
Int I;
Int page_size = 512;
If (large_block = 1)
Page_size = 2048;
If (large_block = 2)
Page_size = 4096;
If (large_block = 3)
Page_size = 8192;
Nand_enable_ce ();
Nf1__reg = nand_1__read0;
/* Write address * // five addressing cycles, see
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)
Nf1__reg = nand_1__readstart;
Nf_transrnb (); // wait for the nandflash status pin to be readable.
/* For compatibility (2460). u32 cannot be used. By scsuh */
For (I = 0; I <page_size; I ++)
{
* Buf ++ = nfdata8_reg;
}
Nand_disable_ce ();
Return 0;
}
Addressing cycle diagram:
For more information, see k9gag08u0e datasheet 9th.
Here we use two articles to describe the key points for supporting k9gag08u0e in the S. Of course, there are some specific details, such as assigning page size and block size to key structures such as NAND chip and mtd_device, OOB size operations, hardware ECC 8-Bit Error Correction and other functions, of course, these are not unique to k9gag08u0e, k9gag08u0d also need such operations, this is not detailed here.
I hope these two articles will be of reference value to friends who need to know how nandflash works through software.