Board Bringup

This document provides guidance for board bring-up in IoT Yocto.

Before starting software bring-up, please verify the hardware status of the board. The following hardware components and interfaces should be inspected according to your board design:

  • Power source & voltage

  • Clock frequency

  • Voltage in different outputs

  • LEDs status

Check Boot ROM

Connect the board to serial port (UART0) and start serial communication using a baud rate of 115200. If the board is well powered, ROM code logs should appear in the serial interface from UART0 port.

If not, please check whether the hardware is well powered or a powering problem has occurred. The following is an example of Boot ROM log for MT8395:

F0: 102B 0000
F3: 1006 0033 [0200]
F3: 4001 00E0 [0200]
F3: 0000 0000
V0: 0000 0000 [0001]
00: 0000 0000
BP: 0C00 0241 [0000]
G0: 1190 0000
EC: 0080 0000 [0000]
S7: 0000 0000 [0000]
T0: 0000 01AA [100F]
Jump to BL

Different SoC have different Boot ROM log, but the format should be similar.

Create New Yocto Layer

After confirming the SoC is well powered, you can now create new software configurations for your board. To do so, you need to add new layers on top of the meta-mediatek-bsp and meta-rity layers provided by IoT Yocto.

  1. Download IoT Yocto layers by referring to Get Started with IoT Yocto.

  2. Create a meta-<board_name> layer with the following basic architecture:

    meta-<board_name>
    ├── conf
    │   ├── machine
    │   │   └── <machine_name>.conf    # an MACHINE identifier for your board
    │   ├── layer.conf                 #
    │   ├── local.conf.sample          # example configuration for users of your board
    │   └── bblayers.conf.sample       # the layers you'd like to include by default
    │
    ├── recipes-bsp
    │   ├── libdram
    │   │   ├── files/                 # patches to add board support
    │   │   ├── libdram-lk.bbappend    # apply patches to libdram-lk.bb
    │   │   └── libdram.bbappend       # symlink to add the patches to libdram.bb
    │   │
    │   └── u-boot
    │       ├── files/                 # patches to add board support
    │       └── u-boot_%.bbappend      # add device-tree and config patches
    │
    ├── recipes-kernel
    │   └── linux-mtk
    │       ├── files/                 # patches to add device-tree kernel modification and configuration
    │       └── linux-mtk_%.bbappend   # apply the patches to linux kernel
    │
    ├── recipes-core
    │
    └── wic
        └── custom.wks.in              # Partitioning
    

Each recipe could extend or override the definition of existing BSP and RITY layers.

Add New Machine Configuration

For board bring-up, it usually involves adding a new machine configuration to specify the following configurations:

  • DRAM configuration

  • U-Boot device driver and configuration

  • Kernel device driver and configuration

  • Boot process configuration

  • Additional Yocto package and image customization

In meta-<board_name>/conf/machine, add a <machine_name>.conf file. The content should be:

  1. Include SoC-recipe include files. For example,

    require conf/machine/include/mtxxxx.inc
    

    You can refer to existing board configurations in meta-mediatek-bsp layer to know which include files that should be used.

    For example,

    • conf/machine/genio-1200-evk.conf provides configuration for the Genio 1200-EVK which uses eMMC storage by default.

    • conf/machine/genio-1200-evk-ufs.conf provides configuration for UFS boot and storage configurations for Genio 1200 EVK configured for UFS storage.

  2. Set LIBDRAM_BOARD_NAME, See Libdram configuration

  3. Set kernel device-tree: KERNEL_DEVICETREE, See Kernel device tree

  4. Set u-boot configuration: UBOOT_MACHINE, See U-boot device tree

  5. Set OP-TEE DRAM size: OPTEE_DRAM_SIZE, See OP-TEE DRAM size configuration

  6. Set overrides via MACHINEOVERRIDES variable.

  7. Add machine and distro features using DISTRO_FEATURES_append and MACHINE_FEATURES_append.

The following sections show how to achieve this by modifying different recipes.

libdram Configuration

Note

Only MT8365 (Genio 350) requires modification to libdram. For other SoCs, please skip this section.

Important

  1. Modifying DRAM component requires proprietary software libdram from MediaTek. You need to get the source code from MediaTek partners and distributors.

  2. The DRAM driver will determine the bank size and bank number based on the voltage of the AUXIN1 pin. Please refer to the hardware design notice and reference design document for guidance, and set the AUXIN1 pin to the correct voltage.

Important

The libdram is used by the bl2 and the download agent(lk). If you make modifications to the source code locally, you need to modify both the libdram and libdram-lk. Using the following commands to obtain the source code.

devtool modify libdram
devtool modify libdram-lk

And also you need to modify both build/workspace/sources/libdram/ and build/workspace/sources/libdram-lk/. Then rebuild rity-demo-image and lk.

In libdram/boards/<board_name>, add a meson.build file that contains the reference for DDR configuration: https://gitlab.com/mediatek/aiot/nda/libdram

libdram
├── board
│    └── <board_name>
│             └── meson.build
├── src
│    └── mtxxxx
│         ├── ddr
│         │    └── <ddr_type>.cfg
│         └── driver
│
└── tools

In meson.build:

SoC = 'mtxxxx'

ddr = [
        '<ddr_type>',
]

MediaTek supports different DDR type and provide some default configurations(refer to libdram/src/<SOC>/ddr : https://gitlab.com/mediatek/aiot/nda/libdram/-/tree/main/src).

  • Please select the ddrtype_default.cfg base on your DDR type.

  • Please define the DDR type you are using and comment out other types.

#add_project_arguments('-DCOMBO_LPDDR3_178BALL', language: 'c')
add_project_arguments('-DCOMBO_LPDDR4', language: 'c')
#add_project_arguments('-DCOMBO_PCDDR3_32BIT', language: 'c')
#add_project_arguments('-DCOMBO_PCDDR4_32BIT', language: 'c')

Patch the modified libdram sources as a libdram patch file.

After adding a new machine in IoT Yocto project (refer to Add New Machine Configuration), set LIBDRAM_BOARD_NAME in machine configuration file.

meta-mediatek-bsp
└─── conf
        └── machine
            └── <board_name>.cfg
...
# libdram
LIBDRAM_BOARD_NAME = "<board_name>"
...
  • Add the libdram patch file to meta-<board_name>/recipes-bsp/libdram/files/.

  • Add the patch PATH to SRC_URI variable in libdram-lk.bbappend.

  • Add symbolic link to libdram.bbappend.

meta-<board_name>
├── recipes-bsp
│   ├── libdram
│   │   ├── files/                 # patches to add board support
│   │   ├── libdram-lk.bbappend    # apply patches to libdram-lk.bb
│   │   └── libdram.bbappend       # symbolic link to add the patches to libdram.bb
... ...

U-Boot configuration

U-Boot Device tree

  1. Add the device tree to u-boot/arch/arm/dts/<mtxxxx-board_name>.dts.

u-boot
└── arch
    └── arm
        └── dts
            └── <mtxxxx-board_name>.dts
  1. Include the SoC device tree : mtxxxx.dtsi.

  2. Refer to already existing device tree with the same SoC.

  3. Configure emmc : frequency, bus-width …

  4. Configure DDR size :

    It is not mandatory to change the default DDR size in u-boot device tree since u-boot only need few MB of memory at most and does not need to use the whole DDR.

memory@40000000 {
            device_type = "memory";
            reg = <0 0x40000000 0 0x80000000>;
    } ;
  • 0 0x40000000 is the address of the DDR in memory coded in 64 Bits, meaning that 0x0000000040000000 is the actual DDR address. This value should not be changed.

  • 0 0x80000000 is the RAM size. In this example, it refers to 2GB of RAM.

With 4GB of RAM use :
reg = <0 0x40000000 1 0x00000000>;  # meaning '0x0000000100000000'.
    1. Add <mtxxxx-board_name>.dtb to u-boot/arch/arm/dts/Makefile.

...
dtb-$(CONFIG_ARCH_MEDIATEK) += \
        <mtxxxx-board_name>.dtb
...
    1. Patch u-boot sources and add the patch to meta-<board_name>/recipes-bsp/u-boot/files/.

    1. Add the patch PATH to SRC_URI variable in meta-<board_name>/recipes-bsp/u-boot/u-boot_%.bbappend.

meta-<board_name>
├──recipes-bsp
│  └── u-boot
│      ├── files/                 # patches to add board support
│      └── u-boot_%.bbappend      # add device-tree and config patches
...

U-Boot Machine Configuration

Use already existing SoC-matching defconfig if no changes are to be added (jump to step 4).

To create a board specific u-boot defconfig please follow the next steps:
    1. Create a <mtxxxx_board_defconfig> that contains u-boot configuration in /configs

u-boot
└── configs
    └── <mtxxxx_board_defconfig>
    1. Patch u-boot sources and add the patch to meta-<board_name>/recipes-bsp/u-boot/files/.

    1. Add the patch PATH to SRC_URI variable in meta-<board_name>/recipes-bsp/u-boot/u-boot_%.bbappend.

meta-<board_name>
├──recipes-bsp
│   └── u-boot
│       ├── files/                 # patches to add board support
│       └── u-boot_%.bbappend      # add device-tree and config patches
    1. Set UBOOT_MACHINE variable in <machine_name>.conf

    meta-<board_name>
    ├── conf
    │   ├── machine
    │   │   └── <machine_name>.conf    #
    │   ├── layer.conf                 #
    │   ├── local.conf.sample          #
    │   └── bblayers.conf.sample       #
...
UBOOT_MACHINE = "mtxxxx_board_defconfig"

OP-TEE configuration

OP-TEE DRAM Size Configuration

Use already existing SoC-matching machine config if no changes are to be added (jump to step 4).

Important

The OP-TEE DRAM size must be equal to the DRAM size configured in kernel device tree.

    1. (Optional) If the DRAM size is large than 4GB, set CFG_CORE_ARM64_PA_BITS,36 in <OP-TEE>/core/arch/arm/plat-mediatek/conf.mk.

optee-os
└── core
    └── arch
        └── arm
            └── plat-mediatek
                └── conf.mk
ifeq ($(PLATFORM_FLAVOR),<platform_name>)
$(call force,CFG_CORE_ARM64_PA_BITS,36)
endif
    1. Patch optee-os sources and add the patch to meta-<board_name>/recipes-security/optee-os/files/.

    1. Add the patch PATH to SRC_URI variable in meta-<board_name>/recipes-security/optee-os/optee-os_%.bbappend.

meta-<board_name>
├──recipes-security
│   └── optee-os
│       ├── files/                 # patches to add board support
│       └── optee-os_%.bbappend    # add DRAM PA bits patch
    1. Set OPTEE_DRAM_SIZE variable in <machine_name>.conf

    meta-<board_name>
    ├── conf
    │   ├── machine
    │   │   └── <machine_name>.conf    #
    │   ├── layer.conf                 #
    │   ├── local.conf.sample          #
    │   └── bblayers.conf.sample       #
...
With 2GB of DRAM use :
OPTEE_DRAM_SIZE = "0x80000000"  # meaning '0x000000080000000'.
With 8GB of DRAM use :
OPTEE_DRAM_SIZE = "0x200000000"  # meaning '0x0000000200000000'.

Kernel Configurations

Kernel Device Tree

Kernel device tree should be added to arch/arm64/boot/dts/mediatek/ in kernel source tree.

    1. Create a device tree file <mtxxxx-board_name>.dts

    1. Refer to already existing device tree with the same SoC

    1. Include necessary .dtsi file and configure RAM size

memory@40000000 {
    device_type = "memory";
    reg = <0 0x40000000 0 0x80000000>;
};
    1. Do pin muxing and emmc configuration, such as frequency.

    1. Add <mtxxxx-board_name>.dtb to arch/arm64/boot/dts/mediatek/Makefile

dtb-$(CONFIG_ARCH_MEDIATEK) += <mtxxxx-board_name>.dtb
    1. Patch kernel sources and add the patch to meta-<board_name>/recipes-kernel/linux-mtk/files/.

    1. Add the patch path to SRC_URI variable in meta-<board_name>/recipes-kernel/linux-mtk/linux-mtk_%.bbappend.

meta-<board_name>
├── recipes-kernel
│   └── linux-mtk
│       ├── files/                 # patches to add device-tree kernel modification and configuration
│       └── linux-mtk_%.bbappend   # apply the patches to linux kernel

Kernel Configuration

The kernel configuration used by yocto is a merge of the Linux ARM64 defconfig in arch/arm64/configs/defconfig and config fragments that can be found in recipes-kernel/linux-mtk/files.

Note

Please refer to Add extra kernel configuration and Kernel Development in order to add extra kernel configuration.

Yocto and Image customization

Add new prebuilt so/ko for drivers

  • In recipes-kernel/, create <module_name>/src folder and add <module_name>.ko.

  • Create a recipe file <recipe_name>.bb in meta-<board_name>/recipes-kernel/<module_name>/ in order to add the module to SRC_URI variable.

meta-<board_name>
├── recipes-kernel
│   ├── linux-mtk
│   │   ├── files/                 # patches to add device-tree kernel modification and configuration
│   │   └── linux-mtk_%.bbappend   # apply the patches to linux kernel
│   │
│   └── <module_name>
│       ├── src/
│       │    └── <module_name>.ko
│       │
│       └── <recipe_name>.bb
...

An example of what the recipe may look like:

SUMMARY = "Example of how to add prebuilt module"
DESCRIPTION = "${SUMMARY}"

FILESEXTRAPATHS:prepend := "${THISDIR}/src:"

inherit linux-kernel-base

S = "${WORKDIR}"

SRC_URI = "file://<module_name>.ko\"

S = "${WORKDIR}"

do_install() {
        install -m 755 ${S}/<module_name>.ko
}

Add extra kernel configuration

In order to add extra kernel configuration:

  • Add new <board>.cfg in meta-<board_name>/recipes-kernel/linux-mtk/files/.

  • Create linux-mtk_%.bbappend in meta-<board_name>/recipes-kernel/linux-mtk/.

meta-<board_name>
├── recipes-kernel
│   └── linux-mtk
│       ├── files/                 # config files and patches to add device-tree kernel modification and configuration
│       │   └── <board>.cfg
│       └── linux-mtk_%.bbappend   # apply the patches to linux kernel
...
  • Append <board>.cfg to SRC_URI variable in linux-mtk_%.bbappend.

FILESEXTRAPATHS:prepend := "${THISDIR}/files:"
SRC_URI:append = " \
        file://<board>.cfg \
    "

Layer configuration

Detailed explanation is given in Create your own layer section.

  • Add the created layer to meta-<board_name>/conf/bblayers.conf.sample.

Example of bblayers.conf.sample
# POKY_BBLAYERS_CONF_VERSION is increased each time build/conf/bblayers.conf
# changes incompatibly
POKY_BBLAYERS_CONF_VERSION = "2"

BBPATH = "${TOPDIR}"
BBFILES ?= ""

BBLAYERS ?= " \
    ##OEROOT##/meta \
    ##OEROOT##/meta-poky \
    ##OEROOT##/meta-yocto-bsp \
    ##OEROOT##/../meta-arm/meta-arm \
    ##OEROOT##/../meta-arm/meta-arm-toolchain \
    ##OEROOT##/../meta-mediatek-bsp \
    ##OEROOT##/../meta-openembedded/meta-oe \
    ##OEROOT##/../meta-openembedded/meta-python \
    ##OEROOT##/../meta-rity/meta \
    ##OEROOT##/../meta-rity/meta-rity-bringup \
    ##OEROOT##/../meta-<board_name> \
"
  • Add meta-<board_name>/conf/layer.conf file and set layer information, priority, dependency …

Example of layer.conf
# We have a conf and classes directory, add to BBPATH
BBPATH .= ":${LAYERDIR}"

# We have recipes-* directories, add to BBFILES
BBFILES += "${LAYERDIR}/recipes-*/*/*.bb ${LAYERDIR}/recipes-*/*/*.bbappend"

BBFILE_COLLECTIONS += "<board_name>"
BBFILE_PATTERN:<board_name> = "^${LAYERDIR}/"
BBFILE_PRIORITY:<board_name> = "12"

# This should only be incremented on significant changes that will
# cause compatibility issues with other layers
LAYERVERSION:<board_name> = "1"

LAYERDEPENDS:<board_name> = ""

# Yocto 3.1, codename: Dunfell (LTS)
# Yocto 3.2, codename: Gatesgarth (Stable)
# Yocto 3.3, codename: Hardknott (Stable)
LAYERSERIES_COMPAT:<board_name> = "dunfell"

Adjust storage partition

  • Add custom.wks.in to meta-<board_name>/wic/.

        meta-<board_name>
        └── wic
            └── custom.wks.in              # Partitioning
  • Add the wks file to meta-<board_name>/conf/local.conf.sample

WKS_FILE:forcevariable = "custom.wks.in"

An example of image partitioning :

# SHORT-description: Create an image for MediaTek SoC based boards
# long-description: Creates a partitioned image for MediaTek SoC based boards.

bootloader --ptable gpt --timeout=0
part --source rawcopy --sourceparams="file=fip.bin" --part-name bootloaders --align 512 --fixed-size 4M
part --source rawcopy --sourceparams="file=fitImage" --part-name kernel --size 15M
part / --source rootfs --fstype=ext4 --label rootfs --part-name rootfs --part-type B921B045-1DF0-41C3-AF44-4C6F280D3FAE --active --exclude-path=home/
part /home --source rootfs --rootfs-dir=${IMAGE_ROOTFS}/home --fstype=ext4 --label home --part-name home --part-type 933AC7E1-2EB4-4F13-B844-0E14E2AEF915 --use-uuid --size ${IMAGE_HOME_SIZE} --mkfs-extraopts "-b ${WIC_BLOCK_SIZE}"

Note

For further information about using wic, please refer to Yocto documentation :

Yocto Documentation

Please see ‘ Frequently Asked Questions ‘ section to change rootfs / home size ..

Memory reserved regions

The size of memory reserved regions used by IoT Yocto SDK is not mandatory to be changed. The memory mapping for MT8395(Genio 1200), MT8390(Genio 700) and MT8365(Genio 350) are shown as follows:

../../_images/sw_yocto_board-bringup_mem.png

For example if you would like to adjust the TF-A(BL31) start address and size, you could find the definition in trusted-firmware-a source and dts:

#define TZRAM_BASE          (0x54600000)
#define TZRAM_SIZE          (0x00200000)
bl31_secmon_reserved: secmon@54600000 {
        no-map;
        reg = <0 0x54600000 0x0 0x200000>;
};

For example if you would like to adjust the OP-TEE(BL32), you could find the definition in trusted-firmware-a source, dts and machine configurations in meta-mediatek-bsp layer:

#define BL32_BASE              (0x43200000)
#define BL32_LIMIT             (0x00c00000)
optee_reserved: optee@43200000 {
        no-map;
        reg = <0 0x43200000 0 0x00c00000>;
};
OPTEE_TZDRAM_START ?= "0x43200000"
OPTEE_TZDRAM_SIZE  ?= "0x00c00000"

You might need to change the memory reserved regions to fit the kernel size changes during development. The default memory address for Genio 1200, Genio 700 and Genio 350 are aligned to 0x64000000, but this is not mandatory and can be adjusted to fit the size of your kernel. The default configuration of IoT Yocto allows kernel to be relocated. If you would like to adjust the Linux Kernel, you could find the definition in meta-mediatek-bsp layer:

UBOOT_ENTRYPOINT       = "0x64000000"
UBOOT_LOADADDRESS      = "0x64000000"
  • When the kernel size is too big, the error messages could happen as follows:

ERROR: reserving fdt memory region failed (addr=43200000 size=c00000 flags=4)

Note

Please make sure the start address and size of memory reserved regions could not overlap.

Testing Memory Region Configuration

If you’ve updated the resered region settings in board DTS or in bootloader, we recommend you to check for the consistency of memory region settings between bootloader and kernel.

Therefore, you should run the kernel memtest after any memory configuration update. To run kernel memtest, you can:

  1. Make sure the kernel config CONFIG_MEMTEST=y is set to enabeld.

  2. Add a kernel boot commandline parameter memtest=1. You can do this in U-Boot console, or use the fw_setenv utility:

    fw_setenv bootargs "memtest=1"
    reboot
    
  3. Reboot the system, and during kernel startup, a kernel message early_memtest should appear:

    [    0.000000] early_memtest: # of tests: 2
    [    0.000000]   0x0000000040000000 - 0x0000000043200000 pattern ffffffffffffffff
    [    0.000000]   0x0000000043e00000 - 0x0000000050000000 pattern ffffffffffffffff
    [    0.000000]   0x0000000052900000 - 0x0000000053000000 pattern ffffffffffffffff
    [    0.000000]   0x0000000054400000 - 0x0000000054600000 pattern ffffffffffffffff
    [    0.000000]   0x0000000054800000 - 0x0000000060000000 pattern ffffffffffffffff
    

    If you see bad mem addr, then this might indicate an incorrect DRAM configuration, or mismatched memory region between bootloader and kernel:

    [    0.000000]   ffffffffffffffff bad mem addr 0x0000000054800740 - 0x0000000054800780 reserved
    [    0.000000]   ffffffffffffffff bad mem addr 0x00000000548009c0 - 0x0000000054800a00 reserved
    [    0.000000]   ffffffffffffffff bad mem addr 0x0000000054800fc0 - 0x0000000054801000 reserved
    [    0.000000]   ffffffffffffffff bad mem addr 0x0000000054801540 - 0x0000000054801580 reserved
    [    0.000000]   ffffffffffffffff bad mem addr 0x0000000054801740 - 0x0000000054801780 reserved
    [    0.000000]   ffffffffffffffff bad mem addr 0x0000000054801880 - 0x00000000548018c0 reserved
    

Boot process (systemd) customization

Enable Systemd

Add the following lines to enable systemd by default:

meta-<board_name>
├── conf
│   ├── machine
│   │   └── <machine_name>.conf    #
│   ├── layer.conf                 #
│   ├── local.conf.sample          #
│   └── bblayers.conf.sample       #
DISTRO_FEATURES_append = " systemd"
DISTRO_FEATURES_BACKFILL_CONSIDERED += "sysvinit"
VIRTUAL-RUNTIME_init_manager = "systemd"
VIRTUAL-RUNTIME_initscripts = "systemd-compat-units"

Add Systemd Services File

  • Create meta-<board_name>/recipes-core/systemd/files

  • Add service files <service_name>,service to /files

  • Add systemd_%.bbappend recipe to integrate the service to systemd configuration.

 meta-<board_name>
 ├── recipes-core
 │   └── systemd
 │       ├── files/
 │       │   └── <service_name>.service
 │       └── systemd_%.bbappend
...

Hardware documentation

Please refer to MediaTek Online or request hardware documentation from your MediaTek contact window.