我是靠谱客的博主 美丽雪碧,这篇文章主要介绍linux pl011串口简述,现在分享给大家,希望可以做个参考。

基于nanopi m2内核3.4.39

串口驱动编译选项

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

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

复制代码
1
2
< > 8250/16550 and compatible serial support
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
*** 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 /proc/tty/driver/可以看到所有串口驱动,相应的中断号,mmio,传输的数据字节

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
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看起

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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,两个结构的实例如下

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
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

复制代码
1
2
3
4
5
6
7
8
9
10
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函数中有下句

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

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

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

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

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
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 了

复制代码
1
2
3
4
5
6
struct bus_type amba_bustype = { ... .match = amba_match, ... };
复制代码
1
2
3
4
5
6
7
sequenceDiagram amba_driver->>amba_bus:amba_driver_register() amba_device->>amba_bus:amba_device_register() amba_device--amba_driver:通过ID amba_driver-->>amba_device:(dev->>periphid & table->>mask) == table->>id

最后

以上就是美丽雪碧最近收集整理的关于linux pl011串口简述的全部内容,更多相关linux内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(67)

评论列表共有 0 条评论

立即
投稿
返回
顶部