PolarFire® System on a Chip (SoC) Applications - General Purpose Input/Output (GPIO)

Last modified by Microchip on 2026/04/17 16:40

Introduction

General Purpose Input/Output (GPIO) pins are essential for interacting with hardware components like LEDs and Dual In-line Package (DIP) switches on embedded systems. In a Linux® environment, you can control these GPIOs to turn LEDs on and off or read the state of Dual In-line Package (DIP) switches.

This article focuses on the GPIO capabilities of the PolarFire® System on a Chip (SoC) series and will guide you through the basics of using the GPIO peripheral on PolarFire SoC boards from:

  • Linux® userspace using the libgpiod utility and writing C application code
  • Bare metal GPIO application

Prerequisites

Hardware Setup

  1. This application is applicable to the following PolarFire SoC-based boards:
  2. Linux host PC for the Yocto Project® building environment or Windows® Subsystem for Linux (WSL) on a Windows machine
  3. Tester 2 Click board™ (MIKROE-6466) for experiments

Software Setup

  1. SoftConsole™ Integrated Development Environment (IDE)
  2. Libero® SoC design suite 2024.2+
  3. Yocto Project Host Environment

Programming a Reference Design Into SoC

The first step is programming the Field-Programmable Gate Array (FPGA) design.

Icicle Kit

We should program the reference design for using Yocto Project in the future. To use the LEDs and the buttons, you should know where they are connected in the design. The following table shows the connections for the PolarFire Discovery Kit and PolarFire SoC Icicle Kit. 

Icicle Kit Discovery Kit
LED/SwitchConnectionLED/SwitchConnection
LED1GPIO 2 pin 16LED1GPIO 2 pin 17
LED2GPIO 2 pin 17LED2GPIO 2 pin 18
LED3GPIO 2 pin 18LED3GPIO 2 pin 19
LED4GPIO 2 pin 19LED4GPIO 2 pin 20
SWITCH2GPIO 2 pin 30SWITCH2MSS_INT_F2M[11]

We will rely on the PolarFire SoC Icicle Kit reference design generated using the Libero SoC design suite:

Start by downloading the PolarFire SoC Icicle Kit reference design generation FlashPro images from the latest release in the PolarFire SoC GitHub repo:

https://github.com/polarfire-soc/icicle-kit-reference-design/releases

Back to Top


Program the FPGA by the MPFS_ICICLE_KIT_BASE_DESIGN_{VERSION}​​​​ ​​​design using the FlashPro Express tool (it is included with the Libero® SoC design suite).

Open FlashPro Express to program the prebuilt reference programming FPGA fabric logic.

Open FlashPro Express. 

Create new project. 

Choose the MPFS_ICICLE_KIT_ES_*\MPFS_ICICLE_KIT_ES_BASE_DESIGN_*\MPFS_ICICLE_KIT_ES_*.job file from reference design download folder. 

Click on the Run button. 

Information

Note: Here are links to the reference designs

  1. Icicle Kit Reference Design
  2. Discovery Kit Reference Design
Warning

You have two choices for programming the FPGA:

  1. Use prebuilt reference programming files only (quick start).
  2. Build or modify the Libero® SoC design suite project and regenerate the programming file. See the "PolarFire® System-on-Chip (SoC) Applications - Microprocessor Subsystem (MSS) and Libero® SoC Design Suite" guide.

Now you have programmed the FPGA fabric logic.

Back to Top

GPIO in Linux® Environment

We need to setup and configure the Microprocessor Subsystem (MSS) GPIO peripheral in the Linux configurations. That's why we need Linux build system to configure it and Hart Software Services (HSS) to boot Linux. For this article we will use the Yocto Project.

HSS Configurations

HSS is the bootloader for PolarFire SoC. It runs first, sets up hardware, and launches Linux or other apps. Essential for multi-core and secure boot.

Objectives:

  • Download and import HSS to SoftConsole
  • Update references and build HSS
  • Deploy HSS to PolarFire SoC Icicle Kit
Information

Note: This application article is verified on HSS 2025.07

First, we need to download HSS from GitHub.

Warning

Ensure that you've set your GIT username and user email as global variables on your Linux host PC:

git config --global user.name "your name"
git config --global user.email "your email"

Import HSS project to SoftConsole by File >Import >Import Existing Project Into Workspace.

Import Project

Warning

Ensure that you checked Copy projects into workspace.

Browse the HSS folder and import the project into the workspace by clicking Finish.


Copy your MSS XML file into the project.

Copy the XML file to hart-software-services/boards/mpfs-icicle-kit/soc_fpga_design/xml/<your xml>.xml.

Information

Note: If your board is production board (not ES): use: boards/mpfs-icicle-kit/... instead of boards/mpfs-icicle-kit-es/...


Copy and rename configurations for HSS.

Copy hart-software-services/boards/mpfs-icicle-kit/def_config to hart-software-services/

Rename def_config to .config

Edit .config file and update path to your xml by changing next line. 

CONFIG_SOC_FPGA_DESIGN_XML="boards/mpfs-icicle-kit/soc_fpga_design/xml/<your xml>.xml"

Build HSS and deploy.

Right-click on the project name

Click on the build project

Select PolarFire SoC program non-secure boot mode 1 run option and deploy project to SoC. 

Warning

Make sure are run configurations right. Else open External tools > External tools configurations and change die and package with your board parameters.

PolarFire SoC Icicle Kit ES's die is MPFS250T_ES and package is FCVG484

Back to Top

Yocto Project® Configurations

In this section, we will create a Linux image and program it into the PolarFire SoC Icicle Kit.

Objectives`:

  1. Setting up the Yocto Project building environment.
  2. Enabling the GPIO peripheral and including the necessary packages in the build.
  3. Building a Linux image and deploying it into the SoC.

Creating Environment

Open the command line in your Linux machine or the WSL.

Information

Note: If this is your first time building, install the required packages on the Linux machine by executing this command in your command line.

sudo apt-get install gawk wget git-core git-lfs diffstat unzip texinfo gcc-multilibbuild-essential chrpath socat cpio python3 python3-pip python3-pexpect xz-utils debianutils iputils-ping python3-git python3-jinja2 libsdl1.2-dev xterm repo

Create an empty directory to hold the workspace:

mkdir yocto-dev && cd yocto-dev


Use the repo tool to fetch all the required repositories:

repo init -u https://github.com/linux4microchip/meta-mchp-manifest.git -b refs/tags/linux4microchip+fpga-2025.07 -m polarfire-soc/default.xml
repo sync


Set the TEMPLATECONF environment variable to point to the appropriate configuration template before initializing the build environment:

export TEMPLATECONF=${TEMPLATECONF:-../meta-mchp/meta-mchp-polarfire-soc/meta-mchp-polarfire-soc-bsp/conf/templates/default}


Then initialize the Yocto Project build environment:

source openembedded-core/oe-init-build-env


Build the Linux image with default configurations to make sure that all packages and tools are installed and working properly:

MACHINE=mpfs-icicle-kit bitbake mchp-base-image

Configuring GPIO Peripheral

Prepare the Microchip Linux kernel (linux-mchp) source tree for local development:

MACHINE=mpfs-icicle-kit devtool modify linux-mchp
Success

We should get the following log:

Recipe linux-mchp now set up to build from /build/workspace/sources/linux-mchp


Add all necessary libraries and apps to include to the build.

Open the conf/local.conf file and add the following variable at the of file:

CORE_IMAGE_EXTRA_INSTALL += "libgpiod libgpiod-dev libgpiod-tools packagegroup-core-buildessential vim"

Information
  • libgpiod - The core runtime library for accessing GPIOs via the Linux character device interface (/dev/gpiochipX)
    • Used by applications to interact with GPIOs programmatically

    • Includes libgpiod.so — what your compiled C code links against

  • libgpiod-dev - The development package: includes header files like gpiod.h
    • Required to compile C programs that use libgpiod

    •  Without this, you’ll get errors like fatal error: gpiod.h: No such file or directory

  • libgpiod-tools - A set of command-line utilities for GPIO control

    • gpiodetect, gpioinfo, gpioset, gpioget, gpiomon, etc.

  • packagegroup-core-buildessential - A Yocto meta-package that pulls in all the essential build tools needed for compiling software on your embedded system.

    • Includes:

      • gcc → C compiler

      • make → build automation

      • binutils → linker, assembler, etc.

      • pkgconfig → helps locate libraries and headers

      • libc-dev → standard C library headers

      • autoconf, automake, libtool → for building autotools-based projects

  • vim - A powerful text editor used in terminal environments
  • mchp-base-image (Release 2025.07) default configuration includes the libgpiod library, you can skip the below steps if you're following the default configs.

Save the file and exit.


Open the Linux kernel configuration menu to enable the GPIO peripheral:

MACHINE=mpfs-icicle-kit bitbake linux-mchp -c menuconfig


Navigate down to the Device Drivers.

Device Drivers

 


Enable the GPIO Support option.

GPIO Support


Save the config by selecting Save > Exit.


Locate the PolarFire Icicle Kit related Device Tree Source (DTS) files for modification:

yocto-dev/build/workspace/sources/linux-mchp/arch/riscv/boot/dts/microchip/mpfs-icicle-kit.dts
yocto-dev/build/workspace/sources/linux-mchp/arch/riscv/boot/dts/microchip/mpfs-icicle-kit-common.dtsi

Make sure that the GPIO2 peripheral is enabled in the mpfs-icicle-kit-common.dtsi:

1
2
3
&gpio2 {
 status = "okay";
};

Compile a customized Yocto Project Linux kernel recipe in a developer-friendly way, producing kernel binaries for PolarFire SoC:

MACHINE=mpfs-icicle-kit devtool build linux-mchp
Warning

You can create a bbappend layer execute following commands
> devtool finish linux-mchp custom-layer

​​​​Your bbappend layer will be saved at: custom-layer/recipes-kernel/linux/linux-mchp_%.bbappend

Building Linux Image and Deploying

Execute the command shown below to build the Linux image:

MACHINE=mpfs-icicle-kit bitbake mchp-base-image

Information

Note: Ensure that the initial Linux image has been built without error, so we can start making the modifications.

Here's the list of names of supporting machines. 

MACHINEBoard NameDescription
MACHINE=mpfs-icicle-kitMPFS-ICICLE-KIT-ES, MPFS-ICICLE-KITPolarFire SoC Icicle Kit
MACHINE=mpfs-disco-kitMPFS-DISCO-KITPolarFire SoC Discovery Kit
MACHINE=mpfs-video-kitMPFS250-VIDEO-KITPolarFire SoC Video Kit

As the build is done, you can locate your Linux image at:

yocto-dev/build/tmp-glibc/deploy/images/<board_name>/<image-name>.rootfs-***.wic


Follow the GitHub instructions to deploy the built Image to the eMMC/SD card memory.

Information

Note: For additional information, refer to the PF SoC Yocto Linux building GitHub page


After booting Linux on the PolarFire Icicle Kit, login as root and check if the GPIO device 0 is appeared under the devices:

root@icicle-kit:/# ls /dev | grep gpio
gpiochip0

If nothing returns, that means the GPIO device is not enabled and you have to double-check the configuration and Device Tree Source (DTS) modification needed to be done.

Back to Top

Software Tools and Utilities

libgpiod – C Library and Tools

Linux GPIO is accessed through the GPIO character device (/dev/gpiochipX). The recommended userspace interface is libgpiod, which provides:

  • Command-line tools (quick testing from the shell)
  • A C library API (for applications)

For more information see the C library and tools for interacting with the Linux GPIO character device.

Command Line Tools of libgpiod

There are some simple tools provided by libgpiod for accessing the GPIO driver from the shell.
​In the past, GPIO was accessed by the shell from the sysfs interface. As of Linux version 4.8, this method has been deprecated. The libgpiod was developed as a more effective way to access the GPIO driver.

There are six commands in in libgpiod tools:

  1. gpiodetect: list all gpiochips present on the system, their names, labels, and number of GPIO lines.
  2. gpioinfo: list all lines of specified gpiochips, their names, consumers, direction, active state, and additional flags.
  3. gpioget: read values of specified GPIO lines.
  4. gpioset: set values of specified GPIO lines, potentially keep the lines exported and wait until timeout, user input or signal.
  5. gpiofind: find the gpiochip name and line offset given the line name.
  6. gpiomon: wait for events on GPIO lines, specify which events to watch, how many events to process before exiting or if the events should be reported to the console.

Using libgpiod Tools on PolarFire Icicle Kit :

Information

Note: All the following commands are running from the Icicle kit connected with the Tester 2 Click board on the mikroBUS socket with following pinout:

PolarFire Icicle Kit 
MBUS LedConnection
GPIO_2_M2F_20_ANMBUS_AN
GPIO_2_M2F_21_RSTMBUS_RST

PolarFire Icicle Kit

Detect GPIOs on the target processor:

# gpiodetect
gpiochip0 [20122000.gpio] (32 lines)

Print all lines of information:

# gpioinfo
gpiochip0 - 32 lines:
        line   0:      unnamed       unused  output  active-high
        line   1:      unnamed       unused  output  active-high
        line   2:      unnamed       unused  output  active-high
        line   3:      unnamed       unused  output  active-high
[...]

Set MBUS_RST output high (turning on the RST LED of Tester 2 Click):

# gpioset gpiochip0 21=1

Set MBUS_RST output low (turning off the RST LED of Tester 2 Click):

# gpioset gpiochip0 21=0

Monitor SW2 pin status:

# gpiomon gpiochip0 30
event:  RISING EDGE offset: 30 timestamp: [     257.493094000]
event: FALLING EDGE offset: 30 timestamp: [     257.661584000]
event:  RISING EDGE offset: 30 timestamp: [     258.530547000]
event: FALLING EDGE offset: 30 timestamp: [     258.699577000]

Reading SW2 Input state:

# gpioget gpiochip0 30

Application Programming in C Language Using gpiod Library

We will write a C program that reads the value of the SW2 switch and flashes the MBUS_AN and INT LED pins using the libgpiod Application Programming Interface (API) (which wraps the GPIO character-device ioctls).

Boot Linux on your PolarFire SoC Icicle Kit. Navigate to /media and create gpio_flash.c using the Vim editor.

cd /media && vim gpio_flash.c

Copy and paste the following C code to the gpio_flash.c:

#include <gpiod.h>
#include
<stdio.h>
#include
<unistd.h>

#define CHIP_NAME "/dev/gpiochip0"
#define SW2_LINE 30
#define LED1_LINE 20
#define LED2_LINE 21

int main(void) {
   struct gpiod_chip *chip;
   struct gpiod_line *sw2, *led1, *led2;
   int sw2_val, i;

   // Open the GPIO chip
   chip = gpiod_chip_open(CHIP_NAME);
   if (!chip) {
        perror("Open chip failed");
       return 1;
    }

   // Get lines
   sw2 = gpiod_chip_get_line(chip, SW2_LINE);
    led1 = gpiod_chip_get_line(chip, LED1_LINE);
    led2 = gpiod_chip_get_line(chip, LED2_LINE);
   if (!sw2 || !led1 || !led2) {
        perror("Get line failed");
        gpiod_chip_close(chip);
       return 1;
    }

   // Request lines
   if (gpiod_line_request_input(sw2, "sw2-read") < 0) {
        perror("Request input failed");
        gpiod_chip_close(chip);
       return 1;
    }
   if (gpiod_line_request_output(led1, "led1-flash", 0) < 0 ||
        gpiod_line_request_output(led2, "led2-flash", 0) < 0) {
        perror("Request output failed");
        gpiod_chip_close(chip);
       return 1;
    }

    printf("Press SW2 to flash LEDs on pins 20 and 21...\n");

   for (i = 0; i < 10; ++i) { // Flash 10 times for demonstration
       sw2_val = gpiod_line_get_value(sw2);
       if (sw2_val < 0) {
            perror("Read SW2 failed");
           break;
        }
       if (!sw2_val) { // If switch is pressed (assuming active low)
           gpiod_line_set_value(led1, 1);
            gpiod_line_set_value(led2, 1);
            usleep(200000); // 200 ms
           gpiod_line_set_value(led1, 0);
            gpiod_line_set_value(led2, 0);
            usleep(200000); // 200 ms
       } else {
            gpiod_line_set_value(led1, 0);
            gpiod_line_set_value(led2, 0);
            usleep(100000); // 100 ms
       }
    }

   // Release lines and close chip
   gpiod_line_release(sw2);
    gpiod_line_release(led1);
    gpiod_line_release(led2);
    gpiod_chip_close(chip);

   return 0;
}

After saving the modification, compile the C code:

gcc -o gpio_flash gpio_flash.c -lgpiod

Run the gpio_flash executable:

./gpio_flash
Success

Running the application, you will get the following response:

root@icicle-kit:/media# ./gpio_flash
Press SW2 to flash LEDs on pins 20 and 21...

Back to Top

GPIO in Bare Metal Applications

To use the MSS GPIO in the bare metal side, we have to use the SoftConsole to develop the application to build, compile, and deploy.

For this application, use the mpfs-blank-bare metal project and start writing our application code in the U54_1 source file.

Download the mpfs-blank-baremetal bare metal application project from the official GitHub repository and import it into the SoftConsole.

Information

Note: If this is your first time importing a project in SoftConsole, refer to the "Clone and Import a Project from the Bare Metal Library" video.

 


Replace the MSS Configuration XML file in the bare metal project with the XML file used in your Libero SoC design suite project. The path to the file that SoftConsole will use to generate header files, which are then used by the MPFS HAL, is:

mpfs-blank-baremetal > "your_board" > fpga_design > design_description > xx.xml

Now we can begin modifying u54_1.c with our custom code to perform two actions:

Read the value of SW2 and increment a counter each time it is pressed. 

Turn on LED1, LED2, LED3, or LED4 based on the current count value. 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <stdio.h>
#include
<string.h>
#include
"mpfs_hal/mss_hal.h"
#include
"drivers/mss/mss_gpio/mss_gpio.h"

uint8_t led = 0U;

void u54_1(void){
    (void)mss_config_clk_rst(MSS_PERIPH_GPIO2, (uint8_t) MPFS_HAL_FIRST_HART, PERIPHERAL_ON);

    MSS_GPIO_config(GPIO2_LO, MSS_GPIO_16, MSS_GPIO_OUTPUT_MODE);
    MSS_GPIO_config(GPIO2_LO, MSS_GPIO_17, MSS_GPIO_OUTPUT_MODE);
    MSS_GPIO_config(GPIO2_LO, MSS_GPIO_18, MSS_GPIO_OUTPUT_MODE);
    MSS_GPIO_config(GPIO2_LO, MSS_GPIO_19, MSS_GPIO_OUTPUT_MODE);
    MSS_GPIO_config(GPIO2_LO, MSS_GPIO_30, MSS_GPIO_INPUT_MODE);

    MSS_GPIO_set_output(GPIO2_LO, MSS_GPIO_16, 1u);
   while(1U){
       if(!(MSS_GPIO_get_inputs(GPIO2_LO) & (1<<30))){
            MSS_GPIO_set_output(GPIO2_LO, MSS_GPIO_16+led, 0u);

            led++;
           if(led == 4U){ led = 0U;}

            MSS_GPIO_set_output(GPIO2_LO, MSS_GPIO_16+led, 1u);

           while(!(MSS_GPIO_get_inputs(GPIO2_LO) & (1<<30))){
                ;
            }
        }
    }
}

Line 1-6: We start by including the necessary header files for standard input/output, string handling, and the PolarFire SoC HAL, GPIO drivers. Also we define LED's status control variable.

Line 8: The u54_1() function is the main entry point for the application. 

Line 9-15: We bringing GPIO2 bank out of reset and configuring their mode's input or output.

Line 18-19: Creating infinite loop where will be implemented main logic of this application. And into this loop checking for button is pressed.

Line 20-25: disabling active Led, updating LED's status, checking for overload and if Led id is greater than 4 it brings 0.

Line 27: Waiting for releasing the button.


Build the project and deploy it either in LIM for Debug mode or eNVM for Release mode.

Note: You can refer to the "Build and Debug the Project" video for building and debugging bare metal applications in SoftConsole.

Back to Top

Summary

This guide provides a detailed overview for enabling and testing GPIO communication on PolarFire SoC-based boards using Yocto Project. The process begins with configuring the device tree to enable the GPIO peripheral, then ensuring the GPIO driver is enabled in the Linux kernel. Userspace testing is then performed using the gpiod libs utility to interact with GPIO devices from the Linux userspace. Additionally, a custom C program is written and executed to enable and disable led on the PolarFire SoC. By following this guide, you establish a solid foundation for further development with GPIO peripherals on the PolarFire SoC-based boards.

Back to Top