uboot源码分析——start_armboot

本文详细分析了U-Boot启动过程中的start_armboot函数,包括gd_t结构体初始化、环境变量处理、串口初始化、定时器设置、I/O中断初始化、DRAM初始化等关键步骤。通过对源码的解读,揭示了U-Boot启动时系统配置和硬件初始化的过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


Stage2源码分析

start_armboot函数的路径:/lib_arm/board.c

void start_armboot (void)
{
init_fnc_t **init_fnc_ptr;
char *s;
#if defined(CONFIG_VFD) || defined(CONFIG_LCD)
unsigned long addr;
#endif
#if defined(CONFIG_MINI2440_LED) 
struct s3c24x0_gpio * const gpio = s3c24x0_get_base_gpio();
#endif
/* Pointer is writable since we allocated a register for it */
gd = (gd_t*)(_armboot_start - CONFIG_SYS_MALLOC_LEN - sizeof(gd_t));
/* compiler optimization barrier needed for GCC >= 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));
 
gd->flags |= GD_FLG_RELOC;
 
monitor_flash_len = _bss_start - _armboot_start;
 
for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
if ((*init_fnc_ptr)() != 0) {
hang ();
}
}
 
/* armboot_start is defined in the board-specific linker script */
mem_malloc_init (_armboot_start - CONFIG_SYS_MALLOC_LEN,
CONFIG_SYS_MALLOC_LEN);
 
#ifndef CONFIG_SYS_NO_FLASH
/* configure available FLASH banks */
display_flash_config (flash_init ());
#endif /* CONFIG_SYS_NO_FLASH */
 
#ifdef CONFIG_VFD
#	ifndef PAGE_SIZE
#	  define PAGE_SIZE 4096
#	endif
/*
 * reserve memory for VFD display (always full pages)
 */
/* bss_end is defined in the board-specific linker script */
addr = (_bss_end + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
vfd_setmem (addr);
gd->fb_base = addr;
#endif /* CONFIG_VFD */
 
#ifdef CONFIG_LCD
/* board init may have inited fb_base */
if (!gd->fb_base) {
#	 ifndef PAGE_SIZE
#	   define PAGE_SIZE 4096
#	 endif
/*
 * reserve memory for LCD display (always full pages)
 */
/* bss_end is defined in the board-specific linker script */
addr = (_bss_end + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
lcd_setmem (addr);
gd->fb_base = addr;
}
#endif /* CONFIG_LCD */
 
#if defined(CONFIG_CMD_NAND)
puts ("NAND:  ");
nand_init();	 /* go init the NAND */
#endif
 
#if defined(CONFIG_CMD_ONENAND)
onenand_init();
#endif
 
#ifdef CONFIG_HAS_DATAFLASH
AT91F_DataflashInit();
dataflash_print_info();
#endif
 
/* initialize environment */
env_relocate ();
 
#ifdef CONFIG_VFD
/* must do this after the framebuffer is allocated */
drv_vfd_init();
#endif /* CONFIG_VFD */
 
#ifdef CONFIG_SERIAL_MULTI
serial_initialize();
#endif
 
/* IP Address */
gd->bd->bi_ip_addr = getenv_IPaddr ("ipaddr");
 
stdio_init ();	/* get the devices list going. */
 
jumptable_init ();
 
#if defined(CONFIG_API)
/* Initialize API */
api_init ();
#endif
 
console_init_r ();	/* fully init console as a device */
 
#if defined(CONFIG_ARCH_MISC_INIT)
/* miscellaneous arch dependent initialisations */
arch_misc_init ();
#endif
#if defined(CONFIG_MISC_INIT_R)
/* miscellaneous platform dependent initialisations */
misc_init_r ();
#endif
/* enable exceptions */
enable_interrupts ();
 
#ifdef CONFIG_USB_DEVICE
usb_init_slave();
#endif
/* Perform network card initialisation if necessary */
#ifdef CONFIG_DRIVER_TI_EMAC
/* XXX: this needs to be moved to board init */
extern void davinci_eth_set_mac_addr (const u_int8_t *addr);
if (getenv ("ethaddr")) {
uchar enetaddr[6];
eth_getenv_enetaddr("ethaddr", enetaddr);
davinci_eth_set_mac_addr(enetaddr);
}
#endif
 
#if defined(CONFIG_DRIVER_SMC91111) || defined (CONFIG_DRIVER_LAN91C96)
/* XXX: this needs to be moved to board init */
if (getenv ("ethaddr")) {
uchar enetaddr[6];
eth_getenv_enetaddr("ethaddr", enetaddr);
smc_set_mac_addr(enetaddr);
}
#endif /* CONFIG_DRIVER_SMC91111 || CONFIG_DRIVER_LAN91C96 */
 
/* 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));
}
#endif
 
#ifdef BOARD_LATE_INIT
board_late_init ();
#endif
 
#ifdef CONFIG_GENERIC_MMC
puts ("MMC:   ");
mmc_initialize (gd->bd);
#endif
 
#ifdef CONFIG_BITBANGMII
bb_miiphy_init();
#endif
#if defined(CONFIG_CMD_NET)
#if defined(CONFIG_NET_MULTI)
puts ("Net:   ");
#endif
eth_initialize(gd->bd);
#if defined(CONFIG_RESET_PHY_R)
debug ("Reset Ethernet PHY\n");
reset_phy();
#endif
#endif
#if defined(CONFIG_MINI2440_LED) 
gpio->GPBDAT = 0x0; //tekkamanninja
#endif
 
#if defined(CONFIG_CFB_CONSOLE)        
printf ("%s\n", version_string);
printf ("modified by kangear\n(kangear@163.com)\n");
printf ("Love Linux forever!!\n");
#endif
/* main_loop() can return to retry autoboot, if so just run it again. */
for (;;) {
main_loop ();
}
 
/* NOTREACHED - no way out of command loop except booting */
}
 

下面来分析代码:

struct s3c24x0_gpio * const gpio = s3c24x0_get_base_gpio();

又有 

static inline struct s3c24x0_gpio *s3c24x0_get_base_gpio(void)
{
return (struct s3c24x0_gpio *)S3C24X0_GPIO_BASE;
}
<span style="line-height: 25.98958396911621px; font-size: 12pt; font-family: 宋体;">#define S3C24X0_GPIO_BASE</span><span style="line-height: 25.98958396911621px; font-size: 12pt; font-family: 宋体;">	</span><span style="line-height: 25.98958396911621px; font-size: 12pt; font-family: 宋体;">0x56000000</span>

返回返回0x56000000,赋给gpio指针。

 

/* Pointer is writable since we allocated a register for it */
gd = (gd_t*)(_armboot_start - CONFIG_SYS_MALLOC_LEN - sizeof(gd_t));

看一下gd_t的定义,在include/asm-arm/global_data.h文件中:

#ifndef	__ASM_GBL_DATA_H
#define __ASM_GBL_DATA_H
/*
 * The following data structure is placed in some memory wich is
 * available very early after boot (like DPRAM on MPC8xx/MPC82xx, or
 * some locked parts of the data cache) to allow for a minimum set of
 * global variables during system initialization (until we have set
 * up the memory controller so that we can use RAM).
 *
 * Keep it *SMALL* and remember to set CONFIG_SYS_GBL_DATA_SIZE > sizeof(gd_t)
 */
 
typedef	struct	global_data {
bd_t	 *bd;
unsigned long	flags;
unsigned long	baudrate;
unsigned long	have_console;	/* serial_init() was called */
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_VFD
unsigned char	vfd_type;	/* display type */
#endif
#if 0
unsigned 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 */
#endif
void	 **jt;	 /* jump table */
} gd_t;

sizeofgd_t)就是gd_t结构体的大小,所以_armboot_start - CONFIG_SYS_MALLOC_LEN - sizeof(gd_t)就相当于减去malloc area再减去gd_t结构体的大小,把此处地址赋值给指针gd

需要注意的一点是

bd_t *bd;

bd是一个结构体指针,指针大小为4字节,并不是该结构体嵌套在gd_t结构体中。

 

/* compiler optimization barrier needed for GCC >= 3.4 */
__asm__ __volatile__("": : :"memory");

memory 强制gcc编译器假设RAM所有内存单元均被汇编指令修改,这样cpu中的registerscache中已缓存的内存单元中的数据将作废。cpu将不得不在需要的时候重新读取内存中的数据。这就阻止了cpuregisterscache中的数据用于去优化指令,而避免去访问内存。

 

memset ((void*)gd, 0, sizeof (gd_t));
gd->bd = (bd_t*)((char*)gd - sizeof(bd_t));
memset (gd->bd, 0, sizeof (bd_t));
 
gd->flags |= GD_FLG_RELOC;
 
monitor_flash_len = _bss_start - _armboot_start;
 
for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
if ((*init_fnc_ptr)() != 0) {
hang ();
}
}

gd_t结构体进行初始化,首先清0

确定bd_t结构体的位置,并把该位置赋值给指针gd->bd

bd_t结构体清0

gd->flags应该是表示是否要relocate code

#define	GD_FLG_RELOC	0x00001	 /* Code was relocated to RAM	 */

 

monitor_flash_len = _bss_start - _armboot_start;

Uboot镜像的大小,以下是一个内存的示意图





for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
if ((*init_fnc_ptr)() != 0) {
hang ();
}
}

board.c中,定义init_sequence

typedef int (init_fnc_t) (void);

又有: 

init_fnc_t *init_sequence[] = {
#if defined(CONFIG_ARCH_CPU_INIT)
arch_cpu_init,	 /* basic arch cpu dependent setup */
#endif
board_init,	 /* basic board dependent setup */
#if defined(CONFIG_USE_IRQ)
interrupt_init,	 /* set up exceptions */
#endif
timer_init,	 /* initialize timer */
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,
#endif
dram_init,	 /* configure available RAM banks */
#if defined(CONFIG_CMD_PCI) || defined (CONFIG_PCI)
arm_pci_init,
#endif
display_dram_config,
NULL,
};

先是定义一个函数类型typedef int (init_fnc_t) (void);

该函数的返回值int,形参为void

init_sequence为函数指针数组,遍历该数组即执行该数组中所有元素各自指向的函数。


 

下面来看一下指针数组中的各个函数:


arch_cpu_init 

CONFIG_ARCH_CPU_INIT没有找到该定义,则不会执行arch_cpu_init

 

board_init

/board/tekkamanninja/mini2440/mini2440.c中:

/*
 * Miscellaneous platform dependent initialisations
 */
 
int board_init (void)
{
struct s3c24x0_clock_power * const clk_power =
s3c24x0_get_base_clock_power();
struct s3c24x0_gpio * const gpio = s3c24x0_get_base_gpio();
 
/* to reduce PLL lock time, adjust the LOCKTIME register */
clk_power->LOCKTIME = 0xFFFFFF;
 
/* configure MPLL */
clk_power->MPLLCON = ((M_MDIV << 12) + (M_PDIV << 4) + M_SDIV);
 
/* some delay between MPLL and UPLL */
delay (4000);
 
/* configure UPLL */
clk_power->UPLLCON = ((U_M_MDIV << 12) + (U_M_PDIV << 4) + U_M_SDIV);
 
/* some delay between MPLL and UPLL */
delay (8000);
 
/* set up the I/O ports */
gpio->GPACON = 0x007FFFFF;
 
#if defined(CONFIG_MINI2440) 
gpio->GPBCON = 0x00295551;
#else
gpio->GPBCON = 0x00044556;
#endif
 
gpio->GPBUP = 0x000007FF;
 
#if defined(CONFIG_MINI2440) 
gpio->GPCCON = 0xAAAAA6AA;
gpio->GPCDAT &= ~(1<<5);
#else
gpio->GPCCON = 0xAAAAAAAA;
#endif
gpio->GPCUP = 0xFFFFFFFF;
gpio->GPDCON = 0xAAAAAAAA;
gpio->GPDUP = 0xFFFFFFFF;
 
    gpio->GPECON = 0xAAAAAAAA;
gpio->GPEUP = 0x0000FFFF;
gpio->GPFCON = 0x000055AA;
gpio->GPFUP = 0x000000FF;
gpio->GPGCON = 0xFF95FF3A;
gpio->GPGUP = 0x0000FFFF;
gpio->GPHCON = 0x0016FAAA;
gpio->GPHUP = 0x000007FF;
 
gpio->EXTINT0=0x22222222;
gpio->EXTINT1=0x22222222;
gpio->EXTINT2=0x22222222;
 
#if defined(CONFIG_S3C2440)
/* arch number of S3C2440-Board */
gd->bd->bi_arch_number = MACH_TYPE_MINI2440 ;
#endif
 
 
/* adress of boot parameters */
gd->bd->bi_boot_params = 0x30000100;
 
icache_enable();
dcache_enable();
#if	defined(CONFIG_MINI2440_LED)
gpio->GPBDAT = 0x00000180;
#endif
return 0;
}<span style="font-family: 宋体; font-size: 12pt; line-height: 19.5pt;"> </span>

设置时钟,引脚初始化,arch number

gd->bd->bi_boot_params存放参数的地址,这些参数用来启动Linux内核。

I/D Cache 使能。

 

interrupt_init

#if defined(CONFIG_USE_IRQ)
interrupt_init,	 /* set up exceptions */
#endif<span style="font-family: 宋体; font-size: 12pt; line-height: 19.5pt;"> </span>

mini2440.h

//#undef CONFIG_USE_IRQ	 /* we don't need IRQ/FIQ stuff */
#define CONFIG_USB_DEVICE 1
#ifdef CONFIG_USB_DEVICE
#define CONFIG_USE_IRQ 1
#endif

所以interrupt_init是执行的:

/lib_arm/interrupts.c

#ifdef CONFIG_USE_IRQ
DECLARE_GLOBAL_DATA_PTR;
 
int interrupt_init (void)
{
/*
 * setup up stacks if necessary
 */
IRQ_STACK_START = _armboot_start - CONFIG_SYS_MALLOC_LEN - CONFIG_SYS_GBL_DATA_SIZE - 4;
FIQ_STACK_START = IRQ_STACK_START - CONFIG_STACKSIZE_IRQ;
 
return arch_interrupt_init();
}

include/configs/mini2440.h文件中:

#ifdef CONFIG_USE_IRQ
#define CONFIG_STACKSIZE_IRQ	(4*1024)	/* IRQ stack */
#define CONFIG_STACKSIZE_FIQ	(4*1024)	/* FIQ stack */
#endif

cpu/arm920t/s3c24x0interrupts.c文件中:

int arch_interrupt_init (void)
{
return 0;
}

所以这里只是对IRQ_STACK_STARTFIQ_STACK_START这两个宏进行赋值,这两个宏是在哪定义的,看start.S

#ifdef CONFIG_USE_IRQ
/* IRQ stack memory (calculated at run-time) */
.globl IRQ_STACK_START
IRQ_STACK_START:
.word	0x0badc0de
 
/* IRQ stack memory (calculated at run-time) */
.globl FIQ_STACK_START
FIQ_STACK_START:
.word 0x0badc0de
#endif

之前只是随便赋了一个值0x0badc0de,现在把他们重新赋值而已。

 

timer_init

对定时器的一些初始化,定时器了解的不多,先放这边以后补。。。。

 

env_init

/common/env_nand.c
/* this is called before nand_init()
 * so we can't read Nand to validate env data.
 * Mark it OK for now. env_relocate() in env_common.c
 * will call our relocate function which does the real
 * validation.
 *
 * When using a NAND boot image (like sequoia_nand), the environment
 * can be embedded or attached to the U-Boot image in NAND flash. This way
 * the SPL loads not only the U-Boot image from NAND but also the
 * environment.
 */
int env_init(void)
{
#if defined(ENV_IS_EMBEDDED) || defined(CONFIG_NAND_ENV_DST)
int crc1_ok = 0, crc2_ok = 0;
env_t *tmp_env1;
 
#ifdef CONFIG_ENV_OFFSET_REDUND
env_t *tmp_env2;
 
tmp_env2 = (env_t *)((ulong)env_ptr + CONFIG_ENV_SIZE);
crc2_ok = (crc32(0, tmp_env2->data, ENV_SIZE) == tmp_env2->crc);
#endif
 
tmp_env1 = env_ptr;
 
crc1_ok = (crc32(0, tmp_env1->data, ENV_SIZE) == tmp_env1->crc);
 
if (!crc1_ok && !crc2_ok) {
gd->env_addr  = 0;
gd->env_valid = 0;
 
return 0;
} else if (crc1_ok && !crc2_ok) {
gd->env_valid = 1;
}
#ifdef CONFIG_ENV_OFFSET_REDUND
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 == 2)
env_ptr = tmp_env2;
else
#endif
if (gd->env_valid == 1)
env_ptr = tmp_env1;
 
gd->env_addr = (ulong)env_ptr->data;
 
#else /* ENV_IS_EMBEDDED || CONFIG_NAND_ENV_DST */
gd->env_addr  = (ulong)&default_environment[0];
gd->env_valid = 1;
#endif /* ENV_IS_EMBEDDED || CONFIG_NAND_ENV_DST */
 
return (0);
}

本意上是对环境变量进行初始化,但是根据注释可以发现,这个函数是在nand_init之前调用的,所以不可能把Nand中的环境变量CopySDRAM中,这里要做的工作只是对gd结构体的一些变量进行初始化,方便之后的relocation

ENV_IS_EMBEDDEDCONFIG_NAND_ENV_DST都没有被定义。

注意注释:大意是当ubootnand启动时,环境变量有两种存在方式embedded or attached,显然这里不是embeddedENV_IS_EMBEDDED没有被定义),属于attached的形式。

什么是embeddedattached呢?有待研究......

gd->env_addr指向的是环境变量的首地址。

gd->env_valid被赋值为1,在relocate的时候会用到。

来看一下default_environment:

/commom/env_common.c

uchar default_environment[] = {
#ifdef	CONFIG_BOOTARGS
"bootargs="	CONFIG_BOOTARGS	 "\0"
#endif
#ifdef	CONFIG_BOOTCOMMAND
"bootcmd="	CONFIG_BOOTCOMMAND	 "\0"
#endif
#ifdef	CONFIG_RAMBOOTCOMMAND
"ramboot="	CONFIG_RAMBOOTCOMMAND	 "\0"
#endif
#ifdef	CONFIG_NFSBOOTCOMMAND
"nfsboot="	CONFIG_NFSBOOTCOMMAND	 "\0"
#endif
#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
"bootdelay="	MK_STR(CONFIG_BOOTDELAY)	"\0"
#endif
#if defined(CONFIG_BAUDRATE) && (CONFIG_BAUDRATE >= 0)
"baudrate="	MK_STR(CONFIG_BAUDRATE)	 "\0"
#endif
#ifdef	CONFIG_LOADS_ECHO
"loads_echo="	MK_STR(CONFIG_LOADS_ECHO)	"\0"
#endif
#ifdef	CONFIG_ETHADDR
"ethaddr="	MK_STR(CONFIG_ETHADDR)	 "\0"
#endif
#ifdef	CONFIG_ETH1ADDR
"eth1addr="	MK_STR(CONFIG_ETH1ADDR)	 "\0"
#endif
#ifdef	CONFIG_ETH2ADDR
"eth2addr="	MK_STR(CONFIG_ETH2ADDR)	 "\0"
#endif
#ifdef	CONFIG_ETH3ADDR
"eth3addr="	MK_STR(CONFIG_ETH3ADDR)	 "\0"
#endif
#ifdef	CONFIG_ETH4ADDR
"eth4addr="	MK_STR(CONFIG_ETH4ADDR)	 "\0"
#endif
#ifdef	CONFIG_ETH5ADDR
"eth5addr="	MK_STR(CONFIG_ETH5ADDR)	 "\0"
#endif
#ifdef	CONFIG_IPADDR
"ipaddr="	MK_STR(CONFIG_IPADDR)	 "\0"
#endif
#ifdef	CONFIG_SERVERIP
"serverip="	MK_STR(CONFIG_SERVERIP)	 "\0"
#endif
#ifdef	CONFIG_SYS_AUTOLOAD
"autoload="	CONFIG_SYS_AUTOLOAD	 "\0"
#endif
#ifdef	CONFIG_PREBOOT
"preboot="	CONFIG_PREBOOT	 "\0"
#endif
#ifdef	CONFIG_ROOTPATH
"rootpath="	MK_STR(CONFIG_ROOTPATH)	 "\0"
#endif
#ifdef	CONFIG_GATEWAYIP
"gatewayip="	MK_STR(CONFIG_GATEWAYIP)	"\0"
#endif
#ifdef	CONFIG_NETMASK
"netmask="	MK_STR(CONFIG_NETMASK)	 "\0"
#endif
#ifdef	CONFIG_HOSTNAME
"hostname="	MK_STR(CONFIG_HOSTNAME)	 "\0"
#endif
#ifdef	CONFIG_BOOTFILE
"bootfile="	MK_STR(CONFIG_BOOTFILE)	 "\0"
#endif
#ifdef	CONFIG_LOADADDR
"loadaddr="	MK_STR(CONFIG_LOADADDR)	 "\0"
#endif
#ifdef  CONFIG_CLOCKS_IN_MHZ
"clocks_in_mhz=1\0"
#endif
#if defined(CONFIG_PCI_BOOTDELAY) && (CONFIG_PCI_BOOTDELAY > 0)
"pcidelay="	MK_STR(CONFIG_PCI_BOOTDELAY)	"\0"
#endif
#ifdef  CONFIG_EXTRA_ENV_SETTINGS
CONFIG_EXTRA_ENV_SETTINGS
#endif
"\0"
};

default_environment结构体中保存的是默认环境变量,每个环境变量之间以\0隔开,整个结构体以\0\0结尾。



init_baudrate

/lib_arm/board.c文件中:
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);
}

在环境变量中查找baudrate字符串,看看有没有设置正确的波特率,有的话就设置上。

 

serial_init

drivers/serial/serial_s3c 24x0.c文件中:

#if !defined(CONFIG_SERIAL_MULTI)
/* Initialise the serial port. The settings are always 8 data bits, no parity,
 * 1 stop bit, no start bits.
 */
int serial_init(void)
{
return serial_init_dev(UART_NR);
}
#endif

同样在这个文件中还有:

/* Initialise the serial port. The settings are always 8 data bits, no parity,
 * 1 stop bit, no start bits.
 */
static int serial_init_dev(const int dev_index)
{
struct s3c24x0_uart *uart = s3c24x0_get_base_uart(dev_index);
 
#ifdef CONFIG_HWFLOW
hwflow = 0;	/* turned off by default */
#endif
 
/* FIFO enable, Tx/Rx FIFO clear */
writel(0x07, &uart->UFCON);
writel(0x0, &uart->UMCON);
 
/* Normal,No parity,1 stop,8 bit */
writel(0x3, &uart->ULCON);
/*
 * tx=level,rx=edge,disable timeout int.,enable rx error int.,
 * normal,interrupt or polling
 */
writel(0x245, &uart->UCON);
 
#ifdef CONFIG_HWFLOW
writel(0x1, &uart->UMCON);	/* RTS up */
#endif
 
/* FIXME: This is sooooooooooooooooooo ugly */
#if defined(CONFIG_ARCH_GTA02_v1) || defined(CONFIG_ARCH_GTA02_v2)
/* we need auto hw flow control on the gsm and gps port */
if (dev_index == 0 || dev_index == 1)
writel(0x10, &uart->UMCON);
#endif
_serial_setbrg(dev_index);
 
return (0);
}

下面分析代码:

serial_init_dev(UART_NR);中的UART_NR是什么?

找到:

#ifdef CONFIG_SERIAL1
#define UART_NR	S3C24X0_UART0

/include/s3c2410.h有:

enum s3c24x0_uarts_nr {
S3C24X0_UART0,
S3C24X0_UART1,
S3C24X0_UART2
};

枚举类型的第一个成员的默认值是0,所以这里UART_NR的值应该是0,表示对标号为0的串口进行操作。

 

下面看serial_init_dev,他的注释说明了这个函数是用于串口的初始化,数据位为8位,没有奇偶校验(parity

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值