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).
The SCFW is built on a Linux host. The steps to set-up your system are the following:
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
export TOOLS=~/gcc_toolchain/
sudo apt-get update
sudo apt-get install srecord
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
./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.
Configuring the PMIC overview and board.c common modifications
case SC_SUBSYS_A53:
pmic_init();
if (pmic_card == PF100)
{
pmic_id[0] = PMIC_2_ADDR;
pmic_reg[0] = SW2;
*num_regs = 1;
}
else
{/* PF8100_dual Card */
pmic_id[0] = PMIC_0_ADDR;
pmic_reg[0] = PF8100_SW5;
*num_regs = 1;
}
break;
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);
}
else
return SC_ERR_PARM;
break;
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);
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,
VGEN_MODE_ON);
}
else
{
pmic_interface.pmic_set_mode(PMIC_2_ADDR, VGEN6,
VGEN_MODE_OFF);
}
}
else
{/* 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,
RUN_EN_STBY_EN);
}
else
{
pmic_interface.pmic_set_mode(PMIC_1_ADDR, PF8100_LDO1,
RUN_OFF_STBY_OFF);
}
}
break;
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);
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:
- SC_P_SCU_PMIC_MEMC_ON
- SC_P_SCU_WDOG_OUT
- SC_P_PMIC_EARLY_WARNING
- SC_P_PMIC_INT_B
- SC_P_SCU_BOOT_MODE0 through SC_P_SCU_BOOT_MODE5
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)
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