System Controller Firmware 101 - Getting started

Document created by manuelrodriguez Employee on Mar 7, 2018Last modified by manuelrodriguez Employee on Feb 7, 2019
Version 5Show Document
  • View in full screen mode

When working with an evaluation kit you will be provided with a System Controller Firmware (SCFW) binary included in your BSP. This scfw binary has been tailored for that specific board and you might need to modify some board dependencies to fit your specific hardware.

This document aims to provide an overview on the SCFW porting process, for detailed information please refer to the System Controller Porting guide (sc_fw_port.pdf).


Setting up the system

The SCFW is built on a Linux host. The steps to set-up your system are the following:

  • Download the GNU ARM Embedded Toolchain: 6-2017-q2-update June 28, 2017 from the ARM website:

GNU ARM Embedded toolchain

  • Select a directory to untar the file unto, for instance:
    mkdir ~/gcc_toolchain
    cp ~/Downloads/gcc-arm-none-eabi-6-2017-q2-update-linux.tar.bz2 ~/gcc_toolchain/
    cd ~/gcc_toolchain/
    tar xvjf gcc-arm-none-eabi-6-2017-q2-update-linux.tar.bz2


  • Set TOOLS environment variable to the directory containing the tool chain, "~/gcc_toolchain" on the example above, .bash_profile can also be modified to export this environment variable:
    export TOOLS=~/gcc_toolchain/
  • srec_cat is also necessary for the build, this is usually contained in the srecord package, on ubuntu you can do:

    sudo apt-get update

    sudo apt-get install srecord

  • Now you can change to the porting kit directory (e.g. scfw_export_mx8qm) and build the scfw.

System Controller Firmware Porting kit 

The SCFW porting kit contains source files and object files that will allow you to modify the SCFW to work with your board.

You can get the latest System Controller Firmware Porting kit from the i.MX Software and development webpage:

Once you obtain the porting kit untar it:

tar xvzf imx-scfw-porting-kit-1.1.tar.gz

You will see the following file structure:

The porting kit is contained under packages, the README contains the instructions to extract the porting kit, basically:

cd packages/
chmod a+x imx-scfw-porting-kit-1.1.bin

You will be prompted to accept an End User License Agreement:

Once you accept the agreement the porting kit will be extracted in a new folder, the folder structure is as follows:

All documentation regarding SCFW is under doc/pdf or in html format if preferred, it is recommended to go over sc_fw_port.pdf.

The porting kits for different SoC variants (QM A0, QM B0 and QXP B0) are under src packaged as tar.gz, all other files are SCFW libraries for different software packages, such as Linux, QNX, FreeRTOS, U-boot, ARM Trusted Firmware, etc...


If you will be working with several SoC variants (working with both QXP and QM) it is recommended to extract all porting kits into a single directory, that way you will be able to build for any variant from this directory, the command to do this is:

cd imx-scfw-porting-kit-1.1/
cd src/
find scfw_export_mx8*.gz -exec tar --strip-components 1 --one-top-level=scfw_export_mx8 -xzvf {} \;

A scfw_export_mx8 folder will be created, from here you will be able to build SCFW for any supported variant. Or you can just extract the package for the variant you are interested on and use that.

cd scfw_export_mx8/

All the build folders contain the results of building the SCFW and platform is where the source of the SCFW is stored.


All the code that is specific to a board configuration is under "platform/board/mx8<derivative>_<board_name>" where derivative is the i.MX8 silicon family such as QXP or QM, and board name is the name of the board the SCFW package is for.

The first step in porting the SCFW to your board is to create a folder for your i.MX8 derivative and board, you can take one of the available board examples and rename the folder, that will provide you a project to get started with, for instance:

cp -r platform/board/mx8qm_val/ platform/board/mx8qm_myBoard/

The board in this example will be called "myBoard" and it is for an i.MX8QM B0 device. To build a SCFW for this board simply call:

make qm R=B0 B=myBoard

If the target is an i.MX8QXP simply take a board based on this device and change the call to "make qx".

Additional information such as build options and in detailed boot information can be found in the SCFW porting guide (sc_fw_port.pdf), chapter 2 of this document is a great introduction to the porting process.


Overview and useful information

Configuring the PMIC overview and board.c common modifications

  • The main file that needs to be altered (if not the only) is the "board.c" file, it is located at "platform/board/mx8X_board/". The board.c file contains most of the board related information such as SCU UART ports, PMIC initialization routines, PMIC temperature alarms settings and you can also modify it to configure LDOs voltages and communicate with the PMIC in general. All functions in the board.c file are executed by the SCU itself and this gives you access to the I2C interface that is used to communicate with the PMIC.
  • SoC resources that are powered by an external supply (PMIC LDO for instace) such as AP cores and GPUs are powered off/on by board_set_power_mode, the mapping of the resource to an specific PMIC supply happens in board_get_pmic_info, for instance in our i.MX8QM validation board using the A53 subsystem is powered by SW2 of the third PMIC (PMIC_2_ADDR addresses start at PMIC_0) on the PF100 PMIC card and by SW5 of the first PMIC (PMIC_0_ADDR) on the PF8100 PMIC card.
    case SC_SUBSYS_A53:
    if (pmic_card == PF100)
    pmic_id[0] = PMIC_2_ADDR;
    pmic_reg[0] = SW2;
    *num_regs = 1;
    {/* PF8100_dual Card */
    pmic_id[0] = PMIC_0_ADDR;
    pmic_reg[0] = PF8100_SW5;
    *num_regs = 1;
  • The voltages of SoC resources that are powered by an external supply (AP cores, GPUs, etc...) are managed by board_set_voltage in the board.c file. The mapping of resource to power supply occurs in board_get_pmic_info as in the example above.
  • Eight "board resources" (SC_R_BOARD_R0, ... SC_R_BOARD_R7) are available, these resources allow you to define components in your board that the SCU can manage, for instance a sensor on your board powered by one of the PMIC LDOs can be mapped to a board resource and the board.c file can be modified to power on/off the sensor as well as modifying its voltage.
  • Modifying the voltage on a board resource can be either be done by modifying the voltage at board_trans_resource_power (see below) or if the voltage needs to change at run time the function board_set_control can be modified to change the voltage whenever a miscellaneous call (more details in the Miscellaneous Service 101) is made on that resource. For instance to change the voltage on SC_R_BOARD_R7 you would have the following case to board_set_control:
    case SC_R_BOARD_R7:
    if (ctrl == SC_C_VOLTAGE)
    /* Example only PMIC_X_ADDR and PMIC_SUPPLY need to match an actual device */
    pmic_interface.pmic_set_voltage(PMIC_X_ADDR, PMIC_SUPPLY, val, step);
    return SC_ERR_PARM;

    The case above will be executed by the SCU every time the application calls the function below:

    sc_misc_set_control( ipc, SC_R_BOARD_R7, SC_C_VOLTAGE, voltage_val);
  • Powering on/off a board resource happens at board_trans_resource_power in the board.c file. For instance in NXP's validation board the PTN5150 on the board is managed through a board resource 0, and the power on/off is managed as follows:
    case BRD_R_BOARD_R0 : /* PTN5150 (use SC_R_BOARD_R0) */
    if (pmic_ver.device_id == PF100_DEV_ID)
    if (to_mode > SC_PM_PW_MODE_OFF)
    pmic_interface.pmic_set_voltage(PMIC_2_ADDR, VGEN6,
    3300, SW_RUN_MODE);
    pmic_interface.pmic_set_mode(PMIC_2_ADDR, VGEN6,
    pmic_interface.pmic_set_mode(PMIC_2_ADDR, VGEN6,
    {/* PF8100_dual Card */
    if (to_mode > SC_PM_PW_MODE_OFF)
    pmic_interface.pmic_set_voltage(PMIC_1_ADDR, PF8100_LDO1,
    3300, REG_RUN_MODE);
    pmic_interface.pmic_set_mode(PMIC_1_ADDR, PF8100_LDO1,
    pmic_interface.pmic_set_mode(PMIC_1_ADDR, PF8100_LDO1,

    Whenever the function below is called from the application side the SCU will execute the code above:

    sc_pm_set_resource_power_mode(ipc, SC_R_BOARD_R0, SC_PM_PW_MODE_ON/OFF);
  • board_config_sc is used to mark resources that the SCU needs, such as the I2C module and pads used to communicate with the PMIC, any resource needed by the board.c functions to work should be marked in this function as not movable, for instance to keep the SCU I2C module the following line is added:
    rm_set_resource_movable(pt_sc, SC_R_SC_I2C, SC_R_SC_I2C, false);

    The following pads are part of the SCU and the application will not be able to access them:


  • board_system_config is where early resource management occurs, this function is only called when the alt_config flag is set in the image, and it can create partitions and allocate resources to it. More details are found in the resource management service 101.
  • board_get_pcie_clk_src defines the clock that the PCIe uses, it can be either BOARD_PCIE_PLL_EXTERNAL or BOARD_PCIE_PLL_INTERNAL.
  • board_print is very useful to debug your changes the syntax is as follows:
    board_print(3, "Debug printout %d\n", val);

    Where the first parameter is the Debug Level and from there on it works as a standard printf. The output will only be visible on the SCU debug output whenever the SCU is built with the corresponding debug level, in the case above the SCFW needs to be built as follows in order to see the output:

make qm B=myBoard DL=3 or higher (debug level goes from 0 to 5)


Usage examples

The following utility shows how to make System Controller Firmware requests and provides a way to make such requests through command line interface on both QNX and Linux

System Controller Firmware Command Line Utility for Linux and QNX


System Controller Firmware 101  

1 person found this helpful