最新消息:20190717 VPS服务器:Vultr新加坡,WordPress主题:大前端D8,统一介绍入口:关于

Linux AMBA设备驱动注册过程浅析

工作和技术 crifan 991浏览 0评论

近日在看,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总线和设备的软件实现逻辑

有了上面的解释,再来看代码里面的含义,就很清楚了:

在driversambali08x.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);

}

即调用driversambabus.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);
}
……
}

即调用driversambabus.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,表示没有此设备。

转载请注明:在路上 » Linux AMBA设备驱动注册过程浅析

发表我的评论
取消评论

表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
56 queries in 0.243 seconds, using 18.84MB memory