uboot的启动过程
2014-11-23 12:49
141 查看
Time 2014- 10-14
基于S5PV210平台
===============================================================================
uboot启动第一阶段(汇编代码)流程:
1》 设置异常向量表
2》 进入SVC32模式,并禁止中断CPST[I,F]= 1:1
3》 CPU初始化 I/D cache 和 MMU 禁用
4》 关闭看门狗
5》 VIC控制(中断控制器)---可选
6》 串口初始化(调试用)---可选
7》 时钟初始化
8》 内存初始化(为重定位做准备)
9》 栈的初始化 (SP指针的初始化)
10》 重定位代码到内存中
11》 清bss段
12》 跳转到第二阶段(c代码)
代码跟读:
(cpu/arm_cortexa8/start.S)
.word 0x2000 //----->s5pv210平台uboot需要包含16字节的头部信息
.word 0x0
.word 0x0
.word 0x0
_start: b reset //------------------------------------->1.设置异常向量表
ldr pc,_undefined_instruction
ldr pc,_software_interrupt
ldr pc,_prefetch_abort
ldr pc,_data_abort
ldr pc,_not_used
ldr pc,_irq
ldr pc,_fiq
…..
mrs r0, cpsr//------------------------------------>2. set thecpu to SVC32 mode
bic r0,r0, #0x1f
orr r0,r0, #0xd3
msr cpsr,r0
mrc p15, 0, r0, c1, c0, 0//--------------------->3.disable MMU stuff and caches
bic r0,r0, #0x00002000 @ clear bits 13(--V-)
bic r0,r0, #0x00000007 @ clear bits 2:0(-CAM)
orr r0,r0, #0x00000002 @ set bit 1 (--A-)Align
orr r0,r0, #0x00000800 @ set bit 12(Z---) BTB
mcr p15,0, r0, c1, c0, 0
bl lowlevel_init --------------------------->时钟、内存、栈的初始化
ldrsp,=(0x22000000) ---------------------------->重定位代码到内存中
blcopy_uboot_to_ram
clear_bss: ---------------------------->清bss
ldr r0,_bss_start @ find start of bsssegment
ldr r1,_bss_end @ stop here
mov r2,#0x00000000 @ clear value
ldr pc, _start_armboot ----------------------------->跳转到第二阶段
=============================================================================
u-boot启动第二阶段(lib_arm/board.c)
1》 初始化一个全局变量 gd
2》 完成初始化序列
3》 nand flash 初始化(nand 命令:nand write/nand erase; saveenv…)
4》 环境变量的重定位
5》 网卡的初始化(tftp )
6》 进入一个死循环(倒计时 ---->a结束:自动执行bootcmd 中的内容;b
打断:接收用户的输入 。(处理的都是命令))
代码跟读:
void start_armboot(void)
|
//gd指针,指向哪个地方??
gd= (gd_t*)(_armboot_start - CONFIG_SYS_MALLOC_LEN - sizeof(gd_t));
/* compiler optimization barrier needed forGCC >= 3.4 */
__asm____volatile__("": : :"memory");
memset((void*)gd, 0, sizeof (gd_t));
gd->bd= (bd_t*)((char*)gd - sizeof(bd_t));
memset(gd->bd, 0, sizeof (bd_t)
//执行数组中的所有函数
for (init_fnc_ptr = init_sequence;*init_fnc_ptr; ++init_fnc_ptr) {
if((*init_fnc_ptr)() != 0) {
hang();
}
}
init_sequence
|
board_init, ------------>boaidid 2456
serial_init, ------------>串口初始化
mem_malloc_init (_armboot_start - CONFIG_SYS_MALLOC_LEN,
CONFIG_SYS_MALLOC_LEN); ------>堆的初始化
nand_init(); ---------------------->nand flash
初始化
env_relocate (); ---------------------->环境变量重定位
#if defined(CONFIG_NET_MULTI) --------------------->网卡的初始化
puts ("Net: ");
#endif
eth_initialize(gd->bd);
eth_init(gd->bd);
for (;;) {
main_loop (); ------------------------>进入死循环
}
============================================================================================
全局的gd数据:(Global_data.h(include\asm)
#define DECLARE_GLOBAL_DATA_PTR register volatile gd_t *gd asm ("r8")
全局:该变量在所有的.c文件中都可以访问---- 需要在.c中声明DECLARE_GLOBAL_DATA_PTR
gd->bd->bi_arch_number = MACH_TYPE_SMDKC100; //开发板的id号码 25260-->在内核中要用到
gd->bd->bi_boot_params = PHYS_SDRAM_1 + 0x100; //传递数据给内核的位置
gd->bd->bi_baudrate = gd->baudrate = 115200
gd->bd->bi_dram[0].start = PHYS_SDRAM_1; //记录内存的物理地址:0x2000000
gd->bd->bi_dram[0].size = get_ram_size((long *)PHYS_SDRAM_1,
PHYS_SDRAM_1_SIZE);//记录内存大小
gd->have_console = 1;
gd->env_addr =(ulong)&default_environment[0];
gd->env_valid = 1;
初始化序列 代码跟读:(lib_arm/board.c)
init_sequence[]
|
arch_cpu_init,
|
s5pc1xx_clock_init();
|
if (cpu_is_s5pc110()) { //-------------------------->系统时钟的初始化信息
get_pll_clk = s5pc110_get_pll_clk;
get_arm_clk = s5pc110_get_arm_clk;
get_pclk = s5pc110_get_pclk;
} else {
get_pll_clk =s5pc100_get_pll_clk;
get_arm_clk =s5pc100_get_arm_clk;
get_pclk = s5pc100_get_pclk;
}
board_init,
|
gd->bd->bi_arch_number = MACH_TYPE_SMDKV210; ----->板子id 2456
gd->bd->bi_boot_params = PHYS_SDRAM_1+ 0x100; ----->传递数据给内核的位置
timer_init, //--------------->为uboot提供一个倒计时时间间隔10ms
|
/* count_value / 100 = 20859.375(HZ) (per 10 msec) */ // (cpu/arm_cortexa8/5pcXX/timer.c)
count_value= count_value / 100;
env_init,
|
gd->env_addr
= (ulong)&default_environment[0];
gd->env_valid= 1;
| //----->如果用户没有自定义环境变量,则使用默认值
|
"bootargs=" CONFIG_BOOTARGS
"bootcmd=" CONFIG_BOOTCOMMAND
init_baudrate,
|
gd->bd->bi_baudrate = gd->baudrate = (i > 0)
?(int) simple_strtoul (tmp, NULL, 10)
:CONFIG_BAUDRATE;
serial_init,
|
struct serial_device *dev= default_serial_console ();
dram_init,
|
gd->bd->bi_dram[0].start = PHYS_SDRAM_1; ---->记录物理内存地址
gd->bd->bi_dram[0].size =get_ram_size((long *)PHYS_SDRAM_1,
PHYS_SDRAM_1_SIZE); ---->记录物理内存大小
=================================================================================================
环境变量的处理:(lib_arm/board.c)
voidstart_armboot (void)
|
init_fnc_t*init_sequence[]
|
env_init,
| //(common/env_nand.c)
#else /* ENV_IS_EMBEDDED ||CONFIG_NAND_ENV_DST */
gd->env_addr = (ulong)&default_environment[0];
gd->env_valid= 1;
env_relocate ();
|
env_ptr= (env_t *)malloc (CONFIG_ENV_SIZE);
env_relocate_spec();
| // CONFIG_ENV_OFFSET从nand中的哪个位置读取
ret= readenv(CONFIG_ENV_OFFSET, (u_char *) env_ptr);
if(ret)
returnuse_default(); ------->
如果读取失败,使用默认位置
|
puts ("*** Warning - bad CRC or NAND, using default environment\n\n");
set_default_env();
|
memcpy(env_ptr->data,default_environment, sizeof(default_environment));
gd->env_addr= (ulong)&(env_ptr->data);
================================================================================================
定制默认的环境变量: smdkc100.h(基于S5PC100平台)
#define CONFIG_SERVERIP 192.168.7.2
#define CONFIG_IPADDR 192.168.7.7
#define CONFIG_ETHADDR 00:23:32:34:ee:ab
#define CONFIG_BOOTCOMMAND "tftp0x20800000 uImage35 ; bootm 0x20800000"
#define CONFIG_BOOTARGS "console=ttySAC0,115200 root=/dev/nfsnfsroot=192.168.7.2:/opt/filesystem ip=192.168.7.7 init=/linuxrc"
=================================================================================================
死循环部分代码跟读
main_loop ();
|//(common/main.c)
有两种分析字符串的方式
1, hushparser 类型于shell,复杂, 代码中采用这种方式去分析
CONFIG_SYS_HUSH_PARSER一般都会定义
2, 普通分析方式: 简单
看代码的时候: 看普通分析方法
实际代码 hushparser
s = getenv("bootdelay");
bootdelay = s ?(int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY;
if (bootdelay >= 0&& s && !abortboot (bootdelay)) { //abortboot 就是倒计时
run_command(s, 0);
|
cmd_tbl_t*cmdtp;
(argc= parse_line (finaltoken, argv)
(cmdtp=
find_cmd(argv[0])) //argv[0] = “tftp”
|
int len = &__u_boot_cmd_end - &__u_boot_cmd_start;
returnfind_cmd_tbl(cmd, &__u_boot_cmd_start, len);
|
for (cmdtp =table;cmdtp != table + table_len; cmdtp++) {
if(strncmp (cmd, cmdtp->name, len) == 0)
cmdtp_temp= cmdtp; /* abbreviated command
}
if(n_found == 1) {
/* exactly one match */
returncmdtp_temp;
}
}
//执行命令的处理方式
(cmdtp->cmd) (cmdtp, flag, argc, argv)
//倒计时被打断
for (;;) {
len = readline(CONFIG_SYS_PROMPT);
rc = run_command (lastcommand,flag);
}
=============================================================================================
nandflash初始化(lib_arm/board.c)
start_armboot
|
#if defined(CONFIG_CMD_NAND)
puts ("NAND: ");
nand_init();
| 1, 构建一个mtd_info对象
| 2,构建一个nand_chip对象<---------board_nand_init();
for (i = 0; i <CONFIG_SYS_MAX_NAND_DEVICE; i++) {
nand_init_chip(&nand_info[i], &nand_chip[i], base_address[i]);
| (drivers/mtd/nand/nand.c)
mtd->priv = nand;
nand->IO_ADDR_R =nand->IO_ADDR_W = (void __iomem*)base_addr;
board_nand_init(nand) //初始化nand_chip对象
|
nand->IO_ADDR_R = (void __iomem *)(NFDATA);
nand->IO_ADDR_W = (void __iomem *)(NFDATA);
nand->cmd_ctrl = s3c_nand_hwcontrol;
nand->dev_ready = s3c_nand_device_ready;
nand->scan_bbt = s3c_nand_scan_bbt;
nand->options = 0;
nand_scan(mtd, maxchips) //初始化mtd_info对象
(include\linux\mtd\nand.h)
struct nand_chip{
void __iomem *IO_ADDR_R;
void __iomem *IO_ADDR_W;
uint8_t (*read_byte)(structmtd_info *mtd);
u16 (*read_word)(structmtd_info *mtd);
void (*write_buf)(structmtd_info *mtd, const uint8_t *buf, int len);
void (*read_buf)(structmtd_info *mtd, uint8_t *buf, int len);
int (*verify_buf)(structmtd_info *mtd, const uint8_t *buf, int len);
void (*select_chip)(structmtd_info *mtd, int chip);
int (*block_bad)(structmtd_info *mtd, loff_t ofs, int getchip);
int (*block_markbad)(structmtd_info *mtd, loff_t ofs);
void (*cmd_ctrl)(structmtd_info *mtd, int dat,
unsigned int ctrl);
int (*dev_ready)(structmtd_info *mtd);
void (*cmdfunc)(struct mtd_info *mtd, unsignedcommand, int column, int page_addr);
int (*waitfunc)(structmtd_info *mtd, struct nand_chip *this);
void (*erase_cmd)(structmtd_info *mtd, int page);
int (*scan_bbt)(structmtd_info *mtd);
int (*errstat)(structmtd_info *mtd, struct nand_chip *this, int state, int status, int page);
int (*write_page)(struct mtd_info*mtd, struct nand_chip *chip,
const uint8_t *buf, int page, int cached, intraw);
int chip_delay;
unsignedint options;
int page_shift;
int phys_erase_shift;
int bbt_erase_shift;
int chip_shift;
int numchips;
uint64_t chipsize;
int pagemask;
int pagebuf;
int subpagesize;
uint8_t cellinfo;
int badblockpos;
int state;
uint8_t *oob_poi;
structnand_hw_control *controller;
structnand_ecclayout *ecclayout;
structnand_ecc_ctrl ecc;
structnand_buffers *buffers;
structnand_hw_control hwcontrol;
structmtd_oob_ops ops;
uint8_t *bbt;
structnand_bbt_descr *bbt_td;
structnand_bbt_descr *bbt_md;
structnand_bbt_descr *badblock_pattern;
void *priv;
};
(include\linux\mtd\mtd.h)
struct mtd_info{
int (*read) (struct mtd_info *mtd,loff_t from, size_t len, size_t *retlen, u_char *buf);
int (*write) (struct mtd_info*mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);
void *priv;
}
基于S5PV210平台
===============================================================================
uboot启动第一阶段(汇编代码)流程:
1》 设置异常向量表
2》 进入SVC32模式,并禁止中断CPST[I,F]= 1:1
3》 CPU初始化 I/D cache 和 MMU 禁用
4》 关闭看门狗
5》 VIC控制(中断控制器)---可选
6》 串口初始化(调试用)---可选
7》 时钟初始化
8》 内存初始化(为重定位做准备)
9》 栈的初始化 (SP指针的初始化)
10》 重定位代码到内存中
11》 清bss段
12》 跳转到第二阶段(c代码)
代码跟读:
(cpu/arm_cortexa8/start.S)
.word 0x2000 //----->s5pv210平台uboot需要包含16字节的头部信息
.word 0x0
.word 0x0
.word 0x0
_start: b reset //------------------------------------->1.设置异常向量表
ldr pc,_undefined_instruction
ldr pc,_software_interrupt
ldr pc,_prefetch_abort
ldr pc,_data_abort
ldr pc,_not_used
ldr pc,_irq
ldr pc,_fiq
…..
mrs r0, cpsr//------------------------------------>2. set thecpu to SVC32 mode
bic r0,r0, #0x1f
orr r0,r0, #0xd3
msr cpsr,r0
mrc p15, 0, r0, c1, c0, 0//--------------------->3.disable MMU stuff and caches
bic r0,r0, #0x00002000 @ clear bits 13(--V-)
bic r0,r0, #0x00000007 @ clear bits 2:0(-CAM)
orr r0,r0, #0x00000002 @ set bit 1 (--A-)Align
orr r0,r0, #0x00000800 @ set bit 12(Z---) BTB
mcr p15,0, r0, c1, c0, 0
bl lowlevel_init --------------------------->时钟、内存、栈的初始化
ldrsp,=(0x22000000) ---------------------------->重定位代码到内存中
blcopy_uboot_to_ram
clear_bss: ---------------------------->清bss
ldr r0,_bss_start @ find start of bsssegment
ldr r1,_bss_end @ stop here
mov r2,#0x00000000 @ clear value
ldr pc, _start_armboot ----------------------------->跳转到第二阶段
=============================================================================
u-boot启动第二阶段(lib_arm/board.c)
1》 初始化一个全局变量 gd
2》 完成初始化序列
3》 nand flash 初始化(nand 命令:nand write/nand erase; saveenv…)
4》 环境变量的重定位
5》 网卡的初始化(tftp )
6》 进入一个死循环(倒计时 ---->a结束:自动执行bootcmd 中的内容;b
打断:接收用户的输入 。(处理的都是命令))
代码跟读:
void start_armboot(void)
|
//gd指针,指向哪个地方??
gd= (gd_t*)(_armboot_start - CONFIG_SYS_MALLOC_LEN - sizeof(gd_t));
/* compiler optimization barrier needed forGCC >= 3.4 */
__asm____volatile__("": : :"memory");
memset((void*)gd, 0, sizeof (gd_t));
gd->bd= (bd_t*)((char*)gd - sizeof(bd_t));
memset(gd->bd, 0, sizeof (bd_t)
//执行数组中的所有函数
for (init_fnc_ptr = init_sequence;*init_fnc_ptr; ++init_fnc_ptr) {
if((*init_fnc_ptr)() != 0) {
hang();
}
}
init_sequence
|
board_init, ------------>boaidid 2456
serial_init, ------------>串口初始化
mem_malloc_init (_armboot_start - CONFIG_SYS_MALLOC_LEN,
CONFIG_SYS_MALLOC_LEN); ------>堆的初始化
nand_init(); ---------------------->nand flash
初始化
env_relocate (); ---------------------->环境变量重定位
#if defined(CONFIG_NET_MULTI) --------------------->网卡的初始化
puts ("Net: ");
#endif
eth_initialize(gd->bd);
eth_init(gd->bd);
for (;;) {
main_loop (); ------------------------>进入死循环
}
============================================================================================
全局的gd数据:(Global_data.h(include\asm)
#define DECLARE_GLOBAL_DATA_PTR register volatile gd_t *gd asm ("r8")
全局:该变量在所有的.c文件中都可以访问---- 需要在.c中声明DECLARE_GLOBAL_DATA_PTR
gd->bd->bi_arch_number = MACH_TYPE_SMDKC100; //开发板的id号码 25260-->在内核中要用到
gd->bd->bi_boot_params = PHYS_SDRAM_1 + 0x100; //传递数据给内核的位置
gd->bd->bi_baudrate = gd->baudrate = 115200
gd->bd->bi_dram[0].start = PHYS_SDRAM_1; //记录内存的物理地址:0x2000000
gd->bd->bi_dram[0].size = get_ram_size((long *)PHYS_SDRAM_1,
PHYS_SDRAM_1_SIZE);//记录内存大小
gd->have_console = 1;
gd->env_addr =(ulong)&default_environment[0];
gd->env_valid = 1;
初始化序列 代码跟读:(lib_arm/board.c)
init_sequence[]
|
arch_cpu_init,
|
s5pc1xx_clock_init();
|
if (cpu_is_s5pc110()) { //-------------------------->系统时钟的初始化信息
get_pll_clk = s5pc110_get_pll_clk;
get_arm_clk = s5pc110_get_arm_clk;
get_pclk = s5pc110_get_pclk;
} else {
get_pll_clk =s5pc100_get_pll_clk;
get_arm_clk =s5pc100_get_arm_clk;
get_pclk = s5pc100_get_pclk;
}
board_init,
|
gd->bd->bi_arch_number = MACH_TYPE_SMDKV210; ----->板子id 2456
gd->bd->bi_boot_params = PHYS_SDRAM_1+ 0x100; ----->传递数据给内核的位置
timer_init, //--------------->为uboot提供一个倒计时时间间隔10ms
|
/* count_value / 100 = 20859.375(HZ) (per 10 msec) */ // (cpu/arm_cortexa8/5pcXX/timer.c)
count_value= count_value / 100;
env_init,
|
gd->env_addr
= (ulong)&default_environment[0];
gd->env_valid= 1;
| //----->如果用户没有自定义环境变量,则使用默认值
|
"bootargs=" CONFIG_BOOTARGS
"bootcmd=" CONFIG_BOOTCOMMAND
init_baudrate,
|
gd->bd->bi_baudrate = gd->baudrate = (i > 0)
?(int) simple_strtoul (tmp, NULL, 10)
:CONFIG_BAUDRATE;
serial_init,
|
struct serial_device *dev= default_serial_console ();
dram_init,
|
gd->bd->bi_dram[0].start = PHYS_SDRAM_1; ---->记录物理内存地址
gd->bd->bi_dram[0].size =get_ram_size((long *)PHYS_SDRAM_1,
PHYS_SDRAM_1_SIZE); ---->记录物理内存大小
=================================================================================================
环境变量的处理:(lib_arm/board.c)
voidstart_armboot (void)
|
init_fnc_t*init_sequence[]
|
env_init,
| //(common/env_nand.c)
#else /* ENV_IS_EMBEDDED ||CONFIG_NAND_ENV_DST */
gd->env_addr = (ulong)&default_environment[0];
gd->env_valid= 1;
env_relocate ();
|
env_ptr= (env_t *)malloc (CONFIG_ENV_SIZE);
env_relocate_spec();
| // CONFIG_ENV_OFFSET从nand中的哪个位置读取
ret= readenv(CONFIG_ENV_OFFSET, (u_char *) env_ptr);
if(ret)
returnuse_default(); ------->
如果读取失败,使用默认位置
|
puts ("*** Warning - bad CRC or NAND, using default environment\n\n");
set_default_env();
|
memcpy(env_ptr->data,default_environment, sizeof(default_environment));
gd->env_addr= (ulong)&(env_ptr->data);
================================================================================================
定制默认的环境变量: smdkc100.h(基于S5PC100平台)
#define CONFIG_SERVERIP 192.168.7.2
#define CONFIG_IPADDR 192.168.7.7
#define CONFIG_ETHADDR 00:23:32:34:ee:ab
#define CONFIG_BOOTCOMMAND "tftp0x20800000 uImage35 ; bootm 0x20800000"
#define CONFIG_BOOTARGS "console=ttySAC0,115200 root=/dev/nfsnfsroot=192.168.7.2:/opt/filesystem ip=192.168.7.7 init=/linuxrc"
=================================================================================================
死循环部分代码跟读
main_loop ();
|//(common/main.c)
有两种分析字符串的方式
1, hushparser 类型于shell,复杂, 代码中采用这种方式去分析
CONFIG_SYS_HUSH_PARSER一般都会定义
2, 普通分析方式: 简单
看代码的时候: 看普通分析方法
实际代码 hushparser
s = getenv("bootdelay");
bootdelay = s ?(int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY;
if (bootdelay >= 0&& s && !abortboot (bootdelay)) { //abortboot 就是倒计时
run_command(s, 0);
|
cmd_tbl_t*cmdtp;
(argc= parse_line (finaltoken, argv)
(cmdtp=
find_cmd(argv[0])) //argv[0] = “tftp”
|
int len = &__u_boot_cmd_end - &__u_boot_cmd_start;
returnfind_cmd_tbl(cmd, &__u_boot_cmd_start, len);
|
for (cmdtp =table;cmdtp != table + table_len; cmdtp++) {
if(strncmp (cmd, cmdtp->name, len) == 0)
cmdtp_temp= cmdtp; /* abbreviated command
}
if(n_found == 1) {
/* exactly one match */
returncmdtp_temp;
}
}
//执行命令的处理方式
(cmdtp->cmd) (cmdtp, flag, argc, argv)
//倒计时被打断
for (;;) {
len = readline(CONFIG_SYS_PROMPT);
rc = run_command (lastcommand,flag);
}
=============================================================================================
nandflash初始化(lib_arm/board.c)
start_armboot
|
#if defined(CONFIG_CMD_NAND)
puts ("NAND: ");
nand_init();
| 1, 构建一个mtd_info对象
| 2,构建一个nand_chip对象<---------board_nand_init();
for (i = 0; i <CONFIG_SYS_MAX_NAND_DEVICE; i++) {
nand_init_chip(&nand_info[i], &nand_chip[i], base_address[i]);
| (drivers/mtd/nand/nand.c)
mtd->priv = nand;
nand->IO_ADDR_R =nand->IO_ADDR_W = (void __iomem*)base_addr;
board_nand_init(nand) //初始化nand_chip对象
|
nand->IO_ADDR_R = (void __iomem *)(NFDATA);
nand->IO_ADDR_W = (void __iomem *)(NFDATA);
nand->cmd_ctrl = s3c_nand_hwcontrol;
nand->dev_ready = s3c_nand_device_ready;
nand->scan_bbt = s3c_nand_scan_bbt;
nand->options = 0;
nand_scan(mtd, maxchips) //初始化mtd_info对象
(include\linux\mtd\nand.h)
struct nand_chip{
void __iomem *IO_ADDR_R;
void __iomem *IO_ADDR_W;
uint8_t (*read_byte)(structmtd_info *mtd);
u16 (*read_word)(structmtd_info *mtd);
void (*write_buf)(structmtd_info *mtd, const uint8_t *buf, int len);
void (*read_buf)(structmtd_info *mtd, uint8_t *buf, int len);
int (*verify_buf)(structmtd_info *mtd, const uint8_t *buf, int len);
void (*select_chip)(structmtd_info *mtd, int chip);
int (*block_bad)(structmtd_info *mtd, loff_t ofs, int getchip);
int (*block_markbad)(structmtd_info *mtd, loff_t ofs);
void (*cmd_ctrl)(structmtd_info *mtd, int dat,
unsigned int ctrl);
int (*dev_ready)(structmtd_info *mtd);
void (*cmdfunc)(struct mtd_info *mtd, unsignedcommand, int column, int page_addr);
int (*waitfunc)(structmtd_info *mtd, struct nand_chip *this);
void (*erase_cmd)(structmtd_info *mtd, int page);
int (*scan_bbt)(structmtd_info *mtd);
int (*errstat)(structmtd_info *mtd, struct nand_chip *this, int state, int status, int page);
int (*write_page)(struct mtd_info*mtd, struct nand_chip *chip,
const uint8_t *buf, int page, int cached, intraw);
int chip_delay;
unsignedint options;
int page_shift;
int phys_erase_shift;
int bbt_erase_shift;
int chip_shift;
int numchips;
uint64_t chipsize;
int pagemask;
int pagebuf;
int subpagesize;
uint8_t cellinfo;
int badblockpos;
int state;
uint8_t *oob_poi;
structnand_hw_control *controller;
structnand_ecclayout *ecclayout;
structnand_ecc_ctrl ecc;
structnand_buffers *buffers;
structnand_hw_control hwcontrol;
structmtd_oob_ops ops;
uint8_t *bbt;
structnand_bbt_descr *bbt_td;
structnand_bbt_descr *bbt_md;
structnand_bbt_descr *badblock_pattern;
void *priv;
};
(include\linux\mtd\mtd.h)
struct mtd_info{
int (*read) (struct mtd_info *mtd,loff_t from, size_t len, size_t *retlen, u_char *buf);
int (*write) (struct mtd_info*mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);
void *priv;
}
相关文章推荐
- uboot 的启动过程及工作原理 汇编部分
- UBOOT 启动过程
- uboot启动过程详解
- uboot启动过程完全分析
- 用uboot 烧写uboot linux内核 文件系统到nandflash的 过程以及bootm go命令启动与区别
- uboot的启动过程
- 用uboot 烧写uboot linux内核 文件系统到nandflash的 过程以及bootm go命令启动与区别
- Uboot启动过程详解
- uboot第二阶段启动过程
- Uboot启动过程详解
- zz linux的uboot启动映像uImage制作过程
- Android 的 ramdisk.img、system.img、userdata.img 作用说明,以及UBoot 系统启动过程
- uboot内核启动过程源码分析
- Uboot启动过程详解
- 记录自己学习android系统启动以及 recovery过程(1)----------uboot
- uboot 的启动过程及工作原理 进入 C 代码部分
- uboot启动过程
- uboot 的启动过程及工作原理
- uboot启动过程完全分析(mini2440)
- uboot启动linux的过程