0

I am trying to get the GPIO pins on my mainboard working but I don't know the numbers/descriptions of the pins and if a driver is loaded or not.

I found this guide where it says that I should echo the pin description and redirect the output into /sys/class/gpio/export

/sys/class/gpio # echo 0 > export

So I did. The /sys/class/gpio/ folder exists on my system and it contains the following:

[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 ~]$ 

(By the way if I see this folder does it mean a driver is loaded?)
Then I tried several pin names from the datasheet of my mainboard but I always get the following

[root@host gpio]# echo 31 > export 
echo: write error: Invalid argument
[root@host gpio]# 

I am using Arch Linux and my kernel version is 4.19.2-arch1-1-ARCH.
The Mainboard I use is a Supermicro X10SBA. https://www.supermicro.com/products/motherboard/celeron/x10/x10sba.cfm

The only thing I can find about GPIOs on the Motherboard is on Page 2-25 in the X10SBA Mainboard Datasheet :

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 GND

From my understanding it means the board has eight GPIOs.

So I tried to echo various different combinations into /sys/class/gpio/export like

echo SOC_P3V3_GPIO_S5_31 > export
echo 111 > export
echo 531 > export
echo S531 > export
echo S5_31 > export
...

And so on. Nothing worked.
Am I doing something fundamentally wrong here? Where are the definitions of these GPIO names? Where does export get its information from? Do I have to make these definitions myself first? Maybe do I have to recompile my kernel?

I went on and tried to find out which chip is used for the GPIO headers.

Next to the GPIO Pin headers (JP1) on the board, there is a Chip NXP GTL2010 (Datasheet) and the pins are connected to it from D1 through to D8. I guess this chip is just doing some voltage translation to make the output 3.3V or 5V. So the signal must be coming from The S1-S8 pins. Unfortunately I could not find where these source pins of the GTL2010 are connected to as the traces lead to vias on the board.

But I assume the pins go directly to the CPU. I'm not 100% sure on that. But its my assumption.

The CPU on board is an Intel Celeron J1900. But unfortunately I couln't find a datasheet or any information about it if it has GPIOs.

Is there some possibility to list the GPIOs on board in Linux? How can I check if there is already some GPIO driver used on my system?

Edit

After some research in the CPU datasheet I found that the GPIO_BASE_ADDRESS register (datasheet p. 1219) needs to be set in order to change GPIO settings. The register expects the base address in the I/O space where the GPIO logic is located. Now I don‘t understand which address I should put here. Can this be any 256 free bytes in the I/O space?

Besides that I don’t understand how to access the GPIO_BASE_ADDRESS register. The datasheet states that the register is in the PCI Configuration Space. Bus 0, Device 31 (hex 1f), Function 0. (Datasheet page 56)

Now lspci gives me the following output for device 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

I am not sure how to access this area to write a base address to the register and I don‘t know where in IO space I should put my registers. And how do I realize this in C? Can I make use of existing Linux funtions to implement this?

Edit

The hexdump of the configuration space outputs the following:

[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 ~]$

From my interpretation the ACPI_BASE_ADDRESS register (manual page 1217) contains „03 04 00 00“.

The GPIO_BASE_ADDRESS register (manual page 1219) contains „03 05 00 00“.

Grepping for acpi in dmesg returns several entries (too much to post here).

/proc/ioports outputs the following:

[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

In general, GPIO pins are highly hardware specific. There are no systematic names, no systematic drivers, no systematic registers.

The only thing you can do is read the information you have, google, and guess.

As your motherboard manual says there is a GPIO header, we can assume that the GPIO pins are actually physically routed somehwere (that's not a given; the GPIO pins may be used for other stuff by the BIOS, or they may just be open). "SOC" means "System on a Chip", "3V3" means 3.3 Volts (the TTL level).

First, a warning: If this header directly connects to the SoC, then it's easy to damage your SoC by doing the wrong things. Electrostatic discharge, wrong voltage levels, confusing inputs with outputs etc. may damange your SoC, and your main CPU with it. Always connect a buffer chip to it first if you want to use it. Even if the buffer chip you found next to it actually secures this header, and not something else.

So now we need a datasheet. Googling turns up this, which looks pretty good.

It tells us that the SoC has 101 GPIO pins for S0, and 43 GPIO pins for S5. Only 10 of those end up on the motherboard header, but thankfully we know which ones. The other ones may be connected to other things on the motherboard, so it's important to leave them alone.

On page 56 it tells us that the GPIO (PCU) is a 256-byte long moveable I/O range, decoded by a PCI device on the I/O fabric. I'm not sure how to interpert GBA: PCI[B:0,D:31,F:0] + 48h. In any case, that means the next step is to use lspci as verbosely as necessary, figure out which PCI devices could be meant, and look for a region of 256 bytes that looks promising.

Further on it tells us about the PCU (Platform Unit Controller), in particular about the GPIO registers, starting on page 1262.

So the next step is to read all this, understand it, write a kernel driver for it that uses the correct PCI card and region. This driver will make the I/O pins appear under /sys/class/gpio. Writing one shouldn't be too difficult, googling existing GPIO drivers and modifying them for this hardware should be enough. You need to know how to program in C, and you need to be able to teach yourself how to write a kernel module.

It's also possible that there already exists a driver for this particular hardware, but at least it's not in your kernel (or you'd already see some pins).

Edit

Ok, B, D and F seem to match the bus, device and function of the PCI devices, and there are two 32-byte regions for the SMBus controller, so at least one will match the one described in the manual.

However, there are no regions on 00:1f.0, only a vendor specific block. The data sheet says +40 for ACPI power management, +48h for GPIO, and +f0h for the RCBA, and it also says "They are set using base address registers (BARs) or other similar means", so maybe it's not a BAR/region, but just bytes in the PCI configuration.

So try something like lspci -xxx -s 00:1f.0 (as root), this should show the whole configuration space as hexdump. Also have a look at dmesg after boot and cat /proc/ioports to see of the ACPI power management shows up somewhere (i.e., if it has any I/O port ranges associated to it). We can compare this to +40h. Please edit question with the info.

If the GPIO range is not in a BAR/region, it will get extremely hacky to enable it; at this point you probably should start writing the kernel driver.

Edit

The Coreboot project also has code to access GPIO stuff on Intel, e.g. gpio.c and gpio.h for the Baytrail-Architecture. Not sure which architecture the Celeron J1900 is, but even if it doesn't match, it may give hints are the GPIO region works.

Edit

Ok, the BARs are indeed completely empty. Assuming +40h and +48h work like bars, they are both I/O space (lowest bit is one), where

+40h (ACPI) = 0400h
+48h (GPIO) = 0500h 

Comparing with /proc/ioports, this makes sense: ACPI is 0400-047f, and 0500-05fe has been reserved for the same device pnp 00:01.

So that's the I/O range, and it is already mapped. You can access it via /dev/port, reading and writing at the correct offset, or in a C program using ioperm. Though I vaguely remember the Linux kernel developers threatened to disable either one or both of those features, so I don't know if it still works. In that case, you need a kernel driver.

In any case, be really careful when working with the I/O space: Even reading the wrong address can cause hardware actions, and if you do that on random addresses, anything can happen. So no hexdump -C /dev/port. Also, access size matters.

I couldn't find anything concrete in the datasheet how the GPIO I/O space works, so either you need to google a better datasheet for that, or possibly the Coreboot files work similarly enough.

  • 1
    Thanks your answer was really helpful. I guess GBA: PCI[B:0,D:31,F:0] + 48h describes the position of the GPIO_BASE_ADRESS on Bus 0, Device 31, Function 0 with an offset of hex 48. See the datasheet page 1219. From my understanding an address of the IO space must be entered here, where the actual GPIO registers are defined. I guess that would be the „movable I/O range“? I don‘t know what I should write to this register and how I can access it. When I call lspci on my system, the entry 00:1f.0 ISA brige: Intel..Pow. Contr. Unit looks very much like the one I need. But how can I access it? – spider_gotten_pricetag Dec 3 '18 at 9:49
  • Use lspci -vvv etc. with as many v as necessary, as root if necessary, until you see the regions. If there's an 256 byte region, then very likely that's the one. Edit the question with the output if you are not sure. Also check other PCI devices, though "ISA bridge" is a good candidate. – dirkt Dec 3 '18 at 9:51
  • I have edited the question – spider_gotten_pricetag Dec 3 '18 at 10:41
  • Please do cat /proc/ioports as root (forget to mention it, sorry), so we see the actual ranges instead of 0000-0000. I'll have a closer look at the PCI config when I have the time. – dirkt Dec 3 '18 at 14:52
  • Okay, I updated the post. Thanks for your time. – spider_gotten_pricetag Dec 3 '18 at 15:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.