1、串口初始化函数调用关系
start.S
_start
reset
lowlevel_init
uart_asm_init
1.1、uart_asm_init汇编函数
#if defined(CONFIG_SERIAL1)
#define ELFIN_UART_CONSOLE_BASE (ELFIN_UART_BASE + ELFIN_UART0_OFFSET)
#elif defined(CONFIG_SERIAL2)
#define ELFIN_UART_CONSOLE_BASE (ELFIN_UART_BASE + ELFIN_UART1_OFFSET)
#elif defined(CONFIG_SERIAL3)
#define ELFIN_UART_CONSOLE_BASE (ELFIN_UART_BASE + ELFIN_UART2_OFFSET)
#elif defined(CONFIG_SERIAL4)
#define ELFIN_UART_CONSOLE_BASE (ELFIN_UART_BASE + ELFIN_UART3_OFFSET)
#else
#define ELFIN_UART_CONSOLE_BASE (ELFIN_UART_BASE + ELFIN_UART0_OFFSET)
#endif
uart_asm_init:
ldr r0, =ELFIN_GPIO_BASE
ldr r1, =0x22222222
str r1, [r0, #GPA0CON_OFFSET]
ldr r1, =0x2222
str r1, [r0, #GPA1CON_OFFSET]
ldr r0, =ELFIN_UART_CONSOLE_BASE
mov r1, #0x0
str r1, [r0, #UFCON_OFFSET]
str r1, [r0, #UMCON_OFFSET]
mov r1, #0x3
str r1, [r0, #ULCON_OFFSET]
ldr r1, =0x3c5
str r1, [r0, #UCON_OFFSET]
ldr r1, =UART_UBRDIV_VAL
str r1, [r0, #UBRDIV_OFFSET]
ldr r1, =UART_UDIVSLOT_VAL
str r1, [r0, #UDIVSLOT_OFFSET]
ldr r1, =0x4f4f4f4f
str r1, [r0, #UTXH_OFFSET] @'O'
mov pc, lr
2、将串口设备注册到设备链表
2.1、函数调用关系
start.S
start_armboot()
devices_init ()
drv_system_init ()
device_register(&dev)
2.2、全局变量devlist
devlist是一个链表节点,将来uboot中新增的设备都注册该链表;devlist是在devices_init()函数里初始化的。
2.3、设备结构体
typedef struct {
int flags;
int ext;
char name[16];
int (*start) (void);
int (*stop) (void);
void (*putc) (const char c);
void (*puts) (const char *s);
int (*tstc) (void);
int (*getc) (void);
void *priv;
} device_t;
这个结构体是用来描述一个输入输出设备的,putc、getc······指针将来要指向实际完成输入输出功能的函数,在构建设备结构体时会赋值。
2.4、drv_system_init函数
static void drv_system_init (void)
{
device_t dev;
memset (&dev, 0, sizeof (dev));
strcpy (dev.name, "serial");
dev.flags = DEV_FLAGS_OUTPUT | DEV_FLAGS_INPUT | DEV_FLAGS_SYSTEM;
dev.putc = serial_putc;
dev.puts = serial_puts;
dev.getc = serial_getc;
dev.tstc = serial_tstc;
device_register (&dev);
}
2.5、device_register()函数
int device_register (device_t * dev)
{
ListInsertItem (devlist, dev, LIST_END);
return 0;
}
将新的设备结构体注册到devlist链表中。
3、全局变量stdio_devices[]
3.1、函数调用关系
start.S
start_armboot()
console_init_f()
console_init_r()
ListGetPtrToItem (devlist, i)
console_setfile()
3.2、全局变量stdio_devices[]介绍
device_t *stdio_devices[] = { NULL, NULL, NULL };
是一个结构体数组,三个成员变量都是device_t结构体,对应stdin、stdout、stderr。
3.3、console_init_r()函数
int console_init_r (void)
{
device_t *inputdev = NULL, *outputdev = NULL;
int i, items = ListNumItems (devlist);
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;
}
}
if (outputdev != NULL) {
console_setfile (stdout, outputdev);
console_setfile (stderr, outputdev);
}
if (inputdev != NULL) {
console_setfile (stdin, inputdev);
}
gd->flags |= GD_FLG_DEVINIT;
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);
}
return (0);
}
3.4、console_setfile()函数
static int console_setfile (int file, device_t * dev)
{
int error = 0;
if (dev == NULL)
return -1;
switch (file) {
case stdin:
case stdout:
case stderr:
if (dev->start) {
error = dev->start ();
if (error < 0)
break;
}
stdio_devices[file] = dev;
switch (file) {
case stdin:
gd->jt[XF_getc] = dev->getc;
gd->jt[XF_tstc] = dev->tstc;
break;
case stdout:
gd->jt[XF_putc] = dev->putc;
gd->jt[XF_puts] = dev->puts;
gd->jt[XF_printf] = printf;
break;
}
break;
default:
error = -1;
}
return error;
}
初始化全局变量stdio_devices,stdin、stdout、stderr都有对应的设备结构体(一般三者都是指向同一个串口),调用printf()函数时会用到。
4、printf()函数用串口输出打印信息
参考博客:《uboot中printf( )函数实现分析》;
5、修改打印输出串口
#if defined(CONFIG_SERIAL1)
#define ELFIN_UART_CONSOLE_BASE (ELFIN_UART_BASE + ELFIN_UART0_OFFSET)
#elif defined(CONFIG_SERIAL2)
#define ELFIN_UART_CONSOLE_BASE (ELFIN_UART_BASE + ELFIN_UART1_OFFSET)
#elif defined(CONFIG_SERIAL3)
#define ELFIN_UART_CONSOLE_BASE (ELFIN_UART_BASE + ELFIN_UART2_OFFSET)
#elif defined(CONFIG_SERIAL4)
#define ELFIN_UART_CONSOLE_BASE (ELFIN_UART_BASE + ELFIN_UART3_OFFSET)
#else
#define ELFIN_UART_CONSOLE_BASE (ELFIN_UART_BASE + ELFIN_UART0_OFFSET)
#endif
#define CONFIG_SERIAL3 1
修改配置文件中的CONFIG_SERIALn[0:3]宏,比如定义CONFIG_SERIAL3就是代表使用串口2作输出。思路就是通过宏定义控制作为打印信息输出串口的寄存器组基地址。
|