X-015-KERNEL-ARM generic timer driver的移植
作者:wowo 发布于:2016-11-2 22:31 分类:X Project
1. 前言
本文将基于“Linux时间子系统之(十七):ARM generic timer驱动代码分析[1]”,以bubblegum-96平台为例,介绍ARM generic timer的移植步骤。
另外,我们在[2]中完成了ARM GIC驱动的移植,但还没有测试是否可用。刚好借助timer驱动,测试GIC是否可以正常工作,顺便理解Interrupt的使用方法。
2. Generic timer硬件说明
有关ARM generic timer的技术细节,可参考[1]。本文所使用的bubblegum-96平台,其SOC包含了4个Cortex A53的core,支持CP15 type的Generic timer。为了驱动它,我们需要如下两个信息:
1)System counter的输入频率。
2)Per-CPU的timer和GIC之间的接口(即这些Timer的中断源以及中断触发方式)。参考[2]中的介绍,对于支持virtualization extension的SOC,每个cpu有四个timer:Non-secure PL1 physical timer,Secure PL1 physical timer,Non-secure PL2 physical timer和virtual timer ,因此将会有四个中断源。
不过,和我们移植GIC驱动[2]时遇到的问题一样,我们找不到bubblegum-96平台有关的信息(大家在开发自己的平台时,应该没有这些困扰),只能从开源出来的代码中[5]反推,结论如下:
1)System counter的输入频率为24MHz,这一点可以从[4]中推测出来,因为bubblegum-96开发板的晶振是24MHz,一般system counter直接使用晶振为输入时钟。
2)4个Per-CPU timer的中断源分别是:Non-secure PL1 physical timer----PPI 13,Secure PL1 physical timer----PPI 14,Non-secure PL2 physical timer----PPI 11,virtual timer----PPI 10。 它们都是低电平触发的方式。
3. Generic timer移植
3.1 u-boot中的移植
记得我们在“X-013-UBOOT-使能autoboot功能”中调试u-boot的autoboot功能的时候,由于没有timer驱动,无法正确使用CONFIG_BOOTDELAY(因为无法计时)。既然本文要在kernel中移植generic timer,就顺便提一下,在u-boot中支持ARM generic timer的方法。
其实很简单,对于ARM64平台来说,支持generic timer只需要知道System counter的输入频率,并通过COUNTER_FREQUENCY宏定义告诉u-boot即可,如下(我们同时修改boot delay为5s,以验证timer功能):
/* include/configs/bubblegum.h */
@@ -74,7 +74,8 @@
#define CONFIG_CMD_BOOTI
-#define CONFIG_BOOTDELAY -2
+#define CONFIG_BOOTDELAY 5
#define CONFIG_BOOTCOMMAND "bootm 0x6400000"
+#define COUNTER_FREQUENCY (24000000) /* 24MHz */
#endif
修改完成后,编译u-boot并启动kernel,就可以看到自动boot之前的倒计时了,说明timer添加成功:
cd ~/work/xprj/build
make u-boot uImage
make spi-runmake kernel-run
3.2 kernel中的移植
在kernel中的移植也很简单,只需要修改dts文件,添加generic timer的节点,并提供第2章所描述的硬件信息即可:
/* ./arch/arm64/boot/dts/actions/s900-bubblegum.dts */
+#include
+
/ {
model = "Bubblegum-96 Development Board";
compatible = "actions,s900-bubblegum", "actions,s900";
+
+ timer {
+ compatible = "arm,armv8-timer";
+ interrupts =,
+,
+,
+;
+ clock-frequency = <24000000>;
+ };
};
说明如下:
1)为了使用GIC有关的信息,我们需要包含“include/dt-bindings/interrupt-controller/arm-gic.h”头文件。
2)timer节点的compatible字段为"arm,armv8-timer",表明我们是armv8 generic timer。
3)通过clock-frequency字段指定system counter的输入频率,这里为24000000(24MHz)。
4)interrupts字段指定了该设备所使用的中断源,可以是一个,也可以是多个,按照第2章的介绍,这里共有4个。参考[2]中的介绍,GIC的interrupt-cell为3,分别是:
第一个cell:PPI或SPI,此处均为PPI;
第二个cell,中断号,这里分别为13,14,11,10;
第三个cell,终端flag,这里需要包含一个GIC强制要求的----GIC_CPU_MASK_SIMPLE(4),另外就是中断触发类型,此处全是低电平触发。
4. 测试和验证
4.1 编译及debug
修改完dts文件,编译并运行kernel,GIC移植[4]时最后的kernel panic(如下)不见了:
clocksource_probe: no matching clocksources found
Kernel panic - not syncing: Unable to initialise architected timer.---[ end Kernel panic - not syncing: Unable to initialise architected timer.
取而代之的是:
NR_IRQS:64 nr_irqs:64 0
arch_timer: No interrupt available, giving up
sched_clock: 64 bits at 250 Hz, resolution 4000000ns, wraps every 9007199254000000ns
Calibrating delay loop (skipped), value calculated using timer frequency.. 48.00 BogoMIPS (lpj=96000)
pid_max: default: 4096 minimum: 301
Mount-cache hash table entries: 4096 (order: 3, 32768 bytes)
Mountpoint-cache hash table entries: 4096 (order: 3, 32768 bytes)
No CPU information found in DT
ASID allocator initialised with 65536 entries
Brought up 1 CPUs
SMP: Total of 1 processors activated.
CPU: All CPU(s) started at EL2
clocksource: jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 7645041785100000 ns
vdso: 2 pages (1 code @ ffffff8008185000, 1 data @ ffffff80081c4000)
DMA: preallocated 256 KiB pool for atomic allocations
workingset: timestamp_bits=60 max_order=19 bucket_order=0
Failed to find cpu0 device node
Unable to detect cache hierarchy from DT for CPU 0
Warning: unable to open an initial console.
Freeing unused kernel memory: 116K (ffffff80081a0000 - ffffff80081bd000)
This architecture does not have kernel memory protection.
Kernel panic - not syncing: No working init found. Try passing init= option to kernel. See Linux Documentation/init.txt for guidance.
Kernel Offset: disabled
Memory Limit: none
---[ end Kernel panic - not syncing: No working init found. Try passing init= option to kernel. See Linux Documentation/init.txt for guidance.
“arch_timer: No interrupt available, giving up”好像还有哪里不对劲,好像我们在第3章dts中指定的interrupts字段,没有被正常解析。没关系,根据[6]的介绍,打开所有的DEBUG输出,然后根据更为详细的日志,检查代码(过程略掉……),如下(从drivers/clocksource/arm_arch_timer.c开始):
CLOCKSOURCE_OF_DECLARE(armv8_arch_timer, "arm,armv8-timer", arch_timer_of_init);
irq_of_parse_and_map(drivers/of/irq.c)
of_irq_parse_one
of_irq_find_parent
好像是找不到interrupt parent?原来是我们的dts还没有添加interrupt-parent字段,按照下面的代码增加:
--- a/arch/arm64/boot/dts/actions/s900-bubblegum.dts
+++ b/arch/arm64/boot/dts/actions/s900-bubblegum.dts@@ -12,6 +12,8 @@
model = "Bubblegum-96 Development Board";
compatible = "actions,s900-bubblegum", "actions,s900";
+ interrupt-parent = <&gic>;
+
#address-cells = <2>;
#size-cells = <2>;
再次编译执行,异常消失了,算是移植完成了吧。
4.2 测试
测试的方法很简单,我们把printk的时间戳打开,如果可以正确显示时间戳,则说明移植成功。打开printk时间戳的方法如下:
cd ~/work/xprj/build;
make kernel-configKernel hacking --->
printk and dmesg options --->
[*] Show timing information on printks
然后编译并运行kernel,输出的日志如下:
…
[ 0.093281] Failed to find cpu0 device node
[ 0.097437] Unable to detect cache hierarchy from DT for CPU 0
[ 0.103562] Warning: unable to open an initial console.
[ 0.108531] Freeing unused kernel memory: 116K (ffffff80081a0000 - ffffff80081bd000)
[ 0.116156] This architecture does not have kernel memory protection.
[ 0.122593] Kernel panic - not syncing: No working init found. Try passing init= option to kernel. See Linux Documentation/init.txt for guidance.
[ 0.135656] Kernel Offset: disabled
[ 0.139124] Memory Limit: none
[ 0.142156] ---[ end Kernel panic - not syncing: No working init found. Try passing init= option to kernel. See Linux Documentation/init.txt for guidance.
成功了。
5. 参考文档
[1] Linux时间子系统之(十七):ARM generic timer驱动代码分析
[2] X-014-KERNEL-ARM GIC driver的移植
[3] bubblegum-96/SoC_bubblegum96.pdf
[4] bubblegum-96/HardwareManual_Bubblegum96.pdf
[5] https://github.com/96boards-bubblegum/linux/blob/bubblegum96-3.10/arch/arm64/boot/dts/s900.dtsi
[6] Linux kernel debug技巧----开启DEBUG选项
原创文章,转发请注明出处。蜗窝科技,www.wowotech.net。
标签: Linux Kernel 内核 timer porting generic

评论:
功能
最新评论
- wangjing
写得太好了 - wangjing
写得太好了! - DRAM
圖面都沒辦法顯示出來好像掛點了。 - Simbr
bus至少是不是还有个subsystem? - troy
@testtest:只要ldrex-modify-strex... - gh
Linux 内核在 sparse 内存模型基础上实现了vme...
文章分类
随机文章
文章存档
- 2025年4月(5)
- 2024年2月(1)
- 2023年5月(1)
- 2022年10月(1)
- 2022年8月(1)
- 2022年6月(1)
- 2022年5月(1)
- 2022年4月(2)
- 2022年2月(2)
- 2021年12月(1)
- 2021年11月(5)
- 2021年7月(1)
- 2021年6月(1)
- 2021年5月(3)
- 2020年3月(3)
- 2020年2月(2)
- 2020年1月(3)
- 2019年12月(3)
- 2019年5月(4)
- 2019年3月(1)
- 2019年1月(3)
- 2018年12月(2)
- 2018年11月(1)
- 2018年10月(2)
- 2018年8月(1)
- 2018年6月(1)
- 2018年5月(1)
- 2018年4月(7)
- 2018年2月(4)
- 2018年1月(5)
- 2017年12月(2)
- 2017年11月(2)
- 2017年10月(1)
- 2017年9月(5)
- 2017年8月(4)
- 2017年7月(4)
- 2017年6月(3)
- 2017年5月(3)
- 2017年4月(1)
- 2017年3月(8)
- 2017年2月(6)
- 2017年1月(5)
- 2016年12月(6)
- 2016年11月(11)
- 2016年10月(9)
- 2016年9月(6)
- 2016年8月(9)
- 2016年7月(5)
- 2016年6月(8)
- 2016年5月(8)
- 2016年4月(7)
- 2016年3月(5)
- 2016年2月(5)
- 2016年1月(6)
- 2015年12月(6)
- 2015年11月(9)
- 2015年10月(9)
- 2015年9月(4)
- 2015年8月(3)
- 2015年7月(7)
- 2015年6月(3)
- 2015年5月(6)
- 2015年4月(9)
- 2015年3月(9)
- 2015年2月(6)
- 2015年1月(6)
- 2014年12月(17)
- 2014年11月(8)
- 2014年10月(9)
- 2014年9月(7)
- 2014年8月(12)
- 2014年7月(6)
- 2014年6月(6)
- 2014年5月(9)
- 2014年4月(9)
- 2014年3月(7)
- 2014年2月(3)
- 2014年1月(4)
2016-11-03 13:54