本文借hello包的壳,对L4Re驱动开发的流程和步骤进行总结(有不妥的地方,欢迎指正)。
1.首先是驱动主体
官网可下载zynq102的trm手册“ug1085-zynq-ultrascale-trm.pdf”。
从Ch. 10: System Addresses章节可以找到TTC0定时器的基地址:0xff110000
可以调用l4io_request_iomem函数将TTC0寄存器的基地址映射出来。函数原型如下:
long l4io_request_iomem(l4_addr_t phys, unsigned long size, int flags, l4_addr_t *virt) |
TTC的寄存器
Name |
Description |
Clock_Control_{1:3} |
Clock control register. |
Counter_Control_{1:3} |
Operational mode and reset. |
Counter_Value_{1:3} |
Current counter value. |
Interval_Counter_{1:3} |
Interval value. |
Match_{1:3}_Counter_{1:3} |
Match value. |
Interrupt_Register_{1:3} |
Counter 1 to 3 interval, match, overflow, and event interrupts. |
Interrupt_Enable_{1:3} |
ANDed with corresponding interrupt. |
Event_Control_Timer_{1:3} |
Enable, pulse, and overflow. |
Event_Register_{1:3} |
APB interface clock cycle count for event. |
寄存器地址偏移及位的具体定义可参考ug1087-zynq-ultrascale-registers;根据需要的功能,如计数或定时,进行不同的初始化。详见ug1085文档中编程示例:TTC Programming Examples
2. 然后对所需的硬件资源及权限进行配置
驱动程序开发好后,就需要配置硬件资源及进行权限申请。这里涉及到两种文件:cfg和io文件。
2.1 首先看cfg文件
ttc.cfg
local L4 = require("L4"); local l = L4.default_loader; local ttc_bus = l:new_channel(); l:start({ caps = { ttc = ttc_bus:svr(), icu = L4.Env.icu, zinit = L4.cast(L4.Proto.Factory, L4.Env.zinit):create(L4.Proto.Zinit), }, }, "rom/io rom/ttc_hw.io rom/ttc.io"); ttc_test = l:start({ caps = { vbus = ttc_bus, }, }, "rom/tsc_test"); |
可参照上面的cfg文件来写。其中,
L4.default_loader就是默认的加载模块——moe;
l:new_channel()则是创建一个IPC gate;
而如下的形式,则是进行能力权限的申请:
local caps = {
name = some_capability
}
l:start的第二个参数“rom/io rom/ttc_hw.io rom/ttc.io”,则是调用io服务进行硬件资源的配置,rom/ttc_hw.io 和rom/ttc.io是其两个参数。
2.2 下面看看这两个io文件
ttc_hw.io
-- vi:ft=lua local Res = Io.Res local Hw = Io.Hw Io.hw_add_devices(function() TTC = Hw.Device(function() Property.hid = "arm-ttc"; compatible = {"arm,ttc"}; Resource.regs = Res.mmio(0xff110000, 0xff11ffff); end); CLK_SOURCE = Hw.Device(function() Property.hid = "arm-clk_source"; compatible = {"arm,clk_source"}; Resource.regs = Res.mmio(0xff180000, 0xff18ffff); end); end) |
ttc.io
-- vi:ft=lua -- configuration file for io local hw = Io.system_bus() Io.add_vbus("ttc", Io.Vi.System_bus { TTC = wrap(hw:match("arm,ttc")); CLK_SOURCE = wrap(hw:match("arm,clk_source")); }) |
io文件也可参照着写,具体模块的含义可详见L4Re的io包源码。
ttc_hw.io中的Io.hw_add_devices函数添加硬件设备,其中加黑部分需要特别注意,下面ttc.io中Io.add_vbus函数增加总线时会“match”上面的“compatible ”。
Res.mmio配置需要用的寄存器地址,如果将TTC作为timer可能还需要中断号的配置,可使用“Resource.irq = Res.irq(中断号);”
3.最后是配置entry
由于本文借用hello包的壳,所以需要修改modules.list的hello-cfg entry如下
entry hello-cfg kernel fiasco -serial_esc roottask moe rom/ttc.cfg module ttc.cfg module ttc.io module ttc_hw.io module l4re module ned module ttc_test module io |