Chinaunix首页 | 论坛 | 博客
  • 博客访问: 3546478
  • 博文数量: 1805
  • 博客积分: 135
  • 博客等级: 入伍新兵
  • 技术积分: 3345
  • 用 户 组: 普通用户
  • 注册时间: 2010-03-19 20:01
文章分类

全部博文(1805)

文章存档

2017年(19)

2016年(80)

2015年(341)

2014年(438)

2013年(349)

2012年(332)

2011年(248)

分类: LINUX

2014-08-29 09:15:55

给和我之前一样对此过程很迷惑的人一些帮助:
---------------------------------------------------------------------------

近日在看,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(用以代表字母AARM 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:
  1. static struct amba_id pl08x_ids[] = {
  2. /* PL080 */
  3. {
  4. .id = 0x00041080,
  5. .mask = 0x000fffff,
  6. },
  7. /* PL081 */
  8. {
  9. .id = 0x00041081,
  10. .mask = 0x000fffff,
  11. },
  12. {0, 0},
  13. };
复制代码

其中的id,就分别对应了pl080和pl081的硬件寄存器中存储的id,
然后此id table赋值给了一个amba_driver型的结构体pl08x:
  1. static struct amba_driver pl08x_amba_driver = {
  2. .drv.name = "pl08xdmaapi",
  3. .id_table = pl08x_ids,
  4. .probe = pl08x_probe,
  5. };
复制代码

然后通用的做法,在init函数pl08x_init中,会去注册此amba driver:

  1. static int __init pl08x_init(void)
  2. {
  3. ...
  4. retval = amba_driver_register(&pl08x_amba_driver);
  5. ...
  6. }
复制代码

即调用\drivers\amba\bus.c 中的amba_driver_register:
  1. int amba_driver_register(struct amba_driver *drv)
  2. {
  3. drv->drv.bus = &amba_bustype;
  4. 。。。。
  5. return driver_register(&drv->drv);
  6. }
复制代码

上面这些也都是通用的函数和架构,去定义id table,注册驱动等等操作。
对此配套的,你在SOC的核心文件中,一般为core.c里面。还要去定义对应的amba device:
AMBA_DEVICE(dmacp, "dmacp", DMACP, &as353x_dma_configs);
然后此设备会挂到一个amba_devs的数组中:
  1. static struct amba_device *amba_devs[] __initdata = {
  2. &dmacp_device,
  3. ...
  4. };
复制代码

然后在你板子初始化函数中,会去注册此amba设备数组:
  1. void __init as353x_init(void)
  2. {
  3. ....
  4. for (i = 0; i < ARRAY_SIZE(amba_devs); i++) {
  5. struct amba_device *d = amba_devs[i];
  6. amba_device_register(d, &iomem_resource);
  7. }
  8. ......
  9. }
复制代码

即调用\drivers\amba\bus.c 中的amba_device_register,注册这些amba设备:

  1. int amba_device_register(struct amba_device *dev, struct resource *parent)
  2. {
  3. 。。。
  4. /* 分别读取对应的四个32位的寄存器,DMACPeriphID0-3,只保留其中有效的低8位,将它们组合成一个32位的值,就得到了Peri ID:0x00041080 */
  5.        for (pid = 0, i = 0; i < 4; i++)
  6.               pid |= (readl(tmp + 0xfe0 + 4 * i) & 255) << (i * 8);
  7. /* 分别读取对应的四个32位的寄存器,DMACPCellID0-3,只保留其中有效的低8位,将它们组合成一个32位的值,就得到了Cell ID:0xb105f00d */
  8.        for (cid = 0, i = 0; i < 4; i++)for (pid = 0, i = 0; i < 4; i++)
  9.               cid |= (readl(tmp + 0xff0 + 4 * i) & 255) << (i * 8);

  10. ......
  11.        /* 如果cell id相等,那说明是amba设备 */
  12.        if (cid == 0xb105f00d)
  13.               dev->periphid = pid;

  14.        if (!dev->periphid) {
  15.               ret = -ENODEV;
  16.               goto err_release;
  17.        }

  18.        ret = device_register(&dev->dev);
  19. 。。。。。。
  20. }
复制代码
上面代码中,通过读取硬件的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) |
给主人留下些什么吧!~~