我试图让主板上的 GPIO 引脚正常工作,但我不知道引脚的编号/描述以及是否加载了驱动程序。
我发现这指导我应该去哪里回声引脚描述并将输出重定向到/sys/class/gpio/导出
/sys/class/gpio # echo 0 > export
所以我做了。这/系统/类/GPIO/我的系统上存在文件夹,其中包含以下内容:
[user@host ~]$ ls -l /sys/class/gpio/
total 0
--w------- 1 root root 4096 Nov 30 18:12 export
--w------- 1 root root 4096 Nov 30 18:12 unexport
[user@host ~]$
(顺便说一句,如果我看到这个文件夹是否意味着驱动程序已加载?)
然后我尝试了主板数据表中的几个引脚名称,但我总是得到以下信息
[root@host gpio]# echo 31 > export
echo: write error: Invalid argument
[root@host gpio]#
我在用架构Linux我的内核版本是4.19.2-arch1-1-ARCH。
我使用的主板是超微 X10SBA。https://www.supermicro.com/products/motherboard/celeron/x10/x10sba.cfm
我能找到的关于主板上 GPIO 的唯一内容是在第 2-25 页X10SBA主板数据表:
1 +3.3V
2 SOC_P3V3_GPIO_S5_31
3 SOC_P3V3_GPIO_S5_32
4 SOC_P3V3_GPIO_S5_33
5 SOC_P3V3_GPIO_S5_34
6 SOC_P3V3_GPIO_S5_35
7 SOC_P3V3_GPIO_S5_36
8 SOC_P3V3_GPIO_S5 _37
9 SOC_P3V3_GPIO_S5_38
10 接地
根据我的理解,这意味着该板有 8 个 GPIO。
所以我尝试将各种不同的组合回显/sys/class/gpio/导出喜欢
echo SOC_P3V3_GPIO_S5_31 > export
echo 111 > export
echo 531 > export
echo S531 > export
echo S5_31 > export
...
等等。什么都没起作用。
我在这里做的是根本错误的事情吗?这些GPIO名称的定义在哪里?哪里有出口从哪里获取其信息?我必须先自己做出这些定义吗?也许我必须重新编译我的内核?
我继续尝试找出 GPIO 接头使用的是哪个芯片。
在电路板上的 GPIO 引脚接头 (JP1) 旁边,有一个芯片恩智浦GTL2010(数据表)并且引脚从 D1 到 D8 连接到它。我猜这个芯片只是做了一些电压转换,使输出为 3.3V 或 5V。因此信号必定来自 S1-S8 引脚。不幸的是,我无法找到 GTL2010 的这些源极引脚的连接位置,因为走线通向板上的过孔。
但我假设引脚直接连接到CPU。我对此不是 100% 确定。但这是我的假设。
主板上的 CPU 是 Intel Celeron J1900。但不幸的是,我找不到数据表或有关它是否有 GPIO 的任何信息。
是否有可能在 Linux 中列出板上的 GPIO?如何检查我的系统上是否已使用某些 GPIO 驱动程序?
编辑
经过一些研究CPU数据表我发现需要设置 GPIO_BASE_ADDRESS 寄存器(数据表第 1219 页)才能更改 GPIO 设置。该寄存器需要 GPIO 逻辑所在的 I/O 空间中的基地址。现在我不明白我应该把哪个地址放在这里。这可以是 I/O 空间中任意 256 个空闲字节吗?
除此之外,我不明白如何访问 GPIO_BASE_ADDRESS 寄存器。数据表指出该寄存器位于 PCI 配置空间中。总线 0,设备 31(十六进制 1f),功能 0。(数据表第 56 页)
现在 lspci 为我提供了设备 31 的以下输出:
[user@host ~]$ sudo lspci -vvvvvv
...
00:1f.0 ISA bridge: Intel Corporation Atom Processor Z36xxx/Z37xxx Series Power Control Unit (rev 0e)
Subsystem: Super Micro Computer Inc Atom Processor Z36xxx/Z37xxx Series Power Control Unit
Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B- DisINTx-
Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=medium >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
Latency: 0
Capabilities: [e0] Vendor Specific Information: Len=0c <?>
Kernel driver in use: lpc_ich
Kernel modules: lpc_ich
00:1f.3 SMBus: Intel Corporation Atom Processor E3800 Series SMBus Controller (rev 0e)
Subsystem: Super Micro Computer Inc Atom Processor E3800 Series SMBus Controller
Control: I/O+ Mem+ BusMaster- SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B- DisINTx-
Status: Cap+ 66MHz- UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
Interrupt: pin B routed to IRQ 18
Region 0: Memory at 90a04000 (32-bit, non-prefetchable) [size=32]
Region 4: I/O ports at e000 [size=32]
Capabilities: [50] Power Management version 3
Flags: PMEClk- DSI- D1- D2- AuxCurrent=0mA PME(D0-,D1-,D2-,D3hot-,D3cold-)
Status: D0 NoSoftRst+ PME-Enable- DSel=0 DScale=0 PME-
Kernel driver in use: i801_smbus
Kernel modules: i2c_i801
我不知道如何访问该区域以将基地址写入寄存器,并且我不知道应该将寄存器放在 IO 空间中的何处。我如何在 C 中实现这一点?我可以利用现有的Linux功能来实现这个功能吗?
编辑
配置空间的十六进制转储输出以下内容:
[user@host ~]$ sudo lspci -xxx -s 00:1f.0
[sudo] password for user:
00:1f.0 ISA bridge: Intel Corporation Atom Processor Z36xxx/Z37xxx Series Power Control Unit (rev 0e)
00: 86 80 1c 0f 07 00 10 02 0e 00 01 06 00 00 80 00
10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
20: 00 00 00 00 00 00 00 00 00 00 00 00 d9 15 16 08
30: 00 00 00 00 e0 00 00 00 00 00 00 00 00 00 00 00
40: 03 04 00 00 02 30 d0 fe 03 05 00 00 02 c0 d0 fe
50: 02 80 d0 fe 02 10 d0 fe 02 00 f0 fe 02 50 d0 fe
60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
d0: 00 00 00 00 00 00 00 00 cf ff 00 00 00 00 00 00
e0: 09 00 0c 10 00 00 00 00 00 00 00 00 00 00 00 00
f0: 01 c0 d1 fe 00 00 00 00 1a 0f 0e 01 03 03 00 00
[user@host ~]$
根据我的解释,ACPI_BASE_ADDRESS 寄存器(手册第 1217 页)包含“03 04 00 00”。
GPIO_BASE_ADDRESS 寄存器(手册第 1219 页)包含“03 05 00 00”。
在 dmesg 中查找 acpi 会返回几个条目(太多,无法在此处发布)。
/proc/ioports 输出以下内容:
[user@host ~]$ sudo cat /proc/ioports
[sudo] password for user:
0000-006f : PCI Bus 0000:00
0000-001f : dma1
0020-0021 : pic1
0040-0043 : timer0
0050-0053 : timer1
0060-0060 : keyboard
0064-0064 : keyboard
0070-0077 : PCI Bus 0000:00
0070-0077 : rtc0
0078-0cf7 : PCI Bus 0000:00
0080-008f : dma page reg
00a0-00a1 : pic2
00c0-00df : dma2
00f0-00ff : fpu
02e0-02e7 : serial
02f8-02ff : serial
03e0-03e7 : serial
03f8-03ff : serial
0400-047f : pnp 00:01
0400-0403 : ACPI PM1a_EVT_BLK
0404-0405 : ACPI PM1a_CNT_BLK
0408-040b : ACPI PM_TMR
0420-042f : ACPI GPE0_BLK
0430-0433 : iTCO_wdt.0.auto
0430-0433 : iTCO_wdt
0450-0450 : ACPI PM2_CNT_BLK
0460-047f : iTCO_wdt.0.auto
0460-047f : iTCO_wdt
0500-05fe : pnp 00:01
0600-061f : pnp 00:01
0680-069f : pnp 00:01
0a30-0a3f : pnp 00:07
0cf8-0cff : PCI conf1
0d00-ffff : PCI Bus 0000:00
1000-1fff : PCI Bus 0000:01
b000-cfff : PCI Bus 0000:03
b000-cfff : PCI Bus 0000:04
b000-bfff : PCI Bus 0000:07
b000-b01f : 0000:07:00.0
b000-b01f : ahci
b020-b023 : 0000:07:00.0
b020-b023 : ahci
b030-b037 : 0000:07:00.0
b030-b037 : ahci
b040-b043 : 0000:07:00.0
b040-b043 : ahci
b050-b057 : 0000:07:00.0
b050-b057 : ahci
c000-cfff : PCI Bus 0000:05
c000-c01f : 0000:05:00.0
d000-dfff : PCI Bus 0000:02
d000-d01f : 0000:02:00.0
e000-e01f : 0000:00:1f.3
e000-e01f : i801_smbus
e020-e027 : 0000:00:02.0
答案1
一般来说,GPIO 引脚是高度硬件特定的。没有系统名称,没有系统驱动程序,没有系统寄存器。
你唯一能做的就是阅读你拥有的信息,谷歌,然后猜测。
正如您的主板手册所说,有一个 GPIO 接头,我们可以假设 GPIO 引脚实际上是物理布线的(这不是给定的;GPIO 引脚可能被 BIOS 用于其他用途,或者它们可能只是处于开放状态)。 “SOC”表示“片上系统”,“3V3”表示 3.3 伏(TTL 电平)。
首先,一个警告:如果此接头直接连接到 SoC,则很容易因错误操作而损坏您的 SoC。静电放电、错误的电压水平、混淆输入与输出等可能会损坏您的 SoC 及其主 CPU。总是如果要使用,请先连接缓冲芯片。即使您在它旁边找到的缓冲芯片实际上保护了这个标头,而不是其他东西。
所以现在我们需要一个数据表。谷歌搜索出现这,看起来不错。
它告诉我们,SoC 有 101 个用于 S0 的 GPIO 引脚,以及 43 个用于 S5 的 GPIO 引脚。其中只有 10 个最终出现在主板接头上,但幸运的是我们知道是哪些。其他的可能连接到主板上的其他东西,所以不要管它们很重要。
第 56 页告诉我们 GPIO (PCU) 是一个 256 字节长的可移动 I/O 范围,由 I/O 结构上的 PCI 设备解码。我不知道如何解释GBA: PCI[B:0,D:31,F:0] + 48h
。无论如何,这意味着下一步是lspci
根据需要尽可能详细地使用,找出可能意味着哪些 PCI 设备,并寻找看起来有希望的 256 字节区域。
从第 1262 页开始,它进一步向我们介绍了 PCU(平台单元控制器),特别是 GPIO 寄存器。
因此,下一步是阅读所有这些内容,理解它,为其编写一个使用正确 PCI 卡和区域的内核驱动程序。该驱动程序将使 I/O 引脚出现在 下/sys/class/gpio
。写一篇不应该也困难,谷歌搜索现有的 GPIO 驱动程序并针对该硬件修改它们应该足够了。您需要知道如何用 C 语言编程,并且需要能够自学如何编写内核模块。
也有可能已经存在针对该特定硬件的驱动程序,但至少它不在您的内核中(或者您已经看到一些引脚)。
编辑
好的,B、D 和 F 似乎与 PCI 设备的总线、设备和功能相匹配,并且 SMBus 控制器有两个 32 字节区域,因此至少有一个与手册中描述的区域相匹配。
但是, 上没有区域00:1f.0
,只有供应商特定的块。数据表中提到了+40
ACPI 电源管理、+48h
GPIO 和+f0h
RCBA,还说“它们是使用基址寄存器 (BAR) 或其他类似方式设置的”,所以也许它不是 BAR/区域,而只是字节在 PCI 配置中。
因此,尝试类似的操作lspci -xxx -s 00:1f.0
(以 root 身份),这应该将整个配置空间显示为 hexdump。还要在dmesg
启动后查看cat /proc/ioports
一下 ACPI 电源管理是否显示在某处(即,是否有与其关联的任何 I/O 端口范围)。我们可以将其与 进行比较+40h
。请使用信息编辑问题。
如果 GPIO 范围不在 BAR/区域中,则启用它会变得非常困难;此时您可能应该开始编写内核驱动程序。
编辑
Coreboot 项目还具有访问 Intel 上的 GPIO 内容的代码,例如GPIO.c和GPIO.hBaytrail 架构。不确定 Celeron J1900 属于哪种架构,但即使不匹配,它也可能会提示 GPIO 区域是否正常工作。
编辑
好吧,BAR 确实是空的。假设+40h和+48h像条一样工作,它们都是I/O空间(最低位是1),其中
+40h (ACPI) = 0400h
+48h (GPIO) = 0500h
与 相比/proc/ioports
,这是有道理的:ACPI 是 0400-047f,而 0500-05fe 已为同一设备保留pnp 00:01
。
这就是 I/O 范围,并且它已经被映射。您可以通过/dev/port
在正确的偏移处读取和写入来访问它,或者在 C 程序中使用ioperm
。尽管我依稀记得 Linux 内核开发人员威胁要禁用其中一个或两个功能,所以我不知道它是否仍然有效。在这种情况下,您需要一个内核驱动程序。
无论如何,在使用 I/O 空间时要非常小心:即使读取错误的地址也可能导致硬件操作,如果您在随机地址上执行此操作,则任何事情都可能发生。所以不行hexdump -C /dev/port
。此外,访问大小也很重要。
我在数据表中找不到任何具体的 GPIO I/O 空间如何工作的内容,因此要么您需要在 google 上搜索更好的数据表,要么 Coreboot 文件的工作方式可能足够相似。
答案2
我购买了类似的硬件并遇到了类似的问题。起初我尝试探索别人描述的路线,但后来我解决如下:
我的系统: CPU 版本: Intel(R) Celeron(R) CPU J1900 @ 1.99GHz
在某些时候我认为这实现了 IT8786 芯片。
如果您检查内核配置,您可能会发现对 IT87x 系列驱动程序的支持(当然在 GPIO 驱动程序下)。就我而言,这仅作为模块启用。
然后,我加载了该模块:
sudo insmod /lib/modules/5.8.0-55-generic/kernel/drivers/gpio/gpio-it87.ko
dmesg 返回以下项目:
gpio_it87: Found Chip IT8786 rev 2. 64 GPIO lines starting at 0a00h
通过检查 /dev,gpiochip0 出现,从那里开始,如果您愿意,您可以使用已经提到的 sysfs 方法(尽管已经退休)。
如果您不知道如何将物理引脚与硬件相关联,请尝试以下操作:
apt-get install gpiod
在我的例子中,运行 gpioinfo 返回以下内容:
gpiochip0 - 64 lines:
line 0: "it87_gp10" unused input active-high
line 1: "it87_gp11" unused input active-high
line 2: "it87_gp12" "sysfs" input active-high [used]
line 3: "it87_gp13" unused input active-high
line 4: "it87_gp14" unused input active-high
line 5: "it87_gp15" unused input active-high
line 6: "it87_gp16" unused input active-high
line 7: "it87_gp17" unused input active-high
line 8: "it87_gp20" unused input active-high
line 9: "it87_gp21" unused input active-high
line 10: "it87_gp22" unused input active-high
line 11: "it87_gp23" unused input active-high
line 12: "it87_gp24" "sysfs" input active-high [used]
line 13: "it87_gp25" unused input active-high
line 14: "it87_gp26" unused input active-high
line 15: "it87_gp27" unused input active-high
line 16: "it87_gp30" unused input active-high
line 17: "it87_gp31" unused input active-high
line 18: "it87_gp32" unused input active-high
line 19: "it87_gp33" unused input active-high
line 20: "it87_gp34" unused input active-high
line 21: "it87_gp35" unused input active-high
line 22: "it87_gp36" "sysfs" output active-high [used]
line 23: "it87_gp37" unused input active-high
line 24: "it87_gp40" unused input active-high
line 25: "it87_gp41" unused input active-high
line 26: "it87_gp42" unused input active-high
line 27: "it87_gp43" unused input active-high
line 28: "it87_gp44" unused input active-high
line 29: "it87_gp45" unused input active-high
line 30: "it87_gp46" unused input active-high
line 31: "it87_gp47" unused input active-high
line 32: "it87_gp50" unused input active-high
line 33: "it87_gp51" unused input active-high
line 34: "it87_gp52" unused input active-high
line 35: "it87_gp53" unused input active-high
line 36: "it87_gp54" unused input active-high
line 37: "it87_gp55" unused input active-high
line 38: "it87_gp56" unused input active-high
line 39: "it87_gp57" unused input active-high
line 40: "it87_gp60" unused input active-high
line 41: "it87_gp61" unused input active-high
line 42: "it87_gp62" unused input active-high
line 43: "it87_gp63" unused input active-high
line 44: "it87_gp64" unused input active-high
line 45: "it87_gp65" unused input active-high
line 46: "it87_gp66" unused input active-high
line 47: "it87_gp67" unused input active-high
line 48: "it87_gp70" unused input active-high
line 49: "it87_gp71" unused input active-high
line 50: "it87_gp72" unused input active-high
line 51: "it87_gp73" "sysfs" input active-high [used]
line 52: "it87_gp74" "sysfs" output active-high [used]
line 53: "it87_gp75" "sysfs" input active-high [used]
line 54: "it87_gp76" "sysfs" input active-high [used]
line 55: "it87_gp77" unused input active-high
line 56: "it87_gp80" unused input active-high
line 57: "it87_gp81" unused output active-high
line 58: "it87_gp82" unused input active-high
line 59: "it87_gp83" unused input active-high
line 60: "it87_gp84" unused input active-high
line 61: "it87_gp85" unused input active-high
line 62: "it87_gp86" unused input active-high
line 63: "it87_gp87" unused input active-high
您可以使用 gpiod 实用程序来处理不同的引脚。如果您的制造商以某种方式指示您可以使用哪个 GPI/O,那么您可以将“线路”与 it87_gpXX”部分相关联,即 XX 可能由制造商提供的引脚。
可以按照旧方式进行快速检查。
转到 /sys/class/gpio 并查看找到的 gpiochip。 gpiochip 内部的基数是起始位置,gpioinfo 返回的线点是偏移量。
就我而言,我以 448 作为基础。如果我想到达 GP81,即第 57 行,所以我会这样做:
echo 505 > /sys/class/gpio/export
我希望这有帮助!它使我免于编写驱动程序(顺便说一句,制造商给我发送了驱动程序,但它不起作用)