# Customize

Source: [https://docs.qualcomm.com/doc/80-70014-3/topic/customize.html](https://docs.qualcomm.com/doc/80-70014-3/topic/customize.html)

The SoC and board device tree support is hosted in the kernel source at
                `arch/arm64/boot/dts/qcom`.

## Kernel development

Source: [https://docs.qualcomm.com/doc/80-70014-3/topic/customize.html](https://docs.qualcomm.com/doc/80-70014-3/topic/customize.html)

Use the following kernel recipes to customize the kernel and generate patches during
        kernel development:

# setup the workspace and get the sources following build guide
    # setup the environment
     
    $ MACHINE=qcm6490 DISTRO=qcom-wayland source setup-environment
     
    # create your own layer to host changes
    $ bitbake-layers create-layer ~/meta-mylayer
    $ bitbake-layers add-layer ~/meta-mylayer
     
    # use devtool to setup kernel source for development
    $ devtool modify linux-kernel-qcom
     
    # do the development , commit changes, build and test
    $ devtool build linux-kernel-qcom
    $ devtool build-image qcom-console-image
     
    # built images are produced in standard location
    $ ls build-qcom-wayland/tmp-glibc/deploy/images/qcm6490/
     
    # generate the patches and update layer
    $ devtool finish linux-kernel-qcom ~/meta-mylayerCopy to clipboard

For more information on customizing the Qualcomm Linux kernel recipe, see [Kernel recipe](https://docs.qualcomm.com/doc/80-70014-3/topic/yocto-kernel-support.html#kernel-recipe).

For information on Yocto provisions, host patches, and how to apply them, see [Yocto Project Linux Kernel Development](https://docs.yoctoproject.org/1.5/kernel-dev/kernel-dev.html#applying-patches).

## Kernel configurations

Source: [https://docs.qualcomm.com/doc/80-70014-3/topic/customize.html](https://docs.qualcomm.com/doc/80-70014-3/topic/customize.html)

Yocto build system is used for modifying the kernel configuration, while invoking
            `menuconfig`.

Run the following commands to modify the kernel
            configuration:

    $ MACHINE=qcm6490 DISTRO=qcom-wayland source setup-environment
    $ bitbake linux-kernel-qcom -c menuconfig
     
    # Above would update .config in kernel build directory build-qcom-wayland/tmp-glibc/work/qcm6490-qcom-linux/linux-kernel-qcom/6.6-r0/build/
    # one can create a config fragment for modifications made by issuing following
     
    $ bitbake linux-kernel-qcom -c diffconfig
     
    # Above would create fragment.cfg in build directory build-qcom-wayland/tmp-glibc/work/qcm6490-qcom-linux/linux-kernel-qcom/6.6-r0/
     Copy to clipboard

Alternatively, use the Devtool to modify the kernel
            configuration:

    $ devtool modify linux-kernel-qcom
    $ devtool menuconfig linux-kernel-qcom
    $ devtool finish linux-kernel-qcom ~/meta-mylayer
     
    # this would create a config fragment as a patch and update in your meta layerCopy to clipboard

For information on Yocto related details on kernel configuration, see [Configuring the Kernel](https://docs.yoctoproject.org/4.3.1/kernel-dev/common.html#configuring-the-kernel).

## Debug builds

Source: [https://docs.qualcomm.com/doc/80-70014-3/topic/customize.html](https://docs.qualcomm.com/doc/80-70014-3/topic/customize.html)

Pass `DEBUG_BUILD=1` as an argument in the shell command prompt to
        create a debug build:

# setup the build environment
    $ export SHELL=/bin/bash
     
    $ MACHINE=qcm6490 DISTRO=qcom-wayland source setup-environment
     
    # build qcom linux console image
    $ DEBUG_BUILD=1 bitbake qcom-console-imageCopy to clipboard

## Update kernel command line

Source: [https://docs.qualcomm.com/doc/80-70014-3/topic/customize.html](https://docs.qualcomm.com/doc/80-70014-3/topic/customize.html)

To update the kernel command line, modify the target-specific
            (`qcm6490.conf`) Yocto machine configuration variable
            `KERNEL_CMDLINE_EXTRA` in the corresponding machine configuration
        file.

For example, `./layers/meta-qcom-hwe/conf/machine/qcm6490.conf`.

To update the kernel command line, modify/append the following
            variable:

    KERNEL_CMDLINE_EXTRA = "root=/dev/disk/by-partlabel/system rw rootwait console=ttyMSM0,115200n8 pcie_pme=nomsi earlycon"Copy to clipboard

## Platform support

Source: [https://docs.qualcomm.com/doc/80-70014-3/topic/customize.html](https://docs.qualcomm.com/doc/80-70014-3/topic/customize.html)

Use the following procedure to update the DTB support in the kernel and select DTB on
        boot.

**DTB build support in kernel**

The device tree for a new platform can be integrated into the kernel build by updating
            the `Makefile`.

    diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile
    index 183aeba47193..a7815c774f7c 100644
    --- a/arch/arm64/boot/dts/qcom/Makefile
    +++ b/arch/arm64/boot/dts/qcom/Makefile
     dtb-$(CONFIG_ARCH_QCOM)        += qcm6490-addons-rb3gen2.dtb
    +dtb-$(CONFIG_ARCH_QCOM)        += qcm6490-my-board.dtb
     dtb-$(CONFIG_ARCH_QCOM)        += qcm6490-rb3gen2.dtb
     dtb-$(CONFIG_ARCH_QCOM)        += qcs404-evb-1000.dtbCopy to clipboard

**DTB inclusion in machine configuration**

The Yocto machine configuration is also updated to include the corresponding device tree
            blob. For example, to add the device tree for QCM6490 machine support use the following
            file
            `conf/machine/qcm6490.conf`:

    OUT_OF_KERNEL_DTSO - qcm6490.conf
    # List of dtbs for corresponding supported qcm6490 platforms
    KERNEL_DEVICETREE = " \ 
                          qcom/qcm6490-my-board.dtb   \
                          qcom/qcm6490-addons-rb3gen2.dtb \
                          qcom/qcm6490-my-board.dtb   \
                          "

    # Do note additional list of dtbos to be overylaid on top of base kernel devicetree
    # Refer below how existing boards are managing it
    # Format - KERNEL_TECH_DTBOS[<base-dtb-name>] = "<dtbo1 <dtbo2> ..."
     
    KERNEL_TECH_DTBOS[qcm6490-addons-rb3gen2] = "qcm6490-graphics.dtbo qcm6490-wlan-rb3gen2.dtbo qcm6490-display-rb3gen2.dtbo qcm6490-bt.dtbo"Copy to clipboard

**DTB selection on boot**

Custom DTB can be packaged as a part of the UKI image that can be updated in EFI to boot
            with the selected DTB.

Generate a UKI image using the ukify tool. The ukify tool is available as part of the
            Yocto build in the
                `tmp-glibc/sysroots-components/x86_64/systemd-boot-native/usr/bin/ukify`
            build directory.

Do the following to generate the UKI image:

# Note - ukify tool need python 3.10 version or above
     
    $ ukify build --efi-arch=aa64  \
                  --stub=<build-path>/tmp-glibc/deploy/images/qcm6490/linuxaa64.efi.stub \
                  --linux=<build-path>/tmp-glibc/deploy/images/qcm6490/Image \
                  --initrd=<build-path>/tmp-glibc/deploy/images/qcm6490/initramfs-qcom-image-qcm6490.cpio.gz \
                  --cmdline="console=ttyMSM0,115200n8 earlycon qcom_geni_serial.con_enabled=1 kernel.sched_pelt_multiplier=4 mem_sleep_default=s2idle" \
                  --devicetree=<build-path>/tmp-glibc/deploy/images/qcm6490/qcm6490-my-board.dtb \
                  --output=./uki.efiCopy to clipboard

The ukify build command generates the `uki.efi` image with a custom board
            DTB.

Do the following to update the `uki.efi` image in the ESP partition
                `efi.bin` image.

    # Following may need sudo privilege
     
    # Take the yocto build generated efi.bin and mount it locally
    $ mount <build-path>/tmp-glibc/deploy/images/qcm6490/efi.bin  /mnt --options rw
     
    # Overwrite the uki.efi with one packaged above
    $ cp uki.efi /mnt/EFI/Linux/uki.efi
    $ umount /mnt
     
    # now efi.bin carries packaged uki.efi which can be flashed to the target and booted
    # UEFI shall now pick the qcm6490-my-board.dtb that is part of uki.efi image
     
    # reboot into fastboot and flash efi.bin
    $ fastboot flash efi <build-path>/tmp-glibc/deploy/images/qcm6490/efi.binCopy to clipboard

For more information on the device tree specification, see [The
                Devicetree Specification](https://www.devicetree.org/specifications/).

For Linux kernel documentation for device tree, see [Linux and the Devicetree](https://docs.kernel.org/devicetree/usage-model.html).

## Update ESP with images

Source: [https://docs.qualcomm.com/doc/80-70014-3/topic/customize.html](https://docs.qualcomm.com/doc/80-70014-3/topic/customize.html)

Use the following steps to compile the systemd-boot boot manager and kernel images
        into a packaged UKI type-2 image file.

Yocto build for QCM6490 generates all the required images and package boot images as
                `efi.bin` that can be flashed in an EFI partition.
                `efi.bin` file consists of systemd-boot boot manager and kernel
            images, which are packaged as UKI type-2 image format.

Rebuild the EFI image after updating the kernel source, configuration, or DTS and flash
            the generated `efi.bin` to the EFI partition.

    $ MACHINE=qcm6490 DISTRO=qcom-wayland source setup-environment
     
    # build qcom linux console image
    $ DEBUG_BUILD=1 bitbake qcom-console-image
     
    # build images are produced in following directory
    $ ls build-qcom-wayland/tmp-glibc/deploy/images/qcm6490/efi.bin
    efi.bin
     
    # reboot into fastboot
    $ fastboot flash efi efi.binCopy to clipboard

For more information on the UKI type-2 image format, see Type #2 [EFI Unified Kernel Images](https://uapi-group.org/specifications/specs/boot_loader_specification/#type-2-efi-unified-kernel-images).

For information on ESP, see [Boot](https://docs.qualcomm.com/doc/80-70014-3/topic/features.html#boot).

## Customize initramfs

Source: [https://docs.qualcomm.com/doc/80-70014-3/topic/customize.html](https://docs.qualcomm.com/doc/80-70014-3/topic/customize.html)

Modify the `PACKAGE_INSTALL` list in
            `meta-qcom-hwe/recipes-kernel/images/initramfs-qcom-image.bbappend` to
        update the initramfs package.

Use the following steps to update the initramfs package:

$ less meta-qcom-hwe/recipes-kernel/images/initramfs-qcom-image.bbappend
     
    # Add additional packages needed as part of initrd
    PACKAGE_INSTALL += " \ 
        e2fsprogs \
        e2fsprogs-e2fsck \
        e2fsprogs-mke2fs \
        e2fsprogs-resize2fs \
        e2fsprogs-tune2fs \
        ${VIRTUAL-RUNTIME_dev_manager} \
        os-release-initrd \
        "Copy to clipboard

## Add kernel module

Source: [https://docs.qualcomm.com/doc/80-70014-3/topic/customize.html](https://docs.qualcomm.com/doc/80-70014-3/topic/customize.html)

Use the following procedure to compile out-of-tree kernel modules using the Yocto
        build system.

Sample `Makefile` for out-of-tree kernel
            driver:

    all: modules
    obj-m := hello.o
     
    SRC := $(shell pwd)
     
    modules:
        $(MAKE) -C $(KERNEL_SRC) M=$(SRC) modules $(KBUILD_OPTIONS)
     
    modules_install:
        $(MAKE) -C $(KERNEL_SRC) M=$(SRC) modules_installCopy to clipboard

These kernel modules are integrated to the Yocto build using recipes that use the
            standard Yocto module
            class.

    DESCRIPTION = "${SUMMARY}"
    LICENSE = "GPL-2.0-only"
    LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/${LICENSE};md5=801f80980d171dd6425610833a22dbe6"
     
    inherit module
     
    SRC_URI += "file://Makefile \
                file://hello.c  \
                file://COPYING  \
               "
    S = "${WORKDIR}"
     
    EXTRA_OEMAKE += "MACHINE='${MACHINE}'"
    MAKE_TARGETS = "modules"
    MODULES_INSTALL_TARGET = "modules_install"
     
    # Kernel module to be autoloaded
     KERNEL_MODULE_AUTOLOAD += "hello"
     
    # The inherit of module.bbclass will automatically name module packages with
    # "kernel-module-" prefix as required by the oe-core build environment.
     
    RPROVIDES_${PN} += "kernel-module-hello"Copy to clipboard

For more information on the out-of-tree module, see [Working with Out-of-Tree Modules](https://docs.yoctoproject.org/kernel-dev/common.html#working-with-out-of-tree-modules).

## Disable console log

Source: [https://docs.qualcomm.com/doc/80-70014-3/topic/customize.html](https://docs.qualcomm.com/doc/80-70014-3/topic/customize.html)

Disable the kernel console logging in the following ways:

1. Update the kernel command line with `quiet`. 
    For more information
                    on kernel parameters, see [The kernel's command-line
                    parameters](https://www.kernel.org/doc/html/latest/admin-guide/kernel-parameters.html).
2. Disable `CONFIG_SERIAL_EARLYCON` and
                    `CONFIG_SERIAL_MSM_CONSOLE` in the kernel configuration.
3. Add the `console=null` parameter to the kernel command line
                arguments.

## Pinctrl configuration

Source: [https://docs.qualcomm.com/doc/80-70014-3/topic/customize.html](https://docs.qualcomm.com/doc/80-70014-3/topic/customize.html)

The Pinctrl subsystem in the Linux kernel manages and configures pins used for
        general-purpose input/output (GPIO), interintegrated circuit (I2C), serial peripheral
        interface (SPI), and other hardware interfaces.

Pinctrl configurations, such as **pin muxing** and **pin groupings**, are managed
            in the device-specific pinctrl drivers, where the drivers list all the available pins
            and functions.

For example, the corresponding driver for QCM6490 is available in the

`kernel-src/drivers/pinctrl/qcom/pinctrl-sc7280.c` file.

The following are the data objects:

Table : Pinctrl data objects

| Variable | Description |
| --- | --- |
| static const struct pinctrl_pin_desc sc7280_pinsCopy to clipboard | Enumerates all pins and their names. |
| static const struct msm_pingroup sc7280_groupsCopy to clipboard | Defines the available muxed functions for the group of<br>                            general-purpose input/output (GPIO) pins. |
| enum sc7280_functionsCopy to clipboard | Lists all the available functions as enum values. |

For more information on the supported functions of the respective SoC pinctrl binding
            documentation for QCM6490, see [pinctrl binding documentation](https://www.kernel.org/doc/Documentation/devicetree/bindings/pinctrl/qcom%2Csc7280-pinctrl.yaml).

**Function selection**

For a `sc7280_functions` data object, one or multiple GPIO pins are used
            as a function and must be registered to the device tree and passed to the right device
            node.

During system boot, the kernel pinctrl infrastructure registers the functions.

The following example shows the kernel configuration
            infrastructure:

    tlmm: pinctrl@f100000 {
        compatible = "qcom,sc7280-pinctrl";
        :
        :
        :  
        :
        qup_spi0_data_clk: qup-spi0-data-clk-state {
            pins = "gpio0", "gpio1", "gpio2";
            function = "qup00";
        };
     
        qup_spi0_cs: qup-spi0-cs-state {
            pins = "gpio3";
            function = "qup00";
        };
     
        qup_spi1_data_clk: qup-spi1-data-clk-state {
            pins = "gpio4", "gpio5", "gpio6";
            function = "qup01";
        };
     
        qup_spi1_cs: qup-spi1-cs-state {
            pins = "gpio7";
            function = "qup01";
        };
        :
        :
        :  
        :
      
    };

     spi0: spi@980000 {
         compatible = "qcom,geni-spi";
         reg = <0 0x00980000 0 0x4000>;
         clocks = <&gcc GCC_QUPV3_WRAP0_S0_CLK>;
         clock-names = "se";
         pinctrl-names = "default";
         pinctrl-0 = <&qup_spi0_data_clk>, <&qup_spi0_cs>;
         interrupts = <GIC_SPI 601 IRQ_TYPE_LEVEL_HIGH>;
         #address-cells = <1>;
         #size-cells = <0>;
         power-domains = <&rpmhpd SC7280_CX>;
         operating-points-v2 = <&qup_opp_table>;
         interconnects = <&clk_virt MASTER_QUP_CORE_0 0 &clk_virt SLAVE_QUP_CORE_0 0>,
                 <&gem_noc MASTER_APPSS_PROC 0 &cnoc2 SLAVE_QUP_0 0>;
         interconnect-names = "qup-core", "qup-config";
         dmas = <&gpi_dma0 0 0 QCOM_GPI_SPI>,
                <&gpi_dma0 1 0 QCOM_GPI_SPI>;
         dma-names = "tx", "rx";
         status = "disabled";
     };Copy to clipboard

## General GPIO usage

Source: [https://docs.qualcomm.com/doc/80-70014-3/topic/customize.html](https://docs.qualcomm.com/doc/80-70014-3/topic/customize.html)

GPIO pin configuration requires the following two settings:

The settings define a GPIO pin state and make those pins available for any input/output
            activity.

- Mux: The mux setting requires selecting the function name that is mapped from the
                set of available functions in the target-specific pinctrl driver.
    For more
                    information on pinctrl, see [Pinctrl configuration](https://docs.qualcomm.com/doc/80-70014-3/topic/customize.html#pinctrl-configuration).
- Configuration: The configuration aspect requires setting the drive-strength and bias
                property.

The following examples show how the two settings define the GPIO pin:

1. Define the pin configuration in the device tree using the following
                    procedure:

        bt_en: bt-en-state {
            pins = "gpio85";
            function = "gpio";
            output-low;
            bias-disable;
        };Copy to clipboard
2. Use the following procedure to configure the device node or intellectual
                    property (IP) block in the device
                    tree:

        bluetooth: bluetooth {
             compatible = "qcom,wcn6750-bt";
             pinctrl-names = "default";
             pinctrl-0 = <&bt_en>, <&sw_ctrl>;
             enable-gpios = <&tlmm 85 GPIO_ACTIVE_HIGH>;
             swctrl-gpios = <&tlmm 86 GPIO_ACTIVE_HIGH>;
             vddaon-supply = <&vreg_s7b_0p9>;
             vddbtcxmx-supply = <&vreg_s7b_0p9>;
             vddrfacmn-supply = <&vreg_s7b_0p9>;
             vddrfa0p8-supply = <&vreg_s7b_0p9>;
             vddrfa1p7-supply = <&vreg_s1b_1p8>;
             vddrfa1p2-supply = <&vreg_s8b_1p2>;
             vddrfa2p2-supply = <&vreg_s1c_2p2>;
             vddasd-supply = <&vreg_l11c_2p8>;
             max-speed = <3200000>;Copy to clipboard
3. The driver code must use generic APIs to select and register their GPIO
                    configurations within the pinctrl configurations.
    The following is an example
                        of available APIs:

        devm_gpiod_get_optional(&serdev->dev, "enable", GPIOD_OUT_LOW);
         
        /**
         * devm_gpiod_get_optional - Resource-managed gpiod_get_optional()
         * @dev: GPIO consumer
         * @con_id: function within the GPIO consumer
         * @flags: optional GPIO initialization flags
         *
         * Managed gpiod_get_optional(). GPIO descriptors returned from this function
         * are automatically disposed on driver detach. See gpiod_get_optional() for
         * detail
         
        /**
        * gpiod_get_value_cansleep() - return a gpio's value
        * @desc: gpio whose value will be returned
        *
        * Return the GPIO's logical value, i.e. taking the ACTIVE_LOW status into
        * account, or negative errno on failure.
        *
        * This function is to be called from contexts that can sleep.
        gpiod_set_value_cansleep(qcadev->bt_en, 0);/**
        * gpiod_set_value_cansleep() - assign a gpio's value
        * @desc: gpio whose value will be assigned
        * @value: value to assign
        *
        * Set the logical value of the GPIO, i.e. taking its ACTIVE_LOW status into
        * account
        *
        * This function is to be called from contexts that can sleep.Copy to clipboard

**GPIO as interrupt request (IRQ)**

Use the following procedure to set the GPIO as an IRQ:

1. Configure the GPIO pin in the DTS file:
    1. Set the properties and the function for the GPIO pin.
    2. Set the pin to use GPIO 55 for `qup_se_l3()` function
                            with the following
                            configurations:

            qupv3_se3_rx: qupv3-se3-rx-state {
                pins = "gpio55";
                function = "qup03"; // To be taken from available from functions.
                drive-strength = <2>;
                bias-disable;
            };Copy to clipboard
2. Create a DT entry like the previous configuration for the device node where the
                    GPIO must be set as an IRQ. 
    In the following example, the GPIO55 is
                        configured as an IRQ with the parent being a top-level mode multiplexer
                        (TLMM) and the level is set to
                    high.

        interrupts-extended = <&tlmm 55 IRQ_TYPE_LEVEL_HIGH>;Copy to clipboard
3. The driver must read the value and register it as an interrupt to the generic
                    interrupt controller (GIC) using the `request_irq` API specifying
                    the interrupt service register (ISR) and IRQ flags.

        irq_no = platform_get_irq(pdev, 1);Copy to clipboard

## ZRAM as swap

Source: [https://docs.qualcomm.com/doc/80-70014-3/topic/customize.html](https://docs.qualcomm.com/doc/80-70014-3/topic/customize.html)

ZRAM is a compressed swap mechanism that creates a virtual block device in RAM. ZRAM
        is enabled as a module within the kernel defconfig.

ZRAM is configured in the Yocto build in the
                `recipes-extended/zram/zram/zram-swap-init-update` file.

To enable or configure ZRAM, do the following:

    # check if zram module is loaded
    $ lsmod | grep zram
     
    # else load it
    $ modprobe zram
     
    # Configure /dev/zram0 size as per your RAM size
    $ echo 128M > /sys/block/zram0/disksize
     
    # activate swap
    $ mkswap /dev/zram0
    $ swapon /dev/zram0Copy to clipboard

To configure ZRAM as a swap device, see [zram: Compressed RAM-based block devices](https://www.kernel.org/doc/html/v6.6/admin-guide/blockdev/zram.html).

## Extend memory map

Source: [https://docs.qualcomm.com/doc/80-70014-3/topic/customize.html](https://docs.qualcomm.com/doc/80-70014-3/topic/customize.html)

To extend the memory map, adjust the addresses and sizes of memory regions in a DTSI
        file.

Use the following information to extend the carved out regions:

Add the carved out region in the
                `arch/arm64/boot/dts/qcom/<target>.dtsi` file in the
                **reserved-memory** node with the following
            syntax:

    my_carveout_mem: my_carveout_mem@address {
          reg= <0x0 0xbase_address 0x0 0xsize>;
          no-map;
    }Copy to clipboard

For example:

    my_carveout_mem: my_carveout_mem@d0800000 {
           reg= <0x0 0xd0800000 0x0 0x100000>;
           no-map;
    }Copy to clipboard

Table : Syntax for carved out region

| Variable | Description |
| --- | --- |
| my_carveout_mem@d0800000Copy to clipboard | Indicates the name of the device node. The convention mandates that<br>                            you append the base address of the memory region to the name. |
| my_carveout_memCopy to clipboard | Indicates the label assigned to this node that can be used to<br>                            reference this node from within the other nodes in the device tree using<br>                            phandles. |
| regCopy to clipboard | Indicates the property, which is a 64‑bit value that defines the base<br>                            and size of the memory region. |
| no-mapCopy to clipboard | Indicates that this region is carved out and the kernel should remove<br>                            the mapping from its addressable range. |

Note:
1. None of the regions should overlap. In case a region size must be increased, all
                    other subsequent regions must be shifted, and configured in the device tree to
                    avoid overlapping.
2. The kernel expects all memory region boundaries defined for kernel usage to be
                    1 MB.
3. Existing carved out regions are protected by trusted firmware from kernel
                    access. Decreasing their size or deleting them may result in an external abort,
                    leading to a kernel crash.

**Add CMA region**

To add the CMA region in the `arch/arm64/boot/dts/qcom/<target>.dtsi`
            file under **reserved-memory** node, use the following
            syntax:

    my_cma_mem: my_cma {
        compatible = "shared-dma-pool";
        alloc-ranges = <0x0 0x00000000 0x0 0xffffffff>;
        reusable;
        alignment = <0x0 0x400000>;
        size = <0x0 0x1400000>; 
     };Copy to clipboard

Table : Syntax for adding CMA region

| Parameters | Description |
| --- | --- |
| my_cma_memCopy to clipboard | Label for the CMA node and can be accessed as a phandle. The label<br>                                `my_cma` is the name of the CMA region. |
| shared-dma-poolCopy to clipboard | Indicates that this region is a CMA area. |
| alloc-rangesCopy to clipboard | Indicates if the region should be within a certain memory limit, as<br>                            some devices cannot access memory regions beyond the 32‑bit address<br>                            limit. |
| reusableCopy to clipboard | Indicates that the kernel can use the memory in this region when it<br>                            is free. |
| alignmentCopy to clipboard | Indicates any alignment requirements in this region. |
| sizeCopy to clipboard | Indicates the size of the region. |
| regCopy to clipboard | An optional attribute that indicates the fixed region for memory<br>                            allocation, in the absence of which memory is dynamically allocated at a<br>                            random address. |

## Add custom CMA heaps

Source: [https://docs.qualcomm.com/doc/80-70014-3/topic/customize.html](https://docs.qualcomm.com/doc/80-70014-3/topic/customize.html)

To create custom CMA regions using DMA-BUF heaps, use the existing DMA-BUF framework
        in the Linux kernel.

Qualcomm kernel exports the `cma_heap_add()` API for the custom DMA-BUF
            heaps.

    /**
     * cma_heap_add - adds a CMA heap to dmabuf heaps
     * @cma:       pointer to the CMA pool to register the heap for
     * @data:      unused
     *
     * Returns 0 on success. Else, returns errno.
     */
     
    int cma_heap_add(struct cma *cma, void *data);Copy to clipboard

The DMA-BUF heap exported to the user space, has the same name as the phandle of the CMA
            region in the device tree.

Steps to add a custom CMA heap:

1. To create a custom CMA region, see [Contiguous memory allocator (CMA)](https://docs.qualcomm.com/doc/80-70014-3/topic/features.html#memory__section_szj_szj_51c).
2. In the driver to which you are adding a custom heap:
    1. Parse the device tree for the newly added CMA region.
    2. Add a DMA-BUF heap associated with the
                        driver.

            int create_my_cma_heap(struct device *dev)
            {
                int rc = 0, idx = 0;
                 
                rc = of_reserved_mem_device_init_by_idx(dev, dev->of_node, 0);  // Parse the devicetree for the cma region
                 
                if (rc) {
                        pr_err("No reserved DMA memory, ret=%d\n", rc);
                        rc = -EINVAL;
                        goto err;
                }
                 
                rc = cma_heap_add(dev->cma_area, NULL);  // Add a dmabuf heap associated with the cma region
                 
                if (rc) {
                        pr_err("cma_heap_add failed, ret=%d\n", rc);
                        rc = -EINVAL;
                        goto err;
                }
                 
            err:    
                return rc;
            }    Copy to clipboard

Note: CMA regions must be aligned to the 4 MB address base and size to
            support page migration. The migration happens at  2^pageblock\_order^ pages at
            the page-block level. Page-block order is 10 in Qualcomm Linux.

## Scheduler

Source: [https://docs.qualcomm.com/doc/80-70014-3/topic/customize.html](https://docs.qualcomm.com/doc/80-70014-3/topic/customize.html)

The Qualcomm Linux kernel supports the standard Linux scheduler solution. The kernel
        uses the scheduler to choose the right CPU for task placement based on the CPU energy
        consumption.

### PELT multiplier
In the Linux kernel, the
            PELT half-life multiplier influences how quickly the system adapts to changing workloads
            and adjusts CPU frequencies based on historical utilization data. It is a configuration
            that speeds up the PELT clock and reduces the half-life time, resulting in faster system
            response. 
PELT multiplier is configured through the kernel command line
                    argument:

`kernel.sched_pelt_multiplier=[1, 2, 4] Default value: 1
                    (half life 32 msec), 2 (half life 16msec), 4 (half life
                    8 msec)]`

### Utilization clamping

Utilization clamping is a scheduler feature that allows user space to manage the
                performance requirements of tasks.

Clamping can be done in the following two ways:

- `UCLAMP_MIN`: If it is set to any value `> 0`, the
                    task demand is always greater than or equal to this value. If the actual task
                    demand is more than this value, then the actual demand signal is used, but if
                    the actual task demand is lower than this value, then
                        `UCLAMP_MIN` is reported as the task demand.
- `UCLAMP_MAX`: If it is set to any value `> 0`, the
                    task demand is always less than or equal to this value. If the actual task
                    demand is less than this value, then the actual demand signal is used, but if
                    actual task demand is above this value, then `UCLAMP_MAX` is
                    reported as task demand.

**Note:** `UCLAMP_MAX > UCLAMP_MIN`

- UCLAMP can be used to influence the scheduler's task placement decisions.

On a heterogeneous system, the scheduler uses the task demand or utilization signal
                (PELT signal) to classify a task as small or big. Based on the input from the task
                classification, the scheduler selects small (less computing power) or big (more
                computing power) CPU cores for task placement with a probable impact on power
                consumption.

For example, nonimportant (trivial/background/housekeeping) tasks can be clamped to
                lower values (`lower UCLAMP_MAX`), whereby influencing the scheduler
                to place the tasks on the little cluster. Similarly, important/foreground/active
                tasks can be clamped to higher values (`higher UCLAMP_MIN`) whereby
                influencing the scheduler to place the tasks on the big cluster.

- UCLAMP also supports influencing the frequency guidance by the scheduler.

The task that needs a quick frequency ramp, can be clamped to higher demand
                    (`UCLAMP_MIN`), which helps to ramp up the frequency of the
                cluster to meet the performance requirements of the task.

For more information on the interface and configuration, see [Utilization Clamping](https://www.kernel.org/doc/html/v6.6/scheduler/sched-util-clamp.html).

## Change default CPU frequency governor

Source: [https://docs.qualcomm.com/doc/80-70014-3/topic/customize.html](https://docs.qualcomm.com/doc/80-70014-3/topic/customize.html)

The CPU frequency governor can be changed at runtime or set statically during build
        compilation.

1. Kconfig configuration option: To set the CPU frequency governor, enable the
                corresponding driver in the kernel defconfiguration file. 
    To set
                        `PERFROMANCE` governor as the default CPU frequency governor,
                    set `CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y` in the
                    defconfiguration file.
2. Kernel command line option: To override the kernel configuration option, add a
                    ` cpufreq.default_governor=performance` parameter to the kernel
                command line in the `meta-qcom-hwe/conf/machine/qcm6490.conf` file to
                set the appropriate CPU frequency governor.

## Customize cache and memory DVFS

Source: [https://docs.qualcomm.com/doc/80-70014-3/topic/customize.html](https://docs.qualcomm.com/doc/80-70014-3/topic/customize.html)

The mapping between **CPU frequency** and **L3/DDR frequency** is adjusted
        based on the power or performance requirements.

In DTSI, for each CPUx node, there is an `operating-points-v2 =
                <&cpux_opp_table>` entry. The `cpux_opp_table` holds a
            static mapping between CPU, L3, and DDR frequencies.

For example:

    cpu0_opp_300mhz: opp-300000000 {
        opp-hz = /bits/ 64 <300000000>;
        opp-peak-kBps = <800000 9600000>;
      };Copy to clipboard

When CPU 0 operates at 300 MHz, it votes for 9600000 to L3, which translates to 300,000
            Hz (9600000 / w) L3 frequency. If the vote is for 800,000 Hz to DDR, this results in
            200,000 Hz (800000 / w) DDR frequency.

In the equation, 'w' represents how many bytes can be written in a single cycle:
- For DDR, 'w' is 4 (each channel performs two transactions per cycle, with each
                    transaction being 2 bytes).
- For L3, 'w' is 32 (one transaction per cycle at 32 bytes per transaction).

Note: These values are set per channel for DDR, and the
                mapping relates CPU frequency to memory controller (MC) channel bandwidth. Adjusting
                this map table can impact power and performance characteristics.

For more information on the operating performance points (OPP) framework and syntax, see
                [Generic OPP (Operating Performance Points)
                Bindings](https://www.kernel.org/doc/Documentation/devicetree/bindings/opp/opp.txt).

## Post boot settings

Source: [https://docs.qualcomm.com/doc/80-70014-3/topic/customize.html](https://docs.qualcomm.com/doc/80-70014-3/topic/customize.html)

Post boot settings comprise completing initial setup, configuring memory, and CPU
        frequency parameters. These steps ensure proper configuration and functionality after the
        system boots up.

### Post boot framework

A post boot script file is used to configure system parameters on the Qualcomm Linux
                distribution.

Postboot settings are managed through a *systemd service* file.

For more information on systemd, see [systemd(1) - Linux manual page](https://www.man7.org/linux/man-pages/man1/systemd.1.html).

### What is a systemd service?

A systemd service is a background process that starts or stops based on specific
                conditions.

A `systemd service` file is written to allow systemd to parse,
                understand, and execute as instructed.

For more information on the background process, see [background process](https://linuxhandbook.com/run-process-background/).

### Basic structure of systemd service file

Use the following procedure to modify the behavior of systemd based on the
                requirement:

The following is the example of the systemd service
                file:

    [Unit]
    SourcePath=/etc/initscripts/log_restrict.sh
    Description=QTI logging service
     
    [Service]
    ExecStart=/etc/initscripts/post_boot.sh
     
    [Install]
    WantedBy=multi-user.targetCopy to clipboard

### The `[Unit]` section

In systemd, a unit refers to any resource that the system knows how to operate on and
                manage. It encompasses services, sockets, devices, mount points, and groups of
                externally created processes.

Each unit is defined using a configuration file called a `unit` file,
                which contains metadata and configuration details. The `[Unit]`
                section within a unit file provides information about the description and
                relationships with other units.

The `unit` section has the following fields:

Table : Supported fields for [Unit] section

| Fields | Description |
| --- | --- |
| DescriptionCopy to clipboard | Human-readable title of the systemd service. |
| AfterCopy to clipboard | Set dependency on a service. For example, if you are configuring<br>                                a WCN3960 web server, you want the server to start after the network<br>                                is online. |
| BeforeCopy to clipboard | Start current service before specified service. In this example,<br>                                the WCN3960 web server is running before the service for the next<br>                                cloud is started because the next cloud server depends on the<br>                                WCN3960 web server. |

### The `[Service]` section

The `Service` section contains details of the execution and
                termination of service.

The `Service` section has the following fields:

Table : Supported fields for [Service] section

| Fields | Description |
| --- | --- |
| ExecStartCopy to clipboard | The command that must be executed when the service starts. For<br>                                example, a web server service to start. |
| ExecReloadCopy to clipboard | The optional field that it specifies how a service is restarted.<br>                                For services that perform disk I/O, it is recommended to kill them<br>                                and restart the service. Use the `ExecReload` field<br>                                if you want to have a specific restart mechanism. |
| TypeCopy to clipboard | Indicates the start-up type of a process for a given systemd<br>                                service. The options available are `simple`,<br>                                    `exec`, `forking`,<br>                                    `oneshot`, `dbus`,<br>                                    `notify`, and `idle`. |

For more information, see [Options](https://www.freedesktop.org/software/systemd/man/latest/systemd.service.html?ref=linuxhandbook.com#Options).

### The `[Install]` section

The `Install` section handles the installation of a systemd service or
                unit file. This is used when you run either `systemctl enable` and
                    `systemctl disable` command for enabling or disabling a service.

The `Install` section has the following fields:

- `WantedBy`: Similar to the `After` and
                        `Before` fields of the [\[Unit\] section](https://docs.qualcomm.com/doc/80-70014-3/topic/customize.html#post-boot-settings__KernelExternalDocumentation-The_Unit_section). However, it is used to specify systemd-equivalent
                        **run levels**.
    The `default.target` is when all the
                        system initialization is complete and when asked to log in. Most user-facing
                        services (like WCN3960, cron, GNOME-stuff) use this target.

    The
                            `shutdown.target` is to run the service just before the
                        device shuts down.

    The `multi-user.target` is to run
                        the service at the time of system boot, as the root user.

It can be
                    either a target or a service, for example `network.target`.

- `RequiredBy`: This field is similar to `WantedBy`.
                    However, the field specifies **hard dependencies**. If a dependency fails,
                    the service also fails.

### Post boot script

The post boot script file is in the core recipe of the `meta-qcom-hwe`
                layer.

The post boot script to be run as a part of the previous systemd service. All post
                boot settings can be hosted in a
                    `meta-qcom-hwe/recipes-core/initscripts/files/post_boot.sh`
                script.

    #!/bin/sh
    # Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
    # SPDX-License-Identifier: BSD-3-Clause-Clear
     
    # Apply post boot settingsCopy to clipboard

### Recipe for postboot systemd service

Use the `initscripts_1.0.bbappend` file to understand the recipe
                configuration procedure to install `post_boot` script.

The recipe to install the postboot bash script in `/etc/init.d` is in
                the `meta-qcom-hwe/recipes-core/initscripts/initscripts_1.0.bbappend`
                file.

    # postboot
     
    inherit systemd externalsrc
     
    FILESEXTRAPATHS:prepend := "${THISDIR}/files:"
    SRC_URI:append = " \
        file://post_boot.sh \
        file://logging-restrictions.sh \
        file://log-restrict.service \
        file://post-boot.service \
        "
     
    do_install:append() {
        # postboot
        install -m 0755 ${WORKDIR}/post_boot.sh ${D}${sysconfdir}/initscripts/post_boot.sh
        install -m 0644 ${WORKDIR}/post-boot.service -D ${D}${systemd_unitdir}/system/post-boot.service
        ln -sf ${systemd_unitdir}/system/post-boot.service ${D}${systemd_unitdir}/system/multi-user.target.wants/post-boot.service
    }
     
    S = "${WORKDIR}"
     
    INITSCRIPT_PACKAGES =+ "${PN}-post-boot"
    INITSCRIPT_NAME:${PN}-post-boot = "post_boot.sh"
     
    PACKAGES =+ "${PN}-post-boot"
    FILES:${PN}-post-boot += "${systemd_unitdir}/system/post-boot.service ${systemd_unitdir}/system/multi-user.target.wants/post-boot.service ${sysconfdir}/initscripts/post_boot.sh"Copy to clipboard

### Scheduler DCVS settings

Scheduler DCVS settings are defined in the `post_boot script`
                file.

All post boot settings are present in the
                    `meta-qcom-hwe/recipes-core/initscripts/files/post_boot.sh`
                script.

    #!/bin/sh
    # Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
    # SPDX-License-Identifier: BSD-3-Clause-Clear
     Copy to clipboard

Last Published: Jul 15, 2024

[Previous Topic
Yocto support](https://docs.qualcomm.com/bundle/publicresource/80-70014-3/topics/yocto-kernel-support.md) [Next Topic
Debug](https://docs.qualcomm.com/bundle/publicresource/80-70014-3/topics/debug.md)