uboot串口初始化
2016-01-15 22:46
246 查看
uboot下的串口初始化分多个步骤完成,在uboot初始化序列init_sequence[]中有三个串口相关的初始化函数。init_baudrate是用来设置串口的波特率,它首先会去uboot的环境变量里面找波特率的定义,如果找到就赋值给全局变量中的baudrate,如果环境变量中没有定义,则使用一个默认的配置值。serial_init跟具体的平台相关,以marvell平台为例,该函数定义在mv_serial.c中。该函数首先根据波特率计算出clock_divisor的值,然后调用mvUartInit()对串口硬件进行初始化。在mvUartInit中就是直接把初始的参数写到串口的寄存器中,从而完成硬件的初始化工作。console_init_f是console初始化的第一阶段,就是设置了全局变量中的have_console变量。
init_fnc_t *init_sequence[] = {
<span style="white-space:pre"> </span>……
init_baudrate, /* initialze baudrate settings */
serial_init, /* serial communications setup */
console_init_f, /* stage 1 init of console */
<span style="white-space:pre"> </span>……
};
第四个初始化阶段在devices_init()中,devices_init()完成的工作就相当于uboot下的设备管理机制,把各类设备按照特定的格式添加到一个设备链表devlist中去。对串口设备的初始化工作在drv_system_init()中,该函数首先把设备名字设为serial,并把设备的flags设为DEV_FLAGS_OUTPUT | DEV_FLAGS_INPUT | DEV_FLAGS_SYSTEM,然后为devict_t中对应的操作函数进行赋值操作,主要实现输入输出的功能,具体的实现函数也跟平台相关。比如dev.putc被定义为serial_putc(),在marvell的平台中该函数定义在mv_serial.c中,它直接调用mvUartPutc()来实现输出操作,在mvUartPutc()中直接把要输出的值赋给输出寄存器。初始化好设备描述符后,调用device_register()把设备加到全局的设备链表中。
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;
#ifdef CONFIG_SERIAL_SOFTWARE_FIFO
dev.putc = serial_buffered_putc;
dev.puts = serial_buffered_puts;
dev.getc = serial_buffered_getc;
dev.tstc = serial_buffered_tstc;
#else
dev.putc = serial_putc;
dev.puts = serial_puts;
dev.getc = serial_getc;
dev.tstc = serial_tstc;
#endif
device_register (&dev);
#ifdef CFG_DEVICE_NULLDEV
memset (&dev, 0, sizeof (dev));
strcpy (dev.name, "nulldev");
dev.flags = DEV_FLAGS_OUTPUT | DEV_FLAGS_INPUT | DEV_FLAGS_SYSTEM;
dev.putc = nulldev_putc;
dev.puts = nulldev_puts;
dev.getc = nulldev_input;
dev.tstc = nulldev_input;
device_register (&dev);
#endif
}
最后一个初始化阶段在console_init_r()中,在该函数中,首先定义两个变量inputdev和outputdev,并初始化为NULL,然后会去遍历全局的设备列表,如果有某个设备的flags为DEV_FLAGS_INPUT,则把该设备赋值给inputdev,同样,如果有某个设备的flags为DEV_FLAGS_OUTPUT,则把它赋值给outputdev。如果有找到这样的inputdev和outputdev,则调用console_setfile()来设置标准输入,标准输入以及错误输出的文件描述符。在console_setfile()中,主要是对stdio_devices[]数组进行赋值操作,该数组有三个元素,对应输入,输出以及错误文件描述符,所以就是把具体的设备跟这三个文件描述绑定在一起。
int console_init_r (void)
{
DECLARE_GLOBAL_DATA_PTR;
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 have
a bmp to display */
if (getenv("splashimage") != NULL)
outputdev = search_device (DEV_FLAGS_OUTPUT, "nulldev");
#endif
#ifdef CONFIG_SILENT_CONSOLE
/* Suppress all output if "silent" mode requested */
if (gd->flags & GD_FLG_SILENT)
outputdev = search_device (DEV_FLAGS_OUTPUT, "nulldev");
#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 */
/* Setting environment variables */
for (i = 0; i < 3; i++) {
setenv (stdio_names[i], stdio_devices[i]->name);
}
#if 0
/* If nothing usable installed, use only the initial console */
if ((stdio_devices[stdin] == NULL) && (stdio_devices[stdout] == NULL))
return (0);
#endif
return (0);
}
前面三个阶段主要是对硬件的初始化,后面两个阶段主要是实现串口操作功能的初始化,因为设置好标准输入输出后,我们就可以从串口看到uboot的加载和调试信息。看一下uboot下的printf()函数,该函数先调用vsprintf()对输出内容进行格式化处理,然后调用puts()输出内容。在puts()中,根据GD_FLG_DEVINIT标记进行不同的处理,这个标记在console_init_r()有被设置,所以调用fputs()函数,而fputs()就是直接调用stdio_devices[]数组中的标准输出设备来输出内容,这个设备就是在console_init_r()中绑定的。
void printf (const char *fmt, ...)
{
va_list args;
uint i;
char printbuffer[CFG_PBSIZE];
va_start (args, fmt);
/* For this to work, printbuffer must be larger than
* anything we ever want to print.
*/
i = vsprintf (printbuffer, fmt, args);
va_end (args);
/* Print the string */
puts (printbuffer);
}
init_fnc_t *init_sequence[] = {
<span style="white-space:pre"> </span>……
init_baudrate, /* initialze baudrate settings */
serial_init, /* serial communications setup */
console_init_f, /* stage 1 init of console */
<span style="white-space:pre"> </span>……
};
static int init_baudrate (void) { DECLARE_GLOBAL_DATA_PTR; uchar 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); }
MV_VOID mvUartInit(MV_U32 port, MV_U32 baudDivisor, MV_UART_PORT* base) { volatile MV_UART_PORT *pUartPort; #if defined(MV_UART_OVER_PEX_WA) || defined(MV_UART_OVER_PCI_WA) uartBase[port] = pUartPort = (volatile MV_UART_PORT *)(base); return; #else uartBase[port] = pUartPort = (volatile MV_UART_PORT *)base; pUartPort->ier = 0x00; pUartPort->lcr = LCR_DIVL_EN; /* Access baud rate */ pUartPort->dll = baudDivisor & 0xff; /* 9600 baud */ pUartPort->dlm = (baudDivisor >> 8) & 0xff; pUartPort->lcr = LCR_8N1; /* 8 data, 1 stop, no parity */ /* Clear & enable FIFOs */ pUartPort->fcr = FCR_FIFO_EN | FCR_RXSR | FCR_TXSR; return; #endif }
int console_init_f (void) { DECLARE_GLOBAL_DATA_PTR; gd->have_console = 1; #ifdef CONFIG_SILENT_CONSOLE if (getenv("silent") != NULL) gd->flags |= GD_FLG_SILENT; #endif return (0); }
第四个初始化阶段在devices_init()中,devices_init()完成的工作就相当于uboot下的设备管理机制,把各类设备按照特定的格式添加到一个设备链表devlist中去。对串口设备的初始化工作在drv_system_init()中,该函数首先把设备名字设为serial,并把设备的flags设为DEV_FLAGS_OUTPUT | DEV_FLAGS_INPUT | DEV_FLAGS_SYSTEM,然后为devict_t中对应的操作函数进行赋值操作,主要实现输入输出的功能,具体的实现函数也跟平台相关。比如dev.putc被定义为serial_putc(),在marvell的平台中该函数定义在mv_serial.c中,它直接调用mvUartPutc()来实现输出操作,在mvUartPutc()中直接把要输出的值赋给输出寄存器。初始化好设备描述符后,调用device_register()把设备加到全局的设备链表中。
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;
#ifdef CONFIG_SERIAL_SOFTWARE_FIFO
dev.putc = serial_buffered_putc;
dev.puts = serial_buffered_puts;
dev.getc = serial_buffered_getc;
dev.tstc = serial_buffered_tstc;
#else
dev.putc = serial_putc;
dev.puts = serial_puts;
dev.getc = serial_getc;
dev.tstc = serial_tstc;
#endif
device_register (&dev);
#ifdef CFG_DEVICE_NULLDEV
memset (&dev, 0, sizeof (dev));
strcpy (dev.name, "nulldev");
dev.flags = DEV_FLAGS_OUTPUT | DEV_FLAGS_INPUT | DEV_FLAGS_SYSTEM;
dev.putc = nulldev_putc;
dev.puts = nulldev_puts;
dev.getc = nulldev_input;
dev.tstc = nulldev_input;
device_register (&dev);
#endif
}
serial_putc(const char c) { #if defined(CONFIG_MV_SMP) || (defined(MV78XX0) && defined(MV78200)) if (c == '\n') mvUartPutc((whoAmI())%2, '\r'); mvUartPutc((whoAmI())%2, c); #else if (c == '\n') mvUartPutc(CFG_DUART_CHAN, '\r'); mvUartPutc(CFG_DUART_CHAN, c); #endif }
MV_VOID mvUartPutc(MV_U32 port, MV_U8 c) { volatile MV_UART_PORT *pUartPort = uartBase[port]; while ((pUartPort->lsr & LSR_THRE) == 0) ; pUartPort->thr = c; return; }
最后一个初始化阶段在console_init_r()中,在该函数中,首先定义两个变量inputdev和outputdev,并初始化为NULL,然后会去遍历全局的设备列表,如果有某个设备的flags为DEV_FLAGS_INPUT,则把该设备赋值给inputdev,同样,如果有某个设备的flags为DEV_FLAGS_OUTPUT,则把它赋值给outputdev。如果有找到这样的inputdev和outputdev,则调用console_setfile()来设置标准输入,标准输入以及错误输出的文件描述符。在console_setfile()中,主要是对stdio_devices[]数组进行赋值操作,该数组有三个元素,对应输入,输出以及错误文件描述符,所以就是把具体的设备跟这三个文件描述绑定在一起。
int console_init_r (void)
{
DECLARE_GLOBAL_DATA_PTR;
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 have
a bmp to display */
if (getenv("splashimage") != NULL)
outputdev = search_device (DEV_FLAGS_OUTPUT, "nulldev");
#endif
#ifdef CONFIG_SILENT_CONSOLE
/* Suppress all output if "silent" mode requested */
if (gd->flags & GD_FLG_SILENT)
outputdev = search_device (DEV_FLAGS_OUTPUT, "nulldev");
#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 */
/* Setting environment variables */
for (i = 0; i < 3; i++) {
setenv (stdio_names[i], stdio_devices[i]->name);
}
#if 0
/* If nothing usable installed, use only the initial console */
if ((stdio_devices[stdin] == NULL) && (stdio_devices[stdout] == NULL))
return (0);
#endif
return (0);
}
static int console_setfile (int file, device_t * dev) { DECLARE_GLOBAL_DATA_PTR; int error = 0; if (dev == NULL) return -1; switch (file) { case stdin: case stdout: case stderr: /* Start new device */ if (dev->start) { error = dev->start (); /* If it's not started dont use it */ if (error < 0) break; } /* Assign the new device (leaving the existing one started) */ stdio_devices[file] = dev; /* * Update monitor functions * (to use the console stuff by other applications) */ 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: /* Invalid file ID */ error = -1; } return error; }
前面三个阶段主要是对硬件的初始化,后面两个阶段主要是实现串口操作功能的初始化,因为设置好标准输入输出后,我们就可以从串口看到uboot的加载和调试信息。看一下uboot下的printf()函数,该函数先调用vsprintf()对输出内容进行格式化处理,然后调用puts()输出内容。在puts()中,根据GD_FLG_DEVINIT标记进行不同的处理,这个标记在console_init_r()有被设置,所以调用fputs()函数,而fputs()就是直接调用stdio_devices[]数组中的标准输出设备来输出内容,这个设备就是在console_init_r()中绑定的。
void printf (const char *fmt, ...)
{
va_list args;
uint i;
char printbuffer[CFG_PBSIZE];
va_start (args, fmt);
/* For this to work, printbuffer must be larger than
* anything we ever want to print.
*/
i = vsprintf (printbuffer, fmt, args);
va_end (args);
/* Print the string */
puts (printbuffer);
}
void puts (const char *s) { DECLARE_GLOBAL_DATA_PTR; #ifdef CONFIG_SILENT_CONSOLE if (gd->flags & GD_FLG_SILENT) return; #endif if (gd->flags & GD_FLG_DEVINIT) { /* Send to the standard output */ fputs (stdout, s); } else { /* Send directly to the handler */ serial_puts (s); } }
void fputs (int file, const char *s) { if (file < MAX_FILES) stdio_devices[file]->puts (s); }
相关文章推荐
- ie插件的简单总结 --- 发文于2013-12-13
- python解析XML
- 类
- Linux学习之XShell与虚拟机的连接
- MyBatis动态SQL完整版
- 建立学习型组织 - 解决了我几年的困惑
- 按位与、或、异或等运算方法
- chrome代码总结 --- 发文于2013-12-11
- 字符串:格式化
- 重拾编程之路--86. Partition List
- Visual Studio 2015 使用 libcurl
- segv & mini coredump
- JAVA系列(2)-JVM
- 机器学习基石第四次作业代码
- ZOJ 1679
- erlang开发工具之intellij idea基本使用
- wfp网络过滤框架总结(一)-主要翻译msdn ---发文于2013-11-24
- [乡土民间故事_徐苟三传奇]第二回_巧答言长工骂财主
- 学习Java技术Eclipse版本的选择
- 浅谈MySQL数据库(一)