Linux下如何使用X86 CPU的GPIO
作者:wsg1100
出处:
1.前言在arm嵌入式开发中 , 各个外设具有固定的物理地址 , 我们可以直接通过芯片手册来编写驱动配置后使用 。 但是在x86中有所不同 , 所有外设控制器集成在PCH(曾经的南桥)中 , 每个外设都是作为一个PCI设备挂在PCH的PCI总线上 , PCH再通过DMI与CPU相联 。 对于标压处理器H/K系列(也就是我们台式机) , 南桥还在主板上 , 对于x86移动处理器(Y/U结尾系列) , 已将PCH和CPU集成到同一封装中 , 与如今各类SOC类似 , 如下(详见 datasheet ) 。
文章插图
由于x86中每个外设是一个PCI设备 , 所以我们要使用某个外设就需要为其分配内存空间映射、IRQ和I/O基址 , x86中这些资源配置是由BIOS(UEFI)完成的 , 因为每块主板设计和外设使用不一样 , 就需要不一样的配置 , 所以不同的主板厂商需要定制自己主板的BIOS。
BIOS配置好主板使用的外设后 , 一些BIOS(UEFI)通过ACPI(高级配置和电源接口)的DSDT来传递设备信息(类似arm设备树 , 但功能更强)给操作系统 , 获取这些设备信息后我们才能配置和使用这个外设 , 但ACPI对各个操作系统有兼容性问题 , 这就会出现你在Windows设备管理器能看到该设备 , 到linux下什么也没有 , 因为大部分X86硬件厂商的BIOS主要兼容Windows为主 , 一般桌面CPU都是用的Windows系统嘛 。
本文说的GPIO就是这么个问题 , linux下无法使用 , 由于涉及的东西有点多 , 所以简单介绍在如何将x86工控机引出的GPIO使用起来的(注意:是CPU的GPIO引脚 , 不是Super IO的GPIO) 。
CPU :英特尔7代低压处理器( Kaby Lake) i5-7200U/赛扬3865Ulinux:linux 4.0以上
2.linux pinctrl子系统要使用gpio需要先看一下linux系统PINCTRL子系统 , 层级如下所示(图片来源蜗窝科技):
文章插图
最底层是硬件控制器 , 其上是操作这些硬件的相关驱动(pin controller driver) , 不同的控制器有不同底层驱动 , 一般由芯片厂商BSP完成;pin controller driver初始化的时候会向pin control core模块注册pin control设备(通过pinctrl_register这个bootom level interface) 。 pin control core模块是一个硬件无关模块 , 它抽象了所有pin controller的硬件特性 , 仅仅从用户(各个driver就是pin control subsystem的用户)角度给出了top level的接口函数 , 这样 ,各个driver不需要关注pin controller的底层硬件相关的内容 , 使用时直接向pinctrl子系统申请IO资源即可 。关于linux GPIO与pinctrl子系统信息 , 详见 蜗窝科技-GPIO子系统 .
pin controller driver成功注册到pin control core后 , 我们通过pin control core导出到sysfs的文件就可以直接操作一个GPIO , 使其输入输出 , 而不需要专门去写一个驱动模块 。
3. pin controller driver搞嵌入式的一定对platform bus非常熟悉 , pin controller driver的注册同样离不开platform bus , driver与device必须经过某种匹配后 , 才能进一步执行probe注册到系统中 。
文章插图
结合前言中对x86设备的描述 , platform bus可通过以下两种方式来判断driver和device是否匹配 。
probe()probe()
别忘了前提 , 启动时BIOS必须为使用的PCI设备分配好设备中断号(中断vector)、映射空间地址等我们才能用 。 那对于我们的GPIO设备linux系统使用的是哪种方式呢 , 这需要到源码中来看 , 首先七代系列CPU linux pinctrl driver源码文件为 \drivers\pinctrl\intel\pinctrl-sunrisepoint.c, 看如下代码 。
static const struct acpi_device_id spt_pinctrl_acpi_match[] = { { "INT344B", (kernel_ulong_t)MODULE_DEVICE_TABLE(acpi, spt_pinctrl_acpi_match);.....static struct platform_driver spt_pinctrl_driver = { .probe = spt_pinctrl_probe, .driver = {.name = "sunrisepoint-pinctrl",.acpi_match_table = spt_pinctrl_acpi_match,.pm =
可以看到使用的是ACPI模式 , 那么驱动的注册逻辑应该如下 ,
文章插图
【Linux下如何使用X86 CPU的GPIO】其中driver把系统中所有的pin描述出来 , 并将driver注册到platform bus 。 driver需要对应的device才能工作 ,但是linux因为ACPI的兼容性问题 , linux并没有解析DSDT并创建出GPIO 相关的device , 所以没有触发执行probe来将pin controller driver注册到pin control core中 , pinctrl子系统没有工作当然无法使用。 到这里我们去解决内核对ACPI的解析(或者说兼容性问题)显然是不太现实的(自己太菜(╯﹏╰)) , 有没有其他办法呢?
- 推新标准建新生态,下载超198亿次金山发力海内外
- 闲鱼|电诉宝:“闲鱼”网络欺诈成用户投诉热点 Q3获“不建议下单”评级
- 王兴称美团优选目前重点是建设核心能力;苏宁旗下云网万店融资60亿元;阿里小米拟增资居然之家|8点1氪 | 美团
- 页面|如何简单、快速制作流程图?上班族的画图技巧get
- 培育|跨境电商人才如何培育,长沙有“谱”了
- 先别|用了周冬雨的照片,我会成为下一个被告?自媒体创作者先别自乱阵脚
- 丹丹|福佑卡车创始人兼CEO单丹丹:数字领航 驶向下一个十年
- 抖音小店|抖音进军电商,短视频的商业模式与变现,创业者该如何抓住机遇?
- 看过明年的iPhone之后,现在下手的都哭了
- 计费|5G是如何计费的?