U-boot(四):start_armboot
本文主要探讨210的uboot启动的第二阶段,主要函数为start_armboot。
uboot
一阶段初始化SoC内部部件(看门狗、时钟等),初始化DDR,重定位
二阶段初始化其余硬件(iNand、网卡芯片···)以及命令、环境变量等···
启动打印硬件信息,进入bootdelay,读秒完后执行bootcmd启动内核或打断读秒进入命名状态
一阶段为汇编,在SRAM中,主要在SoC内部,二阶段为C阶,在DRAM中,主要在Board内部
start_armboot(函数在uboot/lib_arm/board.c(444~908))
全局变量
全局变量定义
#define DECLARE_GLOBAL_DATA_PTR register volatile gd_t *gd asm ("r8")
typedef struct global_data {bd_t *bd;unsigned long flags;unsigned long baudrate;unsigned long have_console; /* serial_init() was called */unsigned long reloc_off; /* Relocation Offset */unsigned long env_addr; /* Address of Environment struct */unsigned long env_valid; /* Checksum of Environment valid? */unsigned long fb_base; /* base address of frame buffer */#ifdef CONFIG_VFDunsigned char vfd_type; /* display type */#endif#if 0unsigned long cpu_clk; /* CPU clock in Hz! */unsigned long bus_clk;phys_size_t ram_size; /* RAM size */unsigned long reset_status; /* reset status register at boot */#endifvoid **jt; /* jump table */} gd_t;
定义全局变量gd到寄存器r8中,为gd_t类型变量指针
gd_t定义在include/asm-arm/global_data.h中
gd_t中定义全局变量,其中bd_t结构体包含硬件参数(波特率,IP,mac,机器码,启动参数,环境变量,DDR,网卡)
全局变量内存分配
#ifdef CONFIG_MEMORY_UPPER_CODE /* by scsuh */ulong gd_base;gd_base = CFG_UBOOT_BASE + CFG_UBOOT_SIZE - CFG_MALLOC_LEN - CFG_STACK_SIZE - sizeof(gd_t);#ifdef CONFIG_USE_IRQgd_base -= (CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ);#endifgd = (gd_t*)gd_base;#elsegd = (gd_t*)(_armboot_start - CFG_MALLOC_LEN - sizeof(gd_t));#endifgd_base = CFG_UBOOT_BASE + CFG_UBOOT_SIZE - CFG_MALLOC_LEN - CFG_STACK_SIZE - sizeof(gd_t);gd = (gd_t*)gd_base;
#define CFG_UBOOT_BASE 0xc3e00000 #define CFG_UBOOT_SIZE (2*1024*1024) #define CFG_MALLOC_LEN (CFG_ENV_SIZE + 896*1024) #define CFG_ENV_SIZE 0x4000 //(16字节)#define CFG_STACK_SIZE 512*1024
uboot CFG_UBOOT_BASE(2MB)
堆 CFG_MALLOC_LEN(912KB)
栈 CFG_STACK_SIZE(512KB)
gd sizeof(gd_t)(36字节)
bd sizeof(bd_t)(44字节左右)
全局变量内存清空
__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));monitor_flash_len = _bss_start - _armboot_start;
board级硬件初始化
init_fnc_t **init_fnc_ptr;typedef int (init_fnc_t) (void); //函数类型
init_fnc_ptr是二重函数指针,用来指向函数指针数组
for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {if ((*init_fnc_ptr)() != 0) {hang ();}}
init_fnc_t *init_sequence[] = {cpu_init, /* basic cpu dependent setup */#if defined(CONFIG_SKIP_RELOCATE_UBOOT)reloc_init, /* Set the relocation done flag, mustdo this AFTER cpu_init(), but as soonas possible */#endifboard_init, /* basic board dependent setup */interrupt_init, /* set up exceptions */env_init, /* initialize environment */init_baudrate, /* initialze baudrate settings */serial_init, /* serial communications setup */console_init_f, /* stage 1 init of console */display_banner, /* say that we are here */#if defined(CONFIG_DISPLAY_CPUINFO)print_cpuinfo, /* display cpu info (and speed) */#endif#if defined(CONFIG_DISPLAY_BOARDINFO)checkboard, /* display board info */#endif#if defined(CONFIG_HARD_I2C) || defined(CONFIG_SOFT_I2C)init_func_i2c,#endifdram_init, /* configure available RAM banks */display_dram_config,NULL,};
cpu_init
int cpu_init (void){/** setup up stacks if necessary*/#ifdef CONFIG_USE_IRQIRQ_STACK_START = _armboot_start - CFG_MALLOC_LEN - CFG_GBL_DATA_SIZE - 4;FIQ_STACK_START = IRQ_STACK_START - CONFIG_STACKSIZE_IRQ;#endifreturn 0;}
空函数,cpu初始化在一阶段cpu_init_crit函数中完成(汇编)
board_init(uboot/board/samsung/x210/x210.c)
int board_init(void){DECLARE_GLOBAL_DATA_PTR;#ifdef CONFIG_DRIVER_SMC911Xsmc9115_pre_init();#endif#ifdef CONFIG_DRIVER_DM9000dm9000_pre_init();#endifgd->bd->bi_arch_number = MACH_TYPE;gd->bd->bi_boot_params = (PHYS_SDRAM_1+0x100);return 0;}
static void dm9000_pre_init(void){unsigned int tmp;#if defined(DM9000_16BIT_DATA)SROM_BW_REG &= ~(0xf << 4);SROM_BW_REG |= (1<<7) | (1<<6) | (1<<5) | (1<<4);#elseSROM_BW_REG &= ~(0xf << 4);SROM_BW_REG |= (0<<6) | (0<<5) | (0<<4);#endifSROM_BC1_REG = ((0<<28)|(1<<24)|(5<<16)|(1<<12)|(4<<8)|(6<<4)|(0<<0));//uboot//SROM_BC1_REG = ((0<<28)|(0<<24)|(5<<16)|(0<<12)|(0<<8)|(0<<4)|(0<<0));//kerneltmp = MP01CON_REG;tmp &=~(0xf<<4);tmp |=(2<<4);MP01CON_REG = tmp;}
dm9000_pre_init函数为网卡初始化(GPIO和端口配置非驱动),gd->bd->bi_arch_number定义机器码,gd->bd->bi_boot_params为内核启动传递参数内存地址(0x30000100)
gd->bd->bi_boot_params = (PHYS_SDRAM_1+0x100);
#define CONFIG_NR_DRAM_BANKS 2 /* we have 2 bank of DRAM */#define SDRAM_BANK_SIZE 0x10000000 //256 /*0x20000000*/ /* 512 MB */#define PHYS_SDRAM_1 MEMORY_BASE_ADDRESS /* SDRAM Bank #1 */#define PHYS_SDRAM_1_SIZE SDRAM_BANK_SIZE#define PHYS_SDRAM_2 MEMORY_BASE_ADDRESS2 /* SDRAM Bank #2 */#define PHYS_SDRAM_2_SIZE SDRAM_BANK_SIZE
#define CFG_FLASH_BASE 0x80000000
#define MEMORY_BASE_ADDRESS 0x30000000
一阶段汇编lowlevel_init初始化DDR为硬件初始化(gpio),DDR可工作,此处为DDR属性配置、地址初始化
x210_sd.h(496~501)宏定义DDR参数(内存个数,内存起始地址,内存长度)
interrupt_init
int interrupt_init(void){S5PC11X_TIMERS *const timers = S5PC11X_GetBase_TIMERS();/* use PWM Timer 4 because it has no output *//* prescaler for Timer 4 is 16 */timers->TCFG0 = 0x0f00;if (timer_load_val == 0) {/** for 10 ms clock period @ PCLK with 4 bit divider = 1/2* (default) and prescaler = 16. Should be 10390* @33.25MHz and @ 66 MHz*/timer_load_val = get_PCLK() / (16 * 100);}/* load value for 10 ms timeout */lastdec = timers->TCNTB4 = timer_load_val;/* auto load, manual update of Timer 4 */timers->TCON = (timers->TCON & ~0x00700000) | TCON_4_AUTO | TCON_4_UPDATE;/* auto load, start Timer 4 */timers->TCON = (timers->TCON & ~0x00700000) | TCON_4_AUTO | COUNT_4_ON;timestamp = 0;return (0);}
初始化定时器(Timer4),210有5个PWM定时器,Timer0-timer3对应PWM信号输出引脚,Timer4无引脚用来做计时
env_init
int env_init(void){#if defined(ENV_IS_EMBEDDED)ulong total;int crc1_ok = 0, crc2_ok = 0;env_t *tmp_env1, *tmp_env2;total = CFG_ENV_SIZE;tmp_env1 = env_ptr;tmp_env2 = (env_t *)((ulong)env_ptr + CFG_ENV_SIZE);crc1_ok = (crc32(0, tmp_env1->data, ENV_SIZE) == tmp_env1->crc);crc2_ok = (crc32(0, tmp_env2->data, ENV_SIZE) == tmp_env2->crc);if (!crc1_ok && !crc2_ok)gd->env_valid = 0;else if(crc1_ok && !crc2_ok)gd->env_valid = 1;else if(!crc1_ok && crc2_ok)gd->env_valid = 2;else {/* both ok - check serial */if(tmp_env1->flags == 255 && tmp_env2->flags == 0)gd->env_valid = 2;else if(tmp_env2->flags == 255 && tmp_env1->flags == 0)gd->env_valid = 1;else if(tmp_env1->flags > tmp_env2->flags)gd->env_valid = 1;else if(tmp_env2->flags > tmp_env1->flags)gd->env_valid = 2;else /* flags are equal - almost impossible */gd->env_valid = 1;}if (gd->env_valid == 1)env_ptr = tmp_env1;else if (gd->env_valid == 2)env_ptr = tmp_env2;#else /* ENV_IS_EMBEDDED */gd->env_addr = (ulong)&default_environment[0];gd->env_valid = 1;#endif /* ENV_IS_EMBEDDED */return (0);}
环境变量初始化,开发板可能包含不同启动介质(norflash、nandflash、inand、sd卡·····),故env的存取需要支持多种存储方式,210使用的为inand(env_movi.c)
函数有无环境变量(无),start_armboot函数(776)调用env_relocate将环境变量从SD卡重定位到DDR,重定位从SD卡中读取
/* initialize environment */env_relocate ();
init_baudrate
static int init_baudrate (void){char tmp[64]; /* long enough for environment variables */int i = getenv_r ("baudrate", tmp, sizeof (tmp));gd->bd->bi_baudrate = gd->baudrate = (i > 0)? (int) simple_strtoul (tmp, NULL, 10): CONFIG_BAUDRATE;return (0);}int getenv_r (char *name, char *buf, unsigned len){int i, nxt;for (i=0; env_get_char(i) != '\0'; i=nxt+1) {int val, n;for (nxt=i; env_get_char(nxt) != '\0'; ++nxt) {if (nxt >= CFG_ENV_SIZE) {return (-1);}}if ((val=envmatch((uchar *)name, i)) < 0)continue;/* found; copy out */n = 0;while ((len > n++) && (*buf++ = env_get_char(val++)) != '\0');if (len == n)*buf = '\0';return (n);}return (-1);}
初始化串口通信的波特率,getenv_r函数读取环境变量值,读取环境变量值为字符串类型在转成相应类型(simple_strtoul将字符串转int)
读取环境变量中波特率值(gd->baudrate,gd->bd->bi_baudrate),若没有则在x210_sd.h中CONFIG_BAUDRATE值作为波特率(环境变量优先级高)
serial_init
int serial_init(void){serial_setbrg();return (0);}空函数,一阶段汇编lowlevel_init中uart_asm_init初始化串口console_init_fint console_init_f (void){gd->have_console = 1;#ifdef CONFIG_SILENT_CONSOLEif (getenv("silent") != NULL)gd->flags |= GD_FLG_SILENT;#endifreturn (0);}
console_init_f是console(控制台)一阶段初始化
display_banner
static int display_banner (void){printf ("\n\n%s\n\n", version_string);debug ("U-Boot code: %08lX -> %08lX BSS: -> %08lX\n",_armboot_start, _bss_start, _bss_end);#ifdef CONFIG_MEMORY_UPPER_CODE /* by scsuh */debug("\t\bMalloc and Stack is above the U-Boot Code.\n");#elsedebug("\t\bMalloc and Stack is below the U-Boot Code.\n");#endif#ifdef CONFIG_MODEM_SUPPORTdebug ("Modem Support enabled\n");#endif#ifdef CONFIG_USE_IRQdebug ("IRQ Stack: %08lx\n", IRQ_STACK_START);debug ("FIQ Stack: %08lx\n", FIQ_STACK_START);#endifopen_backlight();//lqm.//open_gprs();return (0);}
串口输出显示uboot的logo,U_BOOT_VERSION在makefile中定义,编译时生成到include/version_autogenerated.h的宏中
print_cpuinfo
int print_cpuinfo(void){uint set_speed;uint tmp;uchar result_set;#if defined(CONFIG_CLK_533_133_100_100)set_speed = 53300;#elif defined(CONFIG_CLK_667_166_166_133)set_speed = 66700;#elif defined(CONFIG_CLK_800_200_166_133)set_speed = 80000;#elif defined(CONFIG_CLK_1000_200_166_133)set_speed = 100000;#elif defined(CONFIG_CLK_1200_200_166_133)set_speed = 120000;#elseset_speed = 100000;printf("Any CONFIG_CLK_XXX is not enabled\n");#endiftmp = (set_speed / (get_ARMCLK()/1000000));if((tmp < 105) && (tmp > 95)){result_set = 1;} else {result_set = 0;}#ifdef CONFIG_MCP_SINGLEprintf("\nCPU: S5PV210@%ldMHz(%s)\n", get_ARMCLK()/1000000, ((result_set == 1) ? "OK" : "FAIL"));#elseprintf("\nCPU: S5PC110@%ldMHz(%s)\n", get_ARMCLK()/1000000, ((result_set == 1) ? "OK" : "FAIL"));#endifprintf(" APLL = %ldMHz, HclkMsys = %ldMHz, PclkMsys = %ldMHz\n",get_FCLK()/1000000, get_HCLK()/1000000, get_PCLK()/1000000);#if 1printf(" MPLL = %ldMHz, EPLL = %ldMHz\n",get_MPLL_CLK()/1000000, get_PLLCLK(EPLL)/1000000);printf(" HclkDsys = %ldMHz, PclkDsys = %ldMHz\n",get_HCLKD()/1000000, get_PCLKD()/1000000);printf(" HclkPsys = %ldMHz, PclkPsys = %ldMHz\n",get_HCLKP()/1000000, get_PCLKP()/1000000);printf(" SCLKA2M = %ldMHz\n", get_SCLKA2M()/1000000);#endifputs("Serial = CLKUART ");return 0;
}
CPU: S5PV210@1000MHz(OK)
APLL = 1000MHz, HclkMsys = 200MHz, PclkMsys = 100MHz
MPLL = 667MHz, EPLL = 96MHz
HclkDsys = 166MHz, PclkDsys = 83MHz
HclkPsys = 133MHz, PclkPsys = 66MHz
SCLKA2M = 200MHz
Serial = CLKUART
print_cpuinfo打印uboot启动时的cpu参数信息
checkboard
int checkboard(void){#ifdef CONFIG_MCP_SINGLE#if defined(CONFIG_VOGUES)printf("\nBoard: VOGUESV210\n");#elseprintf("\nBoard: X210\n");#endif //CONFIG_VOGUES#elseprintf("\nBoard: X210\n");#endifreturn (0);}
打印开发板名字
init_func_i2c
static int init_func_i2c (void){puts ("I2C: ");i2c_init (CFG_I2C_SPEED, CFG_I2C_SLAVE);puts ("ready\n");return (0);}
X210的uboot未使用I2C,此函数无用
dram_init
int dram_init(void){DECLARE_GLOBAL_DATA_PTR;gd->bd->bi_dram[0].start = PHYS_SDRAM_1;gd->bd->bi_dram[0].size = PHYS_SDRAM_1_SIZE;#if defined(PHYS_SDRAM_2)gd->bd->bi_dram[1].start = PHYS_SDRAM_2;gd->bd->bi_dram[1].size = PHYS_SDRAM_2_SIZE;#endif#if defined(PHYS_SDRAM_3)gd->bd->bi_dram[2].start = PHYS_SDRAM_3;gd->bd->bi_dram[2].size = PHYS_SDRAM_3_SIZE;#endifreturn 0;}
dram_init在一阶段初始化low_level_init中初始化,此处为给全局变量定义赋值,记录DDR配置(gd->bd->bi_dram)
display_dram_config
static int display_dram_config (void){int i;#ifdef DEBUGputs ("RAM Configuration:\n");for(i=0; i<CONFIG_NR_DRAM_BANKS; i++) {printf ("Bank #%d: %08lx ", i, gd->bd->bi_dram[i].start);print_size (gd->bd->bi_dram[i].size, "\n");}#elseulong size = 0;for (i=0; i<CONFIG_NR_DRAM_BANKS; i++) {size += gd->bd->bi_dram[i].size;}puts("DRAM: ");print_size(size, "\n");#endifreturn (0);}
打印显示dram配置信息,uboot启动信息(DRAM: 512 MB)在该处打印
uboot命令bdinfo,打印的位gd->bd中记录硬件全局变量(DDR信息)
DRAM bank = 0x00000000-> start = 0x30000000-> size = 0x10000000DRAM bank = 0x00000001-> start = 0x40000000-> size = 0x10000000
堆管理器初始化
static void mem_malloc_init (ulong dest_addr)
{mem_malloc_start = dest_addr;mem_malloc_end = dest_addr + CFG_MALLOC_LEN;mem_malloc_brk = mem_malloc_start;memset ((void *) mem_malloc_start, 0,mem_malloc_end - mem_malloc_start);
}
初始化uboot堆管理器,DDR内存中堆预留896KB
mmc初始化
#if defined(CONFIG_X210)#if defined(CONFIG_GENERIC_MMC)puts ("SD/MMC: ");mmc_exist = mmc_initialize(gd->bd);if (mmc_exist != 0){puts ("0 MB\n");#ifdef CONFIG_CHECK_X210CV3check_flash_flag=0;//check inand error!#endif}#ifdef CONFIG_CHECK_X210CV3else{check_flash_flag=1;//check inand ok! }#endif#endif#if defined(CONFIG_MTD_ONENAND)puts("OneNAND: ");onenand_init();/*setenv("bootcmd", "onenand read c0008000 80000 380000;bootm c0008000");*/#else//puts("OneNAND: (FSR layer enabled)\n");#endif#if defined(CONFIG_CMD_NAND)puts("NAND: ");nand_init();#endif#endif /* CONFIG_X210 */
mmc_initialize是MMC基础初始化(SoC内部的SD/MMC控制器),函数在uboot/drivers/mmc/mmc.c
uboot对硬件操作(网卡、SD卡···)是用linux内核驱动实现的(drivers目录)
mmc_initialize初始化函数实际调用board_mmc_init和cpu_mmc_init初始化
cpu_mmc_init在uboot/cpu/s5pc11x/cpu.c,实际调用drivers/mmc/s3c_mmcxxx.c驱动代码初始化MMC
环境变量重定位
/* initialize environment */env_relocate ();
SD卡有独立扇区作为环境变量存储区域,uboot代码中包含默认环境变量,运行时会被读取到DDR环境变量中,在写入SD卡中
IP,MAC地址
/* IP Address */gd->bd->bi_ip_addr = getenv_IPaddr ("ipaddr");/* MAC Address */{int i;ulong reg;char *s, *e;char tmp[64];i = getenv_r ("ethaddr", tmp, sizeof (tmp));s = (i > 0) ? tmp : NULL;for (reg = 0; reg < 6; ++reg) {gd->bd->bi_enetaddr[reg] = s ? simple_strtoul (s, &e, 16) : 0;if (s)s = (*e) ? e + 1 : e;}#ifdef CONFIG_HAS_ETH1i = getenv_r ("eth1addr", tmp, sizeof (tmp));s = (i > 0) ? tmp : NULL;for (reg = 0; reg < 6; ++reg) {gd->bd->bi_enet1addr[reg] = s ? simple_strtoul (s, &e, 16) : 0;if (s)s = (*e) ? e + 1 : e;}#endif}
初始化全局变量中的IP和MAC(gd->bd)
devices_init
int devices_init (void)
{#ifndef CONFIG_ARM /* already relocated for current ARM implementation */ulong relocation_offset = gd->reloc_off;int i;/* relocate device name pointers */for (i = 0; i < (sizeof (stdio_names) / sizeof (char *)); ++i) {stdio_names[i] = (char *) (((ulong) stdio_names[i]) +relocation_offset);}#endif/* Initialize the list */devlist = ListCreate (sizeof (device_t));if (devlist == NULL) {eputs ("Cannot initialize the list of devices!\n");return -1;}#if defined(CONFIG_HARD_I2C) || defined(CONFIG_SOFT_I2C)i2c_init (CFG_I2C_SPEED, CFG_I2C_SLAVE);#endif#ifdef CONFIG_LCDdrv_lcd_init ();#endif#if defined(CONFIG_VIDEO) || defined(CONFIG_CFB_CONSOLE)drv_video_init ();#endif#ifdef CONFIG_KEYBOARDdrv_keyboard_init ();#endif#ifdef CONFIG_LOGBUFFERdrv_logbuff_init ();#endifdrv_system_init ();#ifdef CONFIG_SERIAL_MULTIserial_devices_init ();#endif#ifdef CONFIG_USB_TTYdrv_usbtty_init ();#endif#ifdef CONFIG_NETCONSOLEdrv_nc_init ();#endifreturn (0);
}
函数执行所有从linux内核中继承来的那些硬件驱动的初始化函数
跳转表
void jumptable_init (void)
{int i;gd->jt = (void **) malloc (XF_MAX * sizeof (void *));for (i = 0; i < XF_MAX; i++)gd->jt[i] = (void *) dummy;gd->jt[XF_get_version] = (void *) get_version;gd->jt[XF_malloc] = (void *) malloc;gd->jt[XF_free] = (void *) free;gd->jt[XF_getenv] = (void *) getenv;gd->jt[XF_setenv] = (void *) setenv;gd->jt[XF_get_timer] = (void *) get_timer;gd->jt[XF_simple_strtoul] = (void *) simple_strtoul;gd->jt[XF_udelay] = (void *) udelay;gd->jt[XF_simple_strtol] = (void *) simple_strtol;gd->jt[XF_strcmp] = (void *) strcmp;#if defined(CONFIG_I386) || defined(CONFIG_PPC)gd->jt[XF_install_hdlr] = (void *) irq_install_handler;gd->jt[XF_free_hdlr] = (void *) irq_free_handler;#endif /* I386 || PPC */#if defined(CONFIG_CMD_I2C)gd->jt[XF_i2c_write] = (void *) i2c_write;gd->jt[XF_i2c_read] = (void *) i2c_read;#endif
}
未使用
控制台二阶段初始化
/* Called after the relocation - use desired console functions */
int console_init_r (void)
{device_t *inputdev = NULL, *outputdev = NULL;int i, items = ListNumItems (devlist);#ifdef CONFIG_SPLASH_SCREEN/* suppress all output if splash screen is enabled and we havea bmp to display */if (getenv("splashimage") != NULL)gd->flags |= GD_FLG_SILENT;#endif/* Scan devices looking for input and output devices */for (i = 1;(i <= items) && ((inputdev == NULL) || (outputdev == NULL));i++) {device_t *dev = ListGetPtrToItem (devlist, i);if ((dev->flags & DEV_FLAGS_INPUT) && (inputdev == NULL)) {inputdev = dev;}if ((dev->flags & DEV_FLAGS_OUTPUT) && (outputdev == NULL)) {outputdev = dev;}}/* Initializes output console first */if (outputdev != NULL) {console_setfile (stdout, outputdev);console_setfile (stderr, outputdev);}/* Initializes input console */if (inputdev != NULL) {console_setfile (stdin, inputdev);}gd->flags |= GD_FLG_DEVINIT; /* device initialization completed */#ifndef CFG_CONSOLE_INFO_QUIET/* Print information */puts ("In: ");if (stdio_devices[stdin] == NULL) {puts ("No input devices available!\n");} else {printf ("%s\n", stdio_devices[stdin]->name);}puts ("Out: ");if (stdio_devices[stdout] == NULL) {puts ("No output devices available!\n");} else {printf ("%s\n", stdio_devices[stdout]->name);}puts ("Err: ");if (stdio_devices[stderr] == NULL) {puts ("No error devices available!\n");} else {printf ("%s\n", stdio_devices[stderr]->name);}#endif /* CFG_CONSOLE_INFO_QUIET */#ifndef CONFIG_X210/* Setting environment variables */for (i = 0; i < 3; i++) {setenv (stdio_names[i], stdio_devices[i]->name);}#endif#if 0/* If nothing usable installed, use only the initial console */if ((stdio_devices[stdin] == NULL) && (stdio_devices[stdout] == NULL))return (0);#endifreturn (0);
}
console_init_r初始化数据结构配置值
使能中断
void enable_interrupts (void)
{return;
}
初始化网卡地址
#ifdef CONFIG_DRIVER_CS8900cs8900_get_enetaddr (gd->bd->bi_enetaddr);
#endif初始化网卡地址(gd->bd)loadaddr和bootfile/* Initialize from environment */if ((s = getenv ("loadaddr")) != NULL) {load_addr = simple_strtoul (s, NULL, 16);}
#if defined(CONFIG_CMD_NET)if ((s = getenv ("bootfile")) != NULL) {copy_filename (BootFile, s, sizeof (BootFile));}
初始化环境变量,启动linux内核使用该值
空函数
#ifdef BOARD_LATE_INITboard_late_init ();
#endif
#if defined(CONFIG_CMD_NET)
#if defined(CONFIG_NET_MULTI)puts ("Net: ");
#endifeth_initialize(gd->bd);
#if defined(CONFIG_RESET_PHY_R)debug ("Reset Ethernet PHY\n");reset_phy();
#endif
#endif#if defined(CONFIG_CMD_IDE)puts("IDE: ");ide_init();
#endif
board_late_init,eth_initialize空函数
LCD初始化和logo显示
#ifdef CONFIG_MPADextern int x210_preboot_init(void);x210_preboot_init();
#endifextern void mpadfb_init(void);
int x210_preboot_init(void)
{mpadfb_init();return 1;
}
void mpadfb_init()
{// unsigned short int *pFB;//杩欓噷涓€瀹氳鐢╯hort绫诲瀷!// int i;fb_init();//lqm masked for testlcd_port_init();lcd_reg_init();#ifdef CONFIG_CHECK_X210CV3init_logo();#endifdisplay_logo(&s5pv210_fb);#if(DISP_MODE == TRULY043)backlight_brigness_init(0);#else//AT070TN92backlight_brigness_init(1);#endif// pFB = (unsigned short int *)CFG_LCD_FBUFFER;/*for(i=0; i<800*480; i++)*pFB++ = 0xf800;*//* for(i=0; i<800*100; i++)*pFB++ = 0xf800;for(i=800*100; i<800*200; i++)*pFB++ = 0x07e0;for(i=800*200; i<800*480; i++)*pFB++ = 0x001f;*/#if(DISP_MODE == TRULY043)writel((readl(GPF3DAT) & ~(0x1<<5)) | (0x1<<5), GPF3DAT);#endif
}
快速烧录(镜像升级)
/* check menukey to update from sd */extern void update_all(void);if(check_menu_update_from_sd()==0)//update mode{puts ("[LEFT DOWN] update mode\n");run_command("fdisk -c 0",0);update_all();}elseputs ("[LEFT UP] boot mode\n");
镜像烧录到SD卡,开机按键LEFT键烧录到iNand中
死循环
for (;;) {main_loop ();}/* NOTREACHED - no way out of command loop except booting */
开机延时,命令解析执行
demo:
烧录修改并编译的uboot
make distclean && make x210_sd_config && makecd sd_fusing/make clean./sd_fusing.sh /dev/sdb
结果示例:
相关文章:

U-boot(四):start_armboot
本文主要探讨210的uboot启动的第二阶段,主要函数为start_armboot。 uboot 一阶段初始化SoC内部部件(看门狗、时钟等),初始化DDR,重定位 二阶段初始化其余硬件(iNand、网卡芯片)以及命令、环境变量等 启动打印硬件信息,进入bootdelay,读秒完后执行bootc…...
.Net面试题4
1.请解释一下泛型(Generics)在C#中的作用。 泛型是一种将数据类型参数化的机制,使得代码可以在编译时具有更强的类型安全性和灵活性。C#中的泛型可以用于类、接口、方法等的定义和实例化。泛型允许在编写代码时使用具有不同实参的类型&#x…...
python 列表插入数据的 四种方法 append insert extend 切片赋值
append insert 插入单个数据 append 加到末尾,insert 加到指定位置 extend、切片方式插入多个数据 extend 加到末尾,切片加到指定位置 my_list [1, 2, 3] my_list.append(4) print(my_list) # 输出: [1, 2, 3, 4]my_list [1, 2, 3] my_list.insert(…...
C++中std::string的=,+,+=使用过程中的问题
1. 调用构造函数时的运算符不支持int,char类型的操作数 string str1 a; //error 这是一个构造函数。C中string是一个类,内部封装了char *来管理这个字符串。 string的构造函数: string() // 创建一个空的字符串string(const char * s)…...

ruoyi-plus使用Statistic统计组件升级element-plus
原本使用的就是gitee上lionli的ruoyi-plus版本的代码。但是在使用过程中作首页数据看板时想使用elementui的Statistic统计组件。结果在浏览器控制台报错找不到组件el-statistic 于是查看elementui的历史版本,发现是在新版中才有这个组件,旧版本是没这个组…...
Python基础入门例程72-NP72 生成字典(字典)
最近的博文: Python基础入门例程71-NP71 喜欢的颜色(字典)-CSDN博客 Python基础入门例程70-NP70 首都(字典)-CSDN博客 Python基础入门例程69-NP69 姓名与学号(字典)-CSDN博客 目录 最近的博文: 描述...
flink的java.lang.IllegalStateException: Buffer pool is destroyed 异常
背景 最近flink的在线应用出现错误java.lang.IllegalStateException: Buffer pool is destroyed,本文记录下这个错误的原因 错误原因 详细的日志堆栈如下: Caused by: java.lang.IllegalStateException: Buffer pool is destroyed. at org.apache.flink.runtime…...

物联网AI MicroPython学习之语法 实时时钟RTC
学物联网,来万物简单IoT物联网!! RTC 介绍 模块功能: 实时时钟RTC驱动模块 接口说明 RTC - 构建RTC对象 函数原型:RTC()参数说明: 无 返回值: 构建的RTC对象。 datetime - RTC时钟操作 函数原型&a…...

GEE:kNN(k-最近邻)分类教程(样本制作、特征添加、训练、精度、最优参数、统计面积)
作者:CSDN @ _养乐多_ 本文将介绍在Google Earth Engine (GEE)平台上进行kNN(k-最近邻)分类的方法和代码,其中包括制作样本点教程(本地、在线和本地在线混合制作样本点,合并样本点等),加入特征变量(各种指数、纹理特征、时间序列特征、物候特征等),运行kNN(k-最近…...

【GitHub】保姆级使用教程
一、如何流畅访问GitHub 1、网易uu加速器 输入网址,无脑下载网易加速器;https://uu.163.com/ 下载安装完毕后,创建账号进行登录 登录后,在右上角搜索框中搜索“学术资源”,并点击; 稍等一会儿就会跳…...
Kotlin基础——Lambda和函数式编程
Lambda 使用 { } 定义Lamba,调用run运行 run { println(1) }更常用的为 { 参数 -> 操作 },还可以存储到变量中,把变量作为普通函数对待 val sum { x: Int, y: Int -> x y } println(sum(1, 2))maxBy()接收一个Lambda,传…...

mysql忘记密码,然后重置
数据库版本8.0.26 只针对以下情况 mysql忘记了密码,但是你navicat之前连接上了 解决方法: 第一步,选中mysql这个数据库,点击新建查询 第二步:重置密码 alter user rootlocalhost IDENTIFIED BY 你的密码; 然后就可…...
linux centos系统命令安装
Zip unzip 命令安装下载 centos 命令常用常用下载 https://rpmfind.net/linux/rpm2html/search.php?queryzip%28x86-64%29&submitSearch…&system&arch 在线安装zip命令 Centos用yum安装的话用下面的命令安装 yum install -y unzip zipUbuntu的的系统可以用下…...

基于springboot实现高校食堂移动预约点餐系统【项目源码】计算机毕业设计
基于springboot实现高校食堂移动预约点餐系统演示 Java语言简介 Java是由SUN公司推出,该公司于2010年被oracle公司收购。Java本是印度尼西亚的一个叫做爪洼岛的英文名称,也因此得来java是一杯正冒着热气咖啡的标识。Java语言在移动互联网的大背景下具备…...

栈和队列OJ题目——C语言
目录 LeetCode 20、有效的括号 题目描述: 思路解析: 解题代码: 通过代码: LeetCode 225、用队列实现栈 题目描述: 思路解析: 解题代码: 通过代码: LeetCode 232、用栈…...

System-V共享内存和基于管道通信实现的进程池
文章目录 一.进程间通信:进程间通信的本质: 二.Linux管道通信匿名管道:关于管道通信的要点:基于匿名管道构建进程池: 三.System-V共享内存共享内存和命名管道协同通信 参考Linux内核源码版本------linux-2.4.3 一.进程间通信: 操作系统中,为了保证安全性,进程之间具有严格的独…...

Python武器库开发-前端篇之CSS基本语法(三十)
前端篇之CSS基本语法(三十) CSS简介 CSS(层叠样式表)是一种用于描述网页外观和布局的样式表语言。它与 HTML 一起,帮助开发者对网页进行美化和布局。CSS通过定义网页元素的颜色、字体、大小、背景、边框等属性,使网页变得更加美…...

微信小程序实现类似Vue中的computed、watch功能
微信小程序实现类似Vue中的computed、watch功能 构建npm使用 构建npm 创建包管理器 进入小程序后,打开终端,点击顶部“视图” - “终端” 新建终端 使用 npm init -y初始化包管理器,生成一个package.json文件 安装 npm 包 npm install --…...
[JVM] 美团二面,说一下JVM数据区域
Java 虚拟机在执行 Java 程序的过程中会把它管理的内存划分成若干个不同的数据区域。这些区域有不同的用途。 文章目录 线程私有的数据区域1. 程序计数器2. Java 虚拟机栈3. 本地方法栈 线程共享的数据区域1. Java 堆2. 方法区3. 运行时常量池4. 直接内存 线程私有的数据区域 …...

深入剖析AI大模型:大模型时代的 Prompt 工程全解析
今天聊的内容,我认为是AI开发里面非常重要的内容。它在AI开发里无处不在,当你对 AI 助手说 "用李白的风格写一首关于人工智能的诗",或者让翻译模型 "将这段合同翻译成商务日语" 时,输入的这句话就是 Prompt。…...

python打卡day49
知识点回顾: 通道注意力模块复习空间注意力模块CBAM的定义 作业:尝试对今天的模型检查参数数目,并用tensorboard查看训练过程 import torch import torch.nn as nn# 定义通道注意力 class ChannelAttention(nn.Module):def __init__(self,…...

vscode(仍待补充)
写于2025 6.9 主包将加入vscode这个更权威的圈子 vscode的基本使用 侧边栏 vscode还能连接ssh? debug时使用的launch文件 1.task.json {"tasks": [{"type": "cppbuild","label": "C/C: gcc.exe 生成活动文件"…...
Frozen-Flask :将 Flask 应用“冻结”为静态文件
Frozen-Flask 是一个用于将 Flask 应用“冻结”为静态文件的 Python 扩展。它的核心用途是:将一个 Flask Web 应用生成成纯静态 HTML 文件,从而可以部署到静态网站托管服务上,如 GitHub Pages、Netlify 或任何支持静态文件的网站服务器。 &am…...
sqlserver 根据指定字符 解析拼接字符串
DECLARE LotNo NVARCHAR(50)A,B,C DECLARE xml XML ( SELECT <x> REPLACE(LotNo, ,, </x><x>) </x> ) DECLARE ErrorCode NVARCHAR(50) -- 提取 XML 中的值 SELECT value x.value(., VARCHAR(MAX))…...

第 86 场周赛:矩阵中的幻方、钥匙和房间、将数组拆分成斐波那契序列、猜猜这个单词
Q1、[中等] 矩阵中的幻方 1、题目描述 3 x 3 的幻方是一个填充有 从 1 到 9 的不同数字的 3 x 3 矩阵,其中每行,每列以及两条对角线上的各数之和都相等。 给定一个由整数组成的row x col 的 grid,其中有多少个 3 3 的 “幻方” 子矩阵&am…...

3-11单元格区域边界定位(End属性)学习笔记
返回一个Range 对象,只读。该对象代表包含源区域的区域上端下端左端右端的最后一个单元格。等同于按键 End 向上键(End(xlUp))、End向下键(End(xlDown))、End向左键(End(xlToLeft)End向右键(End(xlToRight)) 注意:它移动的位置必须是相连的有内容的单元格…...

Maven 概述、安装、配置、仓库、私服详解
目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...

视觉slam十四讲实践部分记录——ch2、ch3
ch2 一、使用g++编译.cpp为可执行文件并运行(P30) g++ helloSLAM.cpp ./a.out运行 二、使用cmake编译 mkdir build cd build cmake .. makeCMakeCache.txt 文件仍然指向旧的目录。这表明在源代码目录中可能还存在旧的 CMakeCache.txt 文件,或者在构建过程中仍然引用了旧的路…...

排序算法总结(C++)
目录 一、稳定性二、排序算法选择、冒泡、插入排序归并排序随机快速排序堆排序基数排序计数排序 三、总结 一、稳定性 排序算法的稳定性是指:同样大小的样本 **(同样大小的数据)**在排序之后不会改变原始的相对次序。 稳定性对基础类型对象…...