How to Configure Linux GPIO Access on Cyclone5?

Our team has inherited a design using a Cyclone5 with the HPS and FPGA. The HPS is running Linux. We need to have Linux user space access to 8 GPIO signals - 4 in and 4 out.

The fundamental issue is that the /sys/class/gpio is populated with export and unexport devices, but there are no gpiochip or gpionnn directories here. As I understand it the gpiochip and gpio directories are needed for userspace access to GPIO when using the sysfs GPIO driver support.

It seems we have some various “parts” that are skirting around the GPIO subsystem, but they are not tying together to place the expected devices in the linux /sys/class/gpio directory. Obiously I’m missing something.

I could use some guidance on what that “something” or those “somethings” are.

Here are the pieces I’m aware of relating to GPIO in the system:

  • We use Yocto to build the 4.9.0-rc3-altera kernel. Here are (I think) the important kernel config settings for GPIO:

PTP clock support

CONFIG_PTP_1588_CLOCK=y

CONFIG_DP83640_PHY is not set

CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y
CONFIG_GPIOLIB=y
CONFIG_GPIO_DEVRES=y
CONFIG_OF_GPIO=y
CONFIG_GPIOLIB_IRQCHIP=y

CONFIG_DEBUG_GPIO is not set

CONFIG_GPIO_SYSFS=y
CONFIG_GPIO_GENERIC=y

  • Additionally, the build system has a device tree file with the following GPIO entries in it (linux-udsp is the Yocto “machine” name) :
    poky/meta-udsp/recipes-kernel/linux/linux-udsp/arch/arm/boot/dts/socfpga.dtsi:

      gpio0: gpio@ff708000 {
      	#address-cells = <1>;
      	#size-cells = <0>;
      	compatible = "snps,dw-apb-gpio";
      	reg = <0xff708000 0x1000>;
      	clocks = <&l4_mp_clk>;
      	status = "disabled";
    
      	porta: gpio-controller@0 {
      		compatible = "snps,dw-apb-gpio-port";
      		gpio-controller;
      		#gpio-cells = <2>;
      		snps,nr-gpios = <29>;
      		reg = <0>;
      		interrupt-controller;
      		#interrupt-cells = <2>;
      		interrupts = <0 164 4>;
      	};
      };
    
      gpio1: gpio@ff709000 {
      	#address-cells = <1>;
      	#size-cells = <0>;
      	compatible = "snps,dw-apb-gpio";
      	reg = <0xff709000 0x1000>;
      	clocks = <&l4_mp_clk>;
      	status = "disabled";
    
      	portb: gpio-controller@0 {
      		compatible = "snps,dw-apb-gpio-port";
      		gpio-controller;
      		#gpio-cells = <2>;
      		snps,nr-gpios = <29>;
      		reg = <0>;
      		interrupt-controller;
      		#interrupt-cells = <2>;
      		interrupts = <0 165 4>;
      	};
      };
    
      gpio2: gpio@ff70a000 {
      	#address-cells = <1>;
      	#size-cells = <0>;
      	compatible = "snps,dw-apb-gpio";
      	reg = <0xff70a000 0x1000>;
      	clocks = <&l4_mp_clk>;
      	status = "disabled";
    
      	portc: gpio-controller@0 {
      		compatible = "snps,dw-apb-gpio-port";
      		gpio-controller;
      		#gpio-cells = <2>;
      		snps,nr-gpios = <27>;
      		reg = <0>;
      		interrupt-controller;
      		#interrupt-cells = <2>;
      		interrupts = <0 166 4>;
      	};
      };
    
  • and finally, the HPS IO to MUX connections (we’re interested in using HPS_GIO_IN0 through HPS_GIO_IN3 and HPS_GIO_OUT0 through HPS_GIO_OUT3:

I’m not positive, because I haven’t implemented intel GPIO in Cyclone V, but I think you have to modify the FPGA design in Platform Designer to select which I/O you want as GPIO so that the BSP will be generated correctly for u-boot / linux.

If you open the Platform Designer file for your project (named [something].qsys) with qsys-edit, then right click the HPS module and click the “edit” option. Then select the “Peripheral Pins” tab and scroll down you’ll get a list of all the HPS I/O pins, their assignments and their possible uses.

You can click the GPIO buttons on the right side to “highlight” them (highlighting is not very obvious IMO) and then when you re-generate the Verilog for the qsys module, rerun quartus, re-create the BSP and import the BSP into u-boot, you will end up with the ability to control the GPIO pins in u-boot and in linux.

You may have to write your own linux driver. As I said, I have not tackled GPIO because it was much easier to build it into my own RTL design than figure out how to use the default interface.

Refer to chapter 23 of the Cyclone V Hard Processor System Technical Reference Manual. The Cyclone V has three GPIO ports. You can display by typing ls -al /sys/class/gpio/ at the Linux console. This command should display something like this:
–w------- 1 root root 4096 Apr 14 02:05 export
lrwxrwxrwx 1 root root 0 Jan 1 1970 gpiochip427 -> …/…/devices/platform/soc/ff70a000.gpio/gpio/gpiochip427
lrwxrwxrwx 1 root root 0 Jan 1 1970 gpiochip454 -> …/…/devices/platform/soc/ff709000.gpio/gpio/gpiochip454
lrwxrwxrwx 1 root root 0 Jan 1 1970 gpiochip483 -> …/…/devices/platform/soc/ff708000.gpio/gpio/gpiochip483
–w------- 1 root root 4096 Apr 14 02:05 unexport

Depending on which GPIO pins your application uses, you need to map one or more of the GPIO physical addresses, listed above: ff70a000, ff709000 or ff708000. You will need to configure the relevant GPIOs as described in the TRM.