现在的位置: 首页 > 综合 > 正文

u-boot串口初始化全过程

2013年10月02日 ⁄ 综合 ⁄ 共 5742字 ⁄ 字号 评论关闭

s3c2440 u-boot-1.1.6

串口初始化代码都在/lib_arm/board.c中的start_armboot被调用的。大致流程如下:

   

一、波特率初始化

init_baudrate

在/lib_arm/board.c/start_armboot函数被调用

/lib_arm/board.c/
init_fnc_t *init_sequence[] = {
                cpu_init ,                   /* basic cpu dependent setup */
                board_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
                dram_init,                /* configure available RAM banks */
                display_dram_config,
                NULL,
};
/lib_arm/board.c/start_armboot
for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr)//调用初始化函数,包括串口相关的函数
 {
        if ((*init_fnc_ptr)() != 0)
             {hang ();}
}
/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));//从环境变量中获取波特率值,有这个环境变量的话就使用它,没有就使用CONFIG_BAUDRATE,它一般被定义                                                              在/include/configs/smdk2410.h
    gd->bd->bi_baudrate = gd->baudrate = (i > 0)? (int) simple_strtoul (tmp, NULL, 10): CONFIG_BAUDRATE;
    return (0);
}

二、串口寄存器初始化serial_init

/cpu/arm920t/s3c24x0/serial.c
int serial_init (void)
{
      serial_setbrg ();
      printf("serial_setbrg\n");
      return (0);
}
void serial_setbrg (void)
{
      S3C24X0_UART * const uart = S3C24X0_GetBase_UART(UART_NR);//获得s3c24x0串口寄存器基地址
      int i;
      unsigned int reg = 0;
      reg = get_PCLK() / (16 * gd->baudrate) - 1;//设置波特率寄存器值
      uart->UFCON = 0x07;//设置fifo
      uart->UMCON = 0x0;
     /* Normal,No parity,1 stop,8 bit */
      uart->ULCON = 0x3;//8位数据位1位停止位,无奇偶校验
                /*
                 * tx=level,rx=edge,disable timeout int.,enable rx error int.,
                 * normal,interrupt or polling
                 */
        uart->UCON = 0x245;
        uart->UBRDIV = reg;
#ifdef CONFIG_HWFLOW
        uart->UMCON = 0x1; //硬件流控
#endif
       for (i = 0; i < 100; i++);
}
该文件下还定义了很多对串口的基础操作。
serial_putc;串口字节发送
serial_puts;串口字符串发送
serial_getc;串口读取字节
serial_tstc;
这些函数的函数指针将在后面的device_init中被注册到系统中其他高级结构中去。

三、console初始化第一阶段

/common/console.c
int console_init_f (void)
{
   gd->have_console = 1;
   #ifdef CONFIG_SILENT_CONSOLE
          if (getenv("silent") != NULL)
             gd->flags |= GD_FLG_SILENT;
   #endif
   return (0);
}

四、devices_init设备注册

/common/devices.c
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);//注册i2c设备
#endif
#ifdef CONFIG_LCD
     drv_lcd_init ();//初始化LCD设备并祖册到设备列表中
#endif
#if defined(CONFIG_VIDEO) || defined(CONFIG_CFB_CONSOLE)
     drv_video_init ();//源码中未定义
#endif
#ifdef CONFIG_KEYBOARD
     drv_keyboard_init ();//源码中未定义
#endif
#ifdef CONFIG_LOGBUFFER
     drv_logbuff_init ();
#endif
     drv_system_init ();//这里面其实就已经注册了一个串口设备到设备列表中
#ifdef CONFIG_SERIAL_MULTI
     serial_devices_init ();//串口初始化
#endif
#ifdef CONFIG_USB_TTY
     drv_usbtty_init ();//源码中未定义
#endif
#ifdef CONFIG_NETCONSOLE
     drv_nc_init ();
#endif
     return (0);
}

/common/devices.c
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;//这些函数就是在/cpu/arm920t/s3c24x0/serial.c中定义的
  dev.puts = serial_puts;                //这些函数就是在/cpu/arm920t/s3c24x0/serial.c中定义的
  dev.getc = serial_getc;                //这些函数就是在/cpu/arm920t/s3c24x0/serial.c中定义的
  dev.tstc = serial_tstc;                //这些函数就是在/cpu/arm920t/s3c24x0/serial.c中定义的
#endif
  device_register (&dev);//将该设备加入到                devlist列表
#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
}

五、设置标准输入输出

/common/console.c
int console_init_r (void)
{
  device_t *inputdev = NULL, *outputdev = NULL;
  int i, items = ListNumItems (devlist);
#ifdef CONFIG_SPLASH_SCREEN                                     
  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++)//遍历设备列表devlist中的所有设备
 {
          device_t *dev = ListGetPtrToItem (devlist, i);//获得设备列表第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;	
if (0){						
#ifndef CFG_CONSOLE_INFO_QUIET
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 */
}
这就是很经典的uoot移植好后在串口打印的信息的源码:
In:serial
Out:serial
Err:serial

for (i = 0; i < 3; i++)
{
    setenv (stdio_names[i], stdio_devices[i]->name);//设置环境变量
}
    return (0);
}

参考文献

u-boot串口初始化详解 

U-Boot的设备管理框架

sourceInsight浏览源码利器



抱歉!评论已关闭.