linux pl011串口简述

基于nanopi m2内核3.4.39

串口驱动编译选项

Created with Raphaël 2.1.0 linux Kernel Configuration make menuconfig device drivers character devices serial drivers

nanopi m2 4418中串口驱动的选项如下:

       < > 8250/16550 and compatible serial support                                         
            *** Non-8250 serial port support ***                                             
        < > ARM AMBA PL010 serial port support                                             
        <*> ARM AMBA PL011 serial port support                                              
        [*]   Support for console on AMBA serial port                                        
       < > MAX3100 support                                                                
        < > MAX3107 support                                                                
        < > Support for timberdale UART                                                    
        < > Altera JTAG UART support                                                       
        < > Altera UART support                                                            
        < > SPI protocol driver for Infineon 6x60 modem (EXPERIMENTAL)                  
        < > Xilinx PS UART support                                                         
        < > Nexell S3C SoC serial port support                                             
        [*]   Serial port 0                                                                
        [ ]     Use DMA                                                                    
        [*]   Serial port 1                                                                
        [ ]     Use DMA                                                                    
        [ ]   Serial port 2                                                                
        [*]   Serial port 3                                                                
        [*]   Serial port 4                                                                
        [ ]   Serial port 5                                                                
        [*] Set this to reduce resume time (PL011) 

使用ls /pro/tty/driver/可以看到所有串口驱动,相应的中断号,mmio,传输的数据字节

root@NanoPi2:~# ls /proc/tty/driver/
ttyAMA  usbserial
root@NanoPi2:~# cat /proc/tty/driver/ttyAMA 
serinfo:1.0 driver revision:
0: uart:PL011 rev3 mmio:0xC00A1000 irq:7 tx:2846 rx:133 RTS|DTR
1: uart:PL011 rev3 mmio:0xC00A0000 irq:6 tx:0 rx:0 DSR|CD
2: uart:PL011 rev3 mmio:0xC00A3000 irq:9 tx:0 rx:0
3: uart:PL011 rev3 mmio:0xC006D000 irq:10 tx:0 rx:0
root@NanoPi2:~# ls /dev/ttyAMA* -l
crw------- 1 root tty     204, 64 Sep 20 04:21 /dev/ttyAMA0
crw-rw---- 1 root dialout 204, 65 Sep 20 03:28 /dev/ttyAMA1
crw-rw---- 1 root dialout 204, 66 Sep 20 03:28 /dev/ttyAMA2
crw-rw---- 1 root dialout 204, 67 Sep 20 03:28 /dev/ttyAMA3

4418中一共有5个uart串口,使用了PL011驱动,nanopi中勾选了4 个,其中引出给我们用的有3个,ttyAMA0(调试口),ttyAMA2,ttyAMA3

驱动层次

tty层:uart_register_driver,uart_add_one_port
amba层:提供amba_driver,amba_device的注册实现,
UART层:主要涉及uart_driver,amba_driver,uart_port,uart_ops三个结构体,并调用tty层和amba层的两个函数完成amba_driver,uart_driver和uart_port端口的注册

ARM amba总线驱动

amba_device使用分析
Linux AMBA设备驱动注册过程浅析

内核中专门定义了一类amba_bustype、amba_device、amba_driver。具体定义在内核的/drivers/amba/bus.c中

源码查看

设备驱动文件位置
driver/tty/serial/amba-pl011.c
作用
向系统注册串口驱动

从module_init看起

static int __init pl011_init(void)
{
    int ret;
    ret = uart_register_driver(&amba_reg);
    if (ret == 0) {
        ret = amba_driver_register(&pl011_driver);
        if (ret)
            uart_unregister_driver(&amba_reg);
    }
    return ret;
}
static void __exit pl011_exit(void)
{
    amba_driver_unregister(&pl011_driver);
    uart_unregister_driver(&amba_reg);
}

注册了一个uart_driver和一个amba_driver,两个结构的实例如下

static struct uart_driver amba_reg = {
    .owner          = THIS_MODULE,
    .driver_name        = "ttyAMA",/* /proc/tty/sesial/ttyAMA */
    .dev_name       = "ttyAMA",   /* /dev/ttyAMA */
    .major          = SERIAL_AMBA_MAJOR,  /* /dev/ttyAMAn的节点信息 */
    .minor          = SERIAL_AMBA_MINOR,
    .nr         = UART_NR,
    .cons           = AMBA_CONSOLE,
};
//----------------
static struct amba_id pl011_ids[] = {
    {
        .id = 0x00041011,
        .mask   = 0x000fffff,
        .data   = &vendor_arm,
    },
    {
        .id = 0x00380802,
        .mask   = 0x00ffffff,
        .data   = &vendor_st,
    },
    { 0, 0 },
};
MODULE_DEVICE_TABLE(amba, pl011_ids);
static struct amba_driver pl011_driver = {
    .drv = {
        .name   = "uart-pl011",
    },
    .id_table   = pl011_ids,/*用来匹配设备的,*/
    .probe      = pl011_probe,/*在里面实现了uart_port的注册和uart_ops的赋值*/
    .remove     = pl011_remove,
};

当有设备与此驱动匹配时,就调用pl011_probe函数了,主要就是填充uart_add_one_port,并实现uart_ops

static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
{
    struct uart_amba_port *uap;
    ...
    uap->port.ops = &amba_pl011_pops;
    ...
    ret = uart_add_one_port(&amba_reg, &uap->port);
    ...
}

先说下匹配过程,在注册驱动时amba_driver_register函数中有下句

drv->drv.bus = &amba_bustype;//表明将该驱动注册到amba_bus总线上去,由amba_bus中的match方法匹配

同样的在注册设备时,amba_device_register–>amba_device_initialize中

dev->dev.bus = &amba_bustype;//同样将设备注册到amba_bus总线上去,由amba_bus中的match方法匹配

而且,在amba_device_register–>amba_device_add中会如果没设定会自行计算出AMBA设备的ID号


int amba_device_add(struct amba_device *dev, struct resource *parent)
{
    ...
    /* Hard-coded primecell ID instead of plug-n-play */
    if (dev->periphid != 0)/*如果在添加设备时自行加了id就不再读取硬件上的ID了*/
        goto skip_probe;
    ...
    ret = amba_get_enable_pclk(dev);
    if (ret == 0) {
        u32 pid, cid;
        /*
         * Read pid and cid based on size of resource
         * they are located at end of region 在芯片资源的末区域读取ID信息
         */
        for (pid = 0, i = 0; i < 4; i++)
            pid |= (readl(tmp + size - 0x20 + 4 * i) & 255) <<
                (i * 8);
        for (cid = 0, i = 0; i < 4; i++)
            cid |= (readl(tmp + size - 0x10 + 4 * i) & 255) <<
                (i * 8);

        amba_put_disable_pclk(dev);

        if (cid == AMBA_CID)
            dev->periphid = pid;
        if (!dev->periphid)
            ret = -ENODEV;
    }
    ...
}

那么最后就是由amba_bus总线中的match来匹配驱动和设备了。如下,table就是驱动中的amba_id 了

struct bus_type amba_bustype = {
    ...
    .match      = amba_match,
    ...
};
Created with Raphaël 2.1.0 amba_driver amba_driver amba_bus amba_bus amba_device amba_device amba_driver_register() amba_device_register() 通过ID (dev->periphid & table->mask) == table->id

你可能感兴趣的:(linux)