PolarFire® System on a Chip (SoC) Applications - General Purpose Input/Output (GPIO)
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
- This application is applicable to the following PolarFire SoC-based boards:
- Linux host PC for the Yocto Project® building environment or Windows® Subsystem for Linux (WSL) on a Windows machine
- Tester 2 Click board™ (MIKROE-6466) for experiments
Software Setup
- SoftConsole™ Integrated Development Environment (IDE)
- Libero® SoC design suite 2024.2+
- Yocto Project Host Environment
Programming a Reference Design Into SoC
The first step is programming the Field-Programmable Gate Array (FPGA) design.

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/Switch | Connection | LED/Switch | Connection |
| LED1 | GPIO 2 pin 16 | LED1 | GPIO 2 pin 17 |
| LED2 | GPIO 2 pin 17 | LED2 | GPIO 2 pin 18 |
| LED3 | GPIO 2 pin 18 | LED3 | GPIO 2 pin 19 |
| LED4 | GPIO 2 pin 19 | LED4 | GPIO 2 pin 20 |
| SWITCH2 | GPIO 2 pin 30 | SWITCH2 | MSS_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:
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.
Now you have programmed the FPGA fabric logic.
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
First, we need to download HSS from GitHub.
Import HSS project to SoftConsole by File >Import >Import Existing Project 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.
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.
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.
Yocto Project® Configurations
In this section, we will create a Linux image and program it into the PolarFire SoC Icicle Kit.
Objectives`:
- Setting up the Yocto Project building environment.
- Enabling the GPIO peripheral and including the necessary packages in the build.
- Building a Linux image and deploying it into the SoC.
Creating Environment
Open the command line in your Linux machine or the WSL.
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:
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"
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.

Enable the GPIO Support option.

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-common.dtsi
Make sure that the GPIO2 peripheral is enabled in the mpfs-icicle-kit-common.dtsi:
2
3
status = "okay";
};
Compile a customized Yocto Project Linux kernel recipe in a developer-friendly way, producing kernel binaries for PolarFire SoC:
Building Linux Image and Deploying
Execute the command shown below to build the Linux image:
MACHINE=mpfs-icicle-kit bitbake mchp-base-image
Here's the list of names of supporting machines.
| MACHINE | Board Name | Description |
|---|---|---|
| MACHINE=mpfs-icicle-kit | MPFS-ICICLE-KIT-ES, MPFS-ICICLE-KIT | PolarFire SoC Icicle Kit |
| MACHINE=mpfs-disco-kit | MPFS-DISCO-KIT | PolarFire SoC Discovery Kit |
| MACHINE=mpfs-video-kit | MPFS250-VIDEO-KIT | PolarFire 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.
After booting Linux on the PolarFire Icicle Kit, login as root and check if the GPIO device 0 is appeared under the devices:
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.
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:
- gpiodetect: list all gpiochips present on the system, their names, labels, and number of GPIO lines.
- gpioinfo: list all lines of specified gpiochips, their names, consumers, direction, active state, and additional flags.
- gpioget: read values of specified GPIO lines.
- gpioset: set values of specified GPIO lines, potentially keep the lines exported and wait until timeout, user input or signal.
- gpiofind: find the gpiochip name and line offset given the line name.
- 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 :

Detect GPIOs on the target processor:
gpiochip0 [20122000.gpio] (32 lines)
Print all lines of information:
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):
Set MBUS_RST output low (turning off the RST LED of Tester 2 Click):
Monitor SW2 pin status:
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:
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.
Copy and paste the following C code to the gpio_flash.c:
#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:
Run the gpio_flash executable:
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.
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:
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.
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 <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.
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.