给和我之前一样对此过程很迷惑的人一些帮助:
---------------------------------------------------------------------------
近日在看,ARM的DMAC,PL080的驱动,想看看其实如何注册到amba bus上的。终于看懂了具体含义。下面以属于AMBA总线的arm的dma控制器PL080为例来说明:
1. amba相关硬件知识
首先,作为arm的,支持amba总线的硬件,都会有对应的硬件寄存器,用来
存储你的芯片id信息,包括Cell ID和Peri ID,Cell ID即你属于什么总线,Peri ID即表示你自己是什么设备。
dma控制器PL080,对应的datasheet中可以看到,也有对应的寄存器:
(PL080的基地址叫做base,具体的是多少,根据你所用的SOC决定,我此处的是AS3536,DMACP_BASE是0x00a10000。下面说的地址基于此base而言的offset):
(1)Peri
ID对应的是DMACPeriphID0-3,共四个32位的寄存器,offset是0xFE0-0xFEC,虽然四个都是32位的寄存器,但是目前只用
到低8位,四个8位的值组合在一起,可以看做是一个32位的值,表示对应的外围设备号,此处是0x00041080。LP080的设备号
0x00041080的具体位域含义为:
PartNumber[11:0] | 080(即常说的Part Number,即某个编号对应设备,知道此编号,就知道你说的哪个设备了) |
Designer ID[19:12] | 0x41(用以代表字母A,ARM Limited) |
Revision[23:20] | 0(版本号,从0开始编号) |
Configuration[31:24] | 0(配置选项) |
(2)Cell
ID对应的是DMACPCellID0-3,offset是0xFF0-0xFFC,同上,四个32位寄存器,实际存放了4个8位的值,组合在一起是32
位的值,此处是固定的值, 0xB105F00D,我的理解是,用此固定的值,表示了是AMBA总线型的设备,其内部应该有一系列的规则去定义这些值的。
2. amba总线和设备的软件实现逻辑
有了上面的解释,再来看代码里面的含义,就很清楚了:
在drivers\amba\li08x.c中,定义了一个id table:
- static struct amba_id pl08x_ids[] = {
- /* PL080 */
- {
- .id = 0x00041080,
- .mask = 0x000fffff,
- },
- /* PL081 */
- {
- .id = 0x00041081,
- .mask = 0x000fffff,
- },
- {0, 0},
- };
复制代码
其中的id,就分别对应了pl080和pl081的硬件寄存器中存储的id,
然后此id table赋值给了一个amba_driver型的结构体pl08x:
- static struct amba_driver pl08x_amba_driver = {
- .drv.name = "pl08xdmaapi",
- .id_table = pl08x_ids,
- .probe = pl08x_probe,
- };
复制代码
然后通用的做法,在init函数pl08x_init中,会去注册此amba driver:
-
- static int __init pl08x_init(void)
- {
- ...
- retval = amba_driver_register(&pl08x_amba_driver);
- ...
- }
复制代码
即调用\drivers\amba\bus.c 中的amba_driver_register:
- int amba_driver_register(struct amba_driver *drv)
- {
- drv->drv.bus = &amba_bustype;
- 。。。。
- return driver_register(&drv->drv);
- }
复制代码
上面这些也都是通用的函数和架构,去定义id table,注册驱动等等操作。
对此配套的,你在SOC的核心
文件中,一般为core.c里面。还要去定义对应的amba device:
AMBA_DEVICE(dmacp, "dmacp", DMACP, &as353x_dma_configs);
然后此设备会挂到一个amba_devs的数组中:
- static struct amba_device *amba_devs[] __initdata = {
- &dmacp_device,
- ...
- };
复制代码
然后在你板子初始化函数中,会去注册此amba设备数组:
- void __init as353x_init(void)
- {
- ....
- for (i = 0; i < ARRAY_SIZE(amba_devs); i++) {
- struct amba_device *d = amba_devs[i];
- amba_device_register(d, &iomem_resource);
- }
- ......
- }
复制代码
即调用\drivers\amba\bus.c 中的
amba_device_register,注册这些amba设备: -
- int amba_device_register(struct amba_device *dev, struct resource *parent)
- {
- 。。。
- /* 分别读取对应的四个32位的寄存器,DMACPeriphID0-3,只保留其中有效的低8位,将它们组合成一个32位的值,就得到了Peri ID:0x00041080 */
- for (pid = 0, i = 0; i < 4; i++)
- pid |= (readl(tmp + 0xfe0 + 4 * i) & 255) << (i * 8);
- /* 分别读取对应的四个32位的寄存器,DMACPCellID0-3,只保留其中有效的低8位,将它们组合成一个32位的值,就得到了Cell ID:0xb105f00d */
- for (cid = 0, i = 0; i < 4; i++)for (pid = 0, i = 0; i < 4; i++)
- cid |= (readl(tmp + 0xff0 + 4 * i) & 255) << (i * 8);
- ......
- /* 如果cell id相等,那说明是amba设备 */
- if (cid == 0xb105f00d)
- dev->periphid = pid;
- if (!dev->periphid) {
- ret = -ENODEV;
- goto err_release;
- }
- ret = device_register(&dev->dev);
- 。。。。。。
- }
复制代码 上面代码中,通过读取硬件的Cell ID和Peri ID,然后去判断,你的cell id,是否和amba bus的0xb105f00d相等:A.
如果相等,说明你是amba设备,然后就把硬件中读到的Peri ID保存起来,用于以后的,你的amba设备注册的时候,通过判断你的驱动中id
table中的那些id的值,是否和这个一样,如果一样,才说明你注册的驱动,能支持此设备,否则不支持。上面pl08x.c中的那些id
table,就是你驱动作者要从datasheet中找到并确保填写正确的,这样就和硬件匹配了。
B.如果不相等,那说明你是别的设备,此amba驱动不支持你,就返回-ENODEV,表示没有此设备。
转:
阅读(1007) | 评论(0) | 转发(0) |