linux 4.19.90 acpi与platform设备

一. acpi与platform设备

​ platform设备就是为了给嵌入式设备用的,而嵌入式arm架构基本都是使用设备树,一般的过程是这样

​ ① 在扫描设备树文件的时候,就会自动调用platform_device_register去添加设备

​ ② 然后再用compatible字段去匹配驱动

但在acpi情况下,acpi也有acpi表,我们拿定时设备来说,一般都是GTDT表,和设备树一样,这里面也是有很多描述硬件资源的表项,但platform总线并不会扫描GTDT表,只会扫描设备树。这就需要ACPI上的platform设备自己手动注册platform设备

​ 理论终究是枯燥的,上实例,用sbsa的watchdog来说明:

​ dirvers/acpi/gtdt.c,此文件是acpi专门留给定时器的后台注册文件,实现了诸多对GTDT表项的接口。而sbsa在此处完成了自己扫描GTDT,并注册platform设备的工作

​ 如果有兴趣研究sbsa的源码,可以去drivers/watchdog/sbsa_gwdt.c去看

gtdt_sbsa_gwdt_init

static int __init gtdt_sbsa_gwdt_init(void)
{
	void *platform_timer;
	struct acpi_table_header *table;
	int ret, timer_count, gwdt_count = 0;

	······

	/*
	 * Note: Even though the global variable acpi_gtdt_desc has been
	 * initialized by acpi_gtdt_init() while initializing the arch timers,
	 * when we call this function to get SBSA watchdogs info from GTDT, the
	 * pointers stashed in it are stale (since they are early temporary
	 * mappings carried out before acpi_permanent_mmap is set) and we need
	 * to re-initialize them with permanent mapped pointer values to let the
	 * GTDT parsing possible.
	 */
    // 获取gtdt表
	ret = acpi_gtdt_init(table, &timer_count);
	if (ret || !timer_count)
		return ret;

    // 遍历GTDT表项,拿到对应数据放到platform_timer中
	for_each_platform_timer(platform_timer中) {
		if (is_non_secure_watchdog(platform_timer)) {
            // 进一步初始化
			ret = gtdt_import_sbsa_gwdt(platform_timer, gwdt_count);
			if (ret)
				break;
			gwdt_count++;
		}
	}

	if (gwdt_count)
		pr_info("found %d SBSA generic Watchdog(s).\n", gwdt_count);

	return ret;
}

device_initcall(gtdt_sbsa_gwdt_init);

gtdt_import_sbsa_gwdt

/*
 * Initialize a SBSA generic Watchdog platform device info from GTDT
 */
// 注释也能看出来这个函数的作用
static int __init gtdt_import_sbsa_gwdt(struct acpi_gtdt_watchdog *wd,
					int index)
{
	struct platform_device *pdev;
    // 从GTDT表中拿的数据,来计算中断号,和设备树是一样的逻辑
	int irq = map_gt_gsi(wd->timer_interrupt, wd->timer_flags);

	/*
	 * According to SBSA specification the size of refresh and control
	 * frames of SBSA Generic Watchdog is SZ_4K(Offset 0x000 – 0xFFF).
	 */
    // 控制寄存器和刷新寄存器的基地址
	struct resource res[] = {
		DEFINE_RES_MEM(wd->control_frame_address, SZ_4K),
		DEFINE_RES_MEM(wd->refresh_frame_address, SZ_4K),
		DEFINE_RES_IRQ(irq),
	};
    // 资源数量
	int nr_res = ARRAY_SIZE(res);

	······错误校验代码······

	/*
	 * Add a platform device named "sbsa-gwdt" to match the platform driver.
	 * "sbsa-gwdt": SBSA(Server Base System Architecture) Generic Watchdog
	 * The platform driver can get device info below by matching this name.
	 */
    // 注意这里只是添加了一个设备,并不会匹配驱动,驱动的匹配时机在platform总线轮询的时候才会执行
	pdev = platform_device_register_simple("sbsa-gwdt", index, res, nr_res);
	if (IS_ERR(pdev)) {
		acpi_unregister_gsi(wd->timer_interrupt);
		return PTR_ERR(pdev);
	}

	return 0;
}

​ 看完这些代码,才可以真正理解“手动添加“platform设备的含义,为了与设备树相比较,我们可以把GTDT表与设备树相比较看一下

GTDT表与设备树

GTDT表

​ GTDT表是ACPI表的一种,具体可自行查阅ACPI表的种类,很多,且这部分表由固件厂家(搞SOC板卡的)和硬件厂家共同维护

​ 我们现在电脑看到的BIOS,实际上是ACPI+UEFI来进行的引导,因为UEFI有图形化界面,这个是intel开发的,实际上现在看到所谓的昆仑,鲲鹏固件等BIOS,都是基于这个框架。现在armv8服务器也开始使用ACPI机制,而放弃设备树了。

​ GTDT表可以使用 acpidump -o acpi_table.dat + acpixtract -s GTDT acpi_table.dat来直接导出,但一般情况下没有这个工具,介绍另一种方法

​ 首先拿到二进制的GTDT表:

cp /sys/firmware/acpi/tables/GTDT ./gtdt.dat

​ 然后用iasl命令直接解析就行了

root@kylin-pc:/home/kylin/桌面# iasl -d gtdt.dat 

Intel ACPI Component Architecture
ASL+ Optimizing Compiler/Disassembler version 20190509
Copyright (c) 2000 - 2019 Intel Corporation

File appears to be binary: found 121 non-ASCII characters, disassembling
Binary file appears to be a valid ACPI table, disassembling
Input file gtdt.dat, Length 0x98 (152) bytes
ACPI: GTDT 0x0000000000000000 000098 (v02 PHYLTD PHYTIUM. 00000001 PHYT 00000001)
Acpi Data Table [GTDT] decoded
Formatted output:  gtdt.dsl - 4125 bytes

​ 我们来看看这个解析出来是什么,后面见注释

/*
 * Intel ACPI Component Architecture
 * AML/ASL+ Disassembler version 20190509 (64-bit version)
 * Copyright (c) 2000 - 2019 Intel Corporation
 * 
 * Disassembly of gtdt.dat, Thu Apr 24 17:02:56 2025
 *
 * ACPI Data Table [GTDT]
 *
 * Format: [HexOffset DecimalOffset ByteLength]  FieldName : FieldValue
 */
标识表类型为 ​​Generic Timer Description Table,用于描述ARM架构的通用定时器和看门狗资源
[000h 0000   4]                    Signature : "GTDT"    [Generic Timer Description Table]
[004h 0004   4]                 Table Length : 00000098 表总长度为 ​​152字节​​(0x98),与末尾的Raw Data长度一致。
[008h 0008   1]                     Revision : 02		符合 ​​ACPI 6.3及以上版本规范​​,支持平台定时器和安全扩展功能
[009h 0009   1]                     Checksum : 82		校验和值,通过所有字节相加取模256等于0来验证完整性
[00Ah 0010   6]                       Oem ID : "PHYLTD" 原始设备制造商(OEM)标识符,此处为 ​​Phytium(飞腾)公司​​ 的简写
[010h 0016   8]                 Oem Table ID : "PHYTIUM."厂商自定义表标识符,可能对应特定硬件平台(如Phytium ARM服务器)
[018h 0024   4]                 Oem Revision : 00000001  厂商自定义版本号,表示首次发布或修订版本
[01Ch 0028   4]              Asl Compiler ID : "PHYT"	ACPI编译器标识符,此处为Phytium的定制编译器
[020h 0032   4]        Asl Compiler Revision : 00000001 编译器版本号,与厂商工具链相关。

[024h 0036   8]        Counter Block Address : FFFFFFFFFFFFFFFF  系统计数器(System Counter)的MMIO地址,全F表示 ​​未启用或保留字段​​
[02Ch 0044   4]                     Reserved : 00000000	保留字段,通常填充0

[030h 0048   4]         Secure EL1 Interrupt : 0000001D	安全态EL1级别的定时器中断号为 ​​29​​(0x1D[034h 0052   4]    EL1 Flags (decoded below) : 00000006	中断属性解码:   
                                Trigger Mode : 0  		  ​​Trigger Mode : 0​​ → 电平触发(Level-sensitive)
                                    Polarity : 1		  ​​Polarity : 1​​ → 高电平有效(Active High)
                                   Always On : 1		  ​​Always On : 1​​ → 定时器在低功耗状态下保持运行

[038h 0056   4]     Non-Secure EL1 Interrupt : 0000001E	非安全态EL1中断号为 ​​30​​(0x1E),属性与安全态相同
[03Ch 0060   4]   NEL1 Flags (decoded below) : 00000006
                                Trigger Mode : 0
                                    Polarity : 1
                                   Always On : 1

[040h 0064   4]      Virtual Timer Interrupt : 0000001B	虚拟定时器中断号为 ​​27​​(0x1B),属性同上
[044h 0068   4]     VT Flags (decoded below) : 00000006
                                Trigger Mode : 0
                                    Polarity : 1
                                   Always On : 1

[048h 0072   4]     Non-Secure EL2 Interrupt : 0000001A 非安全态EL2中断号为 ​​26​​(0x1A),属性同上
[04Ch 0076   4]   NEL2 Flags (decoded below) : 00000006
                                Trigger Mode : 0
                                    Polarity : 1
                                   Always On : 1
[050h 0080   8]   Counter Read Block Address : FFFFFFFFFFFFFFFF		系统计数器读取块地址,未启用。

[058h 0088   4]         Platform Timer Count : 00000002	包含 ​​2个平台定时器条目​​,此处均为看门狗类型
[05Ch 0092   4]        Platform Timer Offset : 00000060 平台定时器条目起始偏移为 ​​0x60​​(即从表头开始的第96字节)

                                       看门狗条目(Watchdog Subtable)
[060h 0096   1]                Subtable Type : 01 [Generic Watchdog Timer] 类型为 ​​Generic Watchdog Timer​​(SBSA兼容看门狗)
[061h 0097   2]                       Length : 001C				
[063h 0099   1]                     Reserved : 00
[064h 0100   8]        Refresh Frame Address : 000000002800A000		看门狗刷新寄存器基地址:​​0x2800A000​​
[06Ch 0108   8]        Control Frame Address : 000000002800B000		看门狗控制寄存器基地址:​​0x2800B000​​。
[074h 0116   4]              Timer Interrupt : 00000030				看门狗中断号为 ​​48​​(0x30[078h 0120   4]  Timer Flags (decoded below) : 00000000				
                                Trigger Mode : 0
                                    Polarity : 0
                                    Security : 0
                                        
		结构与条目1类似,地址为 ​​0x28016000​​(Refresh)和 ​​0x28017000​​(Control),中断号为 ​​49
[07Ch 0124   1]                Subtable Type : 01 [Generic Watchdog Timer]	
[07Dh 0125   2]                       Length : 001C
[07Fh 0127   1]                     Reserved : 00
[080h 0128   8]        Refresh Frame Address : 0000000028016000
[088h 0136   8]        Control Frame Address : 0000000028017000
[090h 0144   4]              Timer Interrupt : 00000031
[094h 0148   4]  Timer Flags (decoded below) : 00000000
                                Trigger Mode : 0
                                    Polarity : 0
                                    Security : 0

Raw Table Data: Length 152 (0x98)

    0000: 47 54 44 54 98 00 00 00 02 82 50 48 59 4C 54 44  // GTDT......PHYLTD
    0010: 50 48 59 54 49 55 4D 2E 01 00 00 00 50 48 59 54  // PHYTIUM.....PHYT
    0020: 01 00 00 00 FF FF FF FF FF FF FF FF 00 00 00 00  // ................
    0030: 1D 00 00 00 06 00 00 00 1E 00 00 00 06 00 00 00  // ................
    0040: 1B 00 00 00 06 00 00 00 1A 00 00 00 06 00 00 00  // ................
    0050: FF FF FF FF FF FF FF FF 02 00 00 00 60 00 00 00  // ............`...
    0060: 01 1C 00 00 00 A0 00 28 00 00 00 00 00 B0 00 28  // .......(.......(
    0070: 00 00 00 00 30 00 00 00 00 00 00 00 01 1C 00 00  // ....0...........
    0080: 00 60 01 28 00 00 00 00 00 70 01 28 00 00 00 00  // .`.(.....p.(....
    0090: 31 00 00 00 00 00 00 00                          // 1.......
设备树

​ 在嵌入式的arm中,启动的方式就变为了uboot + 设备树DT的方式

​ 我们的老朋友设备树就不用说了,在这里:

在这里插入图片描述

总结

​ 重中之重,现在的主流两种arm架构的启动方式

​ ① UEFI + ACPI表(acpi支持硬件动态编码,这个不太了解是什么机制)

​ ② uboot +设备树

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值