i.MX Processors Knowledge Base

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

i.MX Processors Knowledge Base

Discussions

Sort by:
This page describes how to determine the NAND timing parameters for use in the NAND driver. This is independent of any OS that may be used. Analyzing NAND Datasheets  We use a spreadsheet to capture and analyze NAND features. That spreadsheet is [attached to this wiki page|Adding support for a new NAND with i.MX28– Nand Analysis^nand_analysis_template.xls]. We analyze a NAND as described below. We must have the NAND datasheet to do the analysis. Copy the *analysis spreadsheet* to a new filename with the exact part number(s) of the NAND(s) being analyzed. Fill in sheet 1 ("Cover Page") of the analysis spreadsheet. Work on sheet 3 next: Fundamental Features. Other tables. If the NAND is one of a family listed together in a data sheet, then analyze the whole family with one spreadsheet. You can use the "Similar to" rows for the additional members of the family. Add more rows if needed. Most NANDs have an asyncrhronous interface, so there is not a simple clock frequency involved. Instead, there are various setup times, hold times, and output delays that imply limits on the I/O rate to/from the NAND. The spreadsheet compares the NAND's timing specifications to see if sums of the setup, hold, and output times are shorter than the minimim read-cycle or write-cycle times. The spreadsheet is specifically intended for use with the Nand controller in STMP378x/i.MX233/i.mx28 chips, so the spreadsheet performs the timing calculations with the goal of deriving the timing parameters *TSU*, *TDS*, and *TDH* for those CPUs. If the TDS and/or TDH quantities {color:#ff0000}turn red{color} after all the timings have been computed, then the computed TDS and/or TDH are too short for the specified cycle-time of the NAND. In that case:           You will have to increase one or both of them in the software. Write a note somewhere in the analysis spreadsheet about the values that you choose, but don't mess up the automatic computations. Record how the flash denotes factory-marked bad-blocks. (Some use the first page of a block, some use the last page,, etc.) Compare it to this [current superset of bad-block marking methods [http://wiki.freescale.net/display/PSGSW/Storage+Media%2C+Flash+Bad+Block+Marks] used to detect any flash factory bad block. Example Analysis Examples of NAND datasheets and analyses can be found on the [Hynix NAND Page | http://wiki.freescale.net/display/PSGSW/Hynix+NAND+Flash+Documents].
View full article
The i.MX 6 D/Q/DL/S/SL  Linux L3.10.17_1.0.2 Patch release is now available on www.freescale.com ·          Target HW boards o   i.MX6DL  SABRE SD board o   i.MX6Q  SABRE SD board o   i.MX6DQ SABRE AI board o   i.MX6DL SABRE AI board o   i.MX6SL EVK board This patch release is based on the i.MX 6 Linux L3.10.17_1.0.2 BSP release. ·         Release Description o    Kernel branch: imx_v2013.04_3.10.17_1.0.0_ga o    U-Boot branch: imx_3.10.17_1.0.0_ga o    Graphics: gpu-viv-bin-mx6q, 3.10.17_1.0.2 o    Graphics: gpu-viv-g2d, 3.10.17_1.0.2 o    Graphics: Xorg-driver, 3.10.17_1.0.2 ·         Patch Description Please consult the release notes.
View full article
Note that this document only applies for REV2 of the SCM QWKS board Refer to the attached presentation to check how the OV5640 camera can be connected to the QWKS rev2 with a retrofit of the OV5640 camera set as in the image below Enjoy!!!
View full article
We are pleased to announce that Config Tools for i.MX 26.06 are now available. Downloads & links To download the installer for all platforms, please login to our download site via:  https://www.nxp.com/design/designs/config-tools-for-i-mx-applications-processors:CONFIG-TOOLS-IMX Please refer to  Documentation  for installation and quick start guides. For further information about DDR config and validation, please go to this  blog post. Release Notes Full details on the release (features, known issues...) Version 26.06 DDR tool – NXP-validated memory configurations for multiple vendors is available System Manager – extended CLI support for a headless setting
View full article
  Overview When using the OX03C10 camera with the deserializer (X-MX95MBDESER01) on i.MX95 platforms, systems are often deployed with fewer than four cameras (e.g., single-camera evaluation setups). This guide provides best practices and configuration guidance to ensure a smooth experience when using 1–3 cameras, including correct hardware connections and software configuration.   Key Recommendations 1. Connect Cameras in Port Order For proper operation, cameras should always be connected starting from the first deserializer port, then incrementally: ✅ 1 camera → connect to Port 0 ✅ 2 cameras → connect to Port 0 and Port 1 ✅ 3 cameras → connect to Port 0, Port 1, Port 2   Avoid skipping ports (e.g., connecting only to Port 2). Note: Starting with release 6.18.20, this constraint is relaxed. However, following this order remains recommended for consistency across software versions. 2. Understand Default Resolution Behavior Resolution handling depends on the software version used: Kernel Version Supported Camera Modes ≤ 6.6.y 1920 × 1280 only ≥ 6.12.y 1920 × 1280 and 1920 × 1080   In newer versions, the system may automatically select different resolutions across components, which can lead to mismatches if not explicitly configured. Recommended Configuration Approach To ensure consistent operation across all supported resolutions, it is recommended to configure the resolution centrally in the libcamera pipeline configuration. Update config.yaml Edit the following file: /usr/share/libcamera/pipeline/nxp/neo/config.yaml Add or update the format section for your camera entity: - entity: mx95mbcam 8-0040 format: { size: [1920,1082] }   Why this is recommended ✅ Works with both 1920×1280 and 1920×1080 ✅ Avoids pipeline mismatches between camera and ISP ✅ Provides consistent behavior across applications   Summary To ensure optimal operation when using fewer than four cameras: ✔ Connect cameras starting from the first port ✔ Use sequential port order (no gaps) ✔ Prefer configuring resolution in config.yaml
View full article
Background: This article discusses the reboot mechanism on the i.MX8MP and i.MX93 platforms. It aims to help customers understand how the reboot command works. We will discuss two different kernel versions separately.   1. Linux version : LF_6.12.34_2.1.0 The executable file for the reboot command is as follows: When the ”reboot“ command is executed, the system enters the ”do_kernel_restart()“ function and executes the reboot mechanism by determining the priority of the registered functions. Since the ”reboot.c“ file does not print out the registered functions, a print function is added to the file to identify the function that is ultimately executed.   The print output is as follows: As shown in the figure above, in version 5.12, the reboot is performed via a reset executed by psci. Continuing to trace the ”psci_sys_reset()“ function, we can see that the system sends the function ID via the PSCI interface to initiate an SMC call, instructing the underlying firmware (ATF/EL3) to perform a system reboot (typically a cold reset). The value of PSCI_0_2_FN_SYSTEM_RESET is 0x80000009   According to the Arm Power State Coordination Interface Platform Design Document, this ID represents a cold reset of the system.     2. Linux version : LF_6.18.2_1.0.0 Use the same debugging method to examine the reboot mechanism in version 6.18 As shown in the output below, in version 6.18, the system reset is triggered by the `sys_off_notify()` function. The final execution function is pca9450_i2c_restart_handler()   By examining the `pca9450_i2c_restart_handler()` function, we can see that the system writes a `SW_RST_COMMAND` value to the PMIC via I²C, where `SW_RST_COMMAND = 0x14`. According to the PMIC data sheet, 10b = Cold Reset; all voltage regulators are reset except LDO1/LDO2   Summary: Regardless of the kernel version, the `reboot` command triggers a system cold reset. The triggering mechanism has been updated in versions 6.18 and later.
View full article
Customer requirement: Use NOR boot as a backup — boot from NOR, then mount kernel, DTB, and rootfs from NAND. Test module: https://www.nxp.com/design/design-center/development-boards-and-designs/m2-nand-flash-daughter-card:M2-NAND-FLASH   Test under L6.12.49 Uboot.   1. Why Does U-Boot Source Need Modification on i.MX95? i.MX93's boot ROM initializes the SD3_XXX and SD1_XXX PADs. On the i.MX93 EVK design, SD3_XXX is routed to the M.2 connector, and SD1_XXX is connected to eMMC.   For i.MX95, the boot ROM only initializes the XSPI1_XXX PADs. The FlexSPI signals can be muxed out from SD3_XXX, but the boot ROM cannot boot from SD3_XXX.   Due to these differences, the uboot.bin flashed into NOR must have the ability to read NAND. However, the default BSP always reads from NOR, so U-Boot must be modified to activate the M.2 NAND module. 2. Flashing NAND To flash NAND, a custom UUU script must be used. Using the built-in UUU spinand flashing script is not recommended — the built-in script assumes NAND is accessible in U-Boot, but the default imx-boot uses NOR. 2.1 UUU Script uuu_version 1.2.39 # Please replace below item with actual name # @_flash_fw.bin | boot loader firmware, for i.MX8QM/QX, it's different from _flash.bin, for all other platforms, it's same as _flash.bin # @_flash.bin | boot loader file burn to NAND # @_Image | linux kernel image, zImage for arm32, Image for arm64 # @_board.dtb | board dtb file # @_initramfs.cpio.zst.uboot | initramfs # @_tee | optee image # @_rootfs.tar.zst | rootfs # This command will be run when i.MX6/7 i.MX8MM, i.MX8MQ SDP: boot -f .\imx-boot-imx95-19x19-lpddr5-evk-fspi.bin-flash_a55_flexspi # This command will be run when ROM support stream mode # i.MX8QXP, i.MX8QM, skip QSPI header SDPS: boot -f .\imx-boot-imx95-19x19-lpddr5-evk-fspi.bin-flash_a55_flexspi -skipfhdr # These commands will be run when use SPL and will be skipped if no spl # SDPU will be deprecated. please use SDPV instead of SDPU # { SDPU: delay 1000 SDPU: write -f .\imx-boot-imx95-19x19-lpddr5-evk-fspi.bin-flash_a55_flexspi -offset 0x10000 -skipfhdr SDPU: jump # } # These commands will be run when use SPL and will be skipped if no spl # if (SPL support SDPV) # { SDPV: delay 1000 SDPV: write -f .\imx-boot-imx95-19x19-lpddr5-evk-fspi.bin-flash_a55_flexspi -skipspl -skipfhdr SDPV: jump # } FB: ucmd setenv fastboot_buffer ${loadaddr} FB: download -f Image.bin FB: ucmd setenv fastboot_buffer ${fdt_addr} FB: download -f imx95-19x19-evk.dtb FB: ucmd setenv fastboot_buffer ${initrd_addr} FB: download -f fsl-image-mfgtool-initramfs-imx_mfgtools.cpio.zst.u-boot FB: ucmd setenv bootargs ${bootargs} ${mtdparts} FB: ucmd setenv fdtfile imx95-19x19-evk.dtb #FB: ucmd setenv bootargs console=ttymxc3,115200 ${mtdparts} FB: acmd ${kboot} ${loadaddr} ${initrd_addr} ${fdt_addr} FBK: ucmd cat /proc/mtd FBK: ucmd rm -f /tmp/mtd.sh FBK: ucmd cat /proc/mtd | while read dev size erase name; do mtd=`echo $dev | sed 's/mtd//;s/://'`; name=`echo $name | tr -d '"'`; echo export $name=$mtd >> /tmp/mtd.sh; done # mapping name FBK: ucmd . /tmp/mtd.sh; [ -n "${bootloader}" ] && echo export nandboot=${bootloader} >> /tmp/mtd.sh FBK: ucmd . /tmp/mtd.sh; [ -n "${kernel}" ] && echo export nandkernel=${kernel} >> /tmp/mtd.sh FBK: ucmd . /tmp/mtd.sh; [ -n "${dtb}" ] && echo export nanddtb=${dtb} >> /tmp/mtd.sh FBK: ucmd . /tmp/mtd.sh; [ -n "${rootfs}" ] && echo export nandrootfs=${rootfs} >> /tmp/mtd.sh FBK: ucmd chmod 755 /tmp/mtd.sh FBK: ucmd cat /tmp/mtd.sh FBK: ucmd mount -t debugfs debugfs /sys/kernel/debug || true # write boot loader — this partition was set to read-only in DTS during testing, skip erase for now # FBK: ucmd . /tmp/mtd.sh; flash_erase /dev/mtd${nandboot} 0 0 # FBK: ucp imx-boot-imx95-19x19-lpddr5-evk-fspi.bin-flash_a55_flexspi t:/tmp/boot # FBK: ucmd . /tmp/mtd.sh; cd /tmp; soc=`cat /sys/devices/soc0/soc_id 2>/dev/null`; pad=""; case "$soc" in MX8Q*|MX8DXL*|MX8MN*|MX8MP*) ;; *) pad="-x" ;; esac; kobs-ng init $pad -v --chip_0_device_path=/dev/mtd${nandboot} /tmp/boot # burn kernel FBK: ucmd . /tmp/mtd.sh; flash_erase /dev/mtd${nandkernel} 0 0 FBK: acmd . /tmp/mtd.sh; nandwrite -p /dev/mtd${nandkernel} - FBK: ucp Image.bin t:- FBK: sync # burn dtb FBK: ucmd . /tmp/mtd.sh; flash_erase /dev/mtd${nanddtb} 0 0 FBK: ucp imx95-19x19-evk.dtb t:/tmp/dtb FBK: ucmd . /tmp/mtd.sh; nandwrite -p /dev/mtd${nanddtb} /tmp/dtb # burn uTee # FBK: ucmd . /tmp/mtd.sh; flash_erase /dev/mtd${nandtee} 0 0 # FBK: ucp _tee t:/tmp/tee # FBK: ucmd . /tmp/mtd.sh; nandwrite -p /dev/mtd${nandtee} /tmp/tee # burn rootfs FBK: ucmd . /tmp/mtd.sh; flash_erase /dev/mtd${nandrootfs} 0 0 FBK: ucmd ubidetach /dev/ubi_ctrl -m ${nandrootfs} || true FBK: ucmd . /tmp/mtd.sh; ubiattach /dev/ubi_ctrl -m ${nandrootfs} FBK: ucmd ubimkvol /dev/ubi0 -N nandrootfs -m FBK: ucmd mkdir -p /mnt/mtd FBK: ucmd mount -t ubifs ubi0:nandrootfs /mnt/mtd FBK: acmd export EXTRACT_UNSAFE_SYMLINKS=1; tar --zstd --warning=no-timestamp -x -C /mnt/mtd FBK: ucp core-image-base-imx95-19x19-lpddr5-evk.rootfs-20260429064745.tar.zst t:- FBK: sync FBK: ucmd umount /mnt/mtd FBK: done 2.2 Linux Patch diff --git a/arch/arm64/boot/dts/freescale/imx95-19x19-evk.dts b/arch/arm64/boot/dts/freescale/imx95-19x19-evk.dts index d21335d8af84..0db2cefbab01 100644 --- a/arch/arm64/boot/dts/freescale/imx95-19x19-evk.dts +++ b/arch/arm64/boot/dts/freescale/imx95-19x19-evk.dts @@ -388,17 +388,47 @@ &flexspi1 { pinctrl-0 = <&pinctrl_flexspi1>; status = "okay"; - mt35xu01gbba: flash@0 { - compatible = "jedec,spi-nor"; - reg = <0>; - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_flexspi1_reset>; - reset-gpios = <&gpio5 11 GPIO_ACTIVE_LOW>; + W25N02KWZEIR: flash@0 { + compatible = "spi-nand"; #address-cells = <1>; #size-cells = <1>; - spi-max-frequency = <200000000>; - spi-tx-bus-width = <8>; - spi-rx-bus-width = <8>; + reg = <0>; + spi-max-frequency = <104000000>; + spi-tx-bus-width = <4>; + spi-rx-bus-width = <4>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "bootloader"; + reg = <0x000000 0x800000>; // 8MB + // read-only;//if you hope imx-boot read only + }; + + partition@1 { + label = "config"; + reg = <0x800000 0x800000>; //8MB + }; + + partition@2 { + label = "kernel"; + reg = <0x1000000 0x2800000>; //40MB + }; + + partition@3 { + label = "dtb"; + reg = <0x3800000 0x20000>; //128K + }; + + partition@4 { + label = "rootfs"; + reg = <0x3820000 0xFFFFFFFF>; + linux,rootfs; + }; + }; }; }; @@ -887,17 +917,12 @@ IMX95_PAD_GPIO_IO27__CAN2_RX 0x39e pinctrl_flexspi1: flexspi1grp { fsl,pins = < - IMX95_PAD_XSPI1_SS0_B__FLEXSPI1_A_SS0_B 0x3fe - IMX95_PAD_XSPI1_SCLK__FLEXSPI1_A_SCLK 0x3fe - IMX95_PAD_XSPI1_DQS__FLEXSPI1_A_DQS 0x3fe - IMX95_PAD_XSPI1_DATA0__FLEXSPI1_A_DATA_BIT0 0x3fe - IMX95_PAD_XSPI1_DATA1__FLEXSPI1_A_DATA_BIT1 0x3fe - IMX95_PAD_XSPI1_DATA2__FLEXSPI1_A_DATA_BIT2 0x3fe - IMX95_PAD_XSPI1_DATA3__FLEXSPI1_A_DATA_BIT3 0x3fe - IMX95_PAD_XSPI1_DATA4__FLEXSPI1_A_DATA_BIT4 0x3fe - IMX95_PAD_XSPI1_DATA5__FLEXSPI1_A_DATA_BIT5 0x3fe - IMX95_PAD_XSPI1_DATA6__FLEXSPI1_A_DATA_BIT6 0x3fe - IMX95_PAD_XSPI1_DATA7__FLEXSPI1_A_DATA_BIT7 0x3fe + IMX95_PAD_SD3_CMD__FLEXSPI1_A_SS0_B 0x3fe + IMX95_PAD_SD3_CLK__FLEXSPI1_A_SCLK 0x3fe + IMX95_PAD_SD3_DATA0__FLEXSPI1_A_DATA_BIT0 0x3fe + IMX95_PAD_SD3_DATA1__FLEXSPI1_A_DATA_BIT1 0x3fe + IMX95_PAD_SD3_DATA2__FLEXSPI1_A_DATA_BIT2 0x3fe + IMX95_PAD_SD3_DATA3__FLEXSPI1_A_DATA_BIT3 0x3fe >; }; 2.3 Flashing Log 2:31-182BA9E87D9840BA>Start Cmd:SDPS: boot -f .\imx-boot-imx95-19x19-lpddr5-evk-fspi.bin-flash_a55_flexspi -skipfhdr 100%2:31-182BA9E87D9840BA>Okay (5.364s) New USB Device Attached at 2:31-182BA9E87D9840BA 2:31-182BA9E87D9840BA>Start Cmd:SDPV: delay 1000 2:31-182BA9E87D9840BA>Okay (1.009s) 2:31-182BA9E87D9840BA>Start Cmd:SDPV: write -f .\imx-boot-imx95-19x19-lpddr5-evk-fspi.bin-flash_a55_flexspi -skipspl -skipfhdr 100%2:31-182BA9E87D9840BA>Okay (3.165s) 2:31-182BA9E87D9840BA>Start Cmd:SDPV: jump 100%2:31-182BA9E87D9840BA>Okay (0.017s) New USB Device Attached at 2:31-182BA9E87D9840BA 2:31-182BA9E87D9840BA>Start Cmd:FB: ucmd setenv fastboot_buffer ${loadaddr} 2:31-182BA9E87D9840BA>Okay (0.014s) 2:31-182BA9E87D9840BA>Start Cmd:FB: download -f Image.bin 2:31-182BA9E87D9840BA>Okay (1.715s) 2:31-182BA9E87D9840BA>Start Cmd:FB: ucmd setenv fastboot_buffer ${fdt_addr} 2:31-182BA9E87D9840BA>Okay (0.011s) 2:31-182BA9E87D9840BA>Start Cmd:FB: download -f imx95-19x19-evk.dtb 2:31-182BA9E87D9840BA>Okay (0.026s) 2:31-182BA9E87D9840BA>Start Cmd:FB: ucmd setenv fastboot_buffer ${initrd_addr} 2:31-182BA9E87D9840BA>Okay (0.011s) 2:31-182BA9E87D9840BA>Start Cmd:FB: download -f fsl-image-mfgtool-initramfs-imx_mfgtools.cpio.zst.u-boot 2:31-182BA9E87D9840BA>Okay (0.702s) 2:31-182BA9E87D9840BA>Start Cmd:FB: ucmd setenv bootargs ${bootargs} ${mtdparts} 2:31-182BA9E87D9840BA>Okay (0.011s) 2:31-182BA9E87D9840BA>Start Cmd:FB: ucmd setenv fdtfile imx95-19x19-evk.dtb 2:31-182BA9E87D9840BA>Okay (0.011s) 2:31-182BA9E87D9840BA>Start Cmd:FB: acmd ${kboot} ${loadaddr} ${initrd_addr} ${fdt_addr} 2:31-182BA9E87D9840BA>Okay (0.007s) New USB Device Attached at 2:31-0000000000000000 2:31-0000000000000000>Start Cmd:FBK: ucmd cat /proc/mtd dev: size erasesize name mtd0: 00800000 00020000 "bootloader" mtd1: 00800000 00020000 "config" mtd2: 02800000 00020000 "kernel" mtd3: 00020000 00020000 "dtb" mtd4: 0c7e0000 00020000 "rootfs" 2:31-0000000000000000>Okay (0.015s) 2:31-0000000000000000>Start Cmd:FBK: ucmd rm -f /tmp/mtd.sh 2:31-0000000000000000>Okay (0.007s) 2:31-0000000000000000>Start Cmd:FBK: ucmd cat /proc/mtd | while read dev size erase name; do mtd=`echo $dev | sed 's/mtd//;s/://'`; name=`echo $name | tr -d '"'`; echo export $name=$mtd >> /tmp/mtd.sh; done 2:31-0000000000000000>Okay (0.077s) 2:31-0000000000000000>Start Cmd:FBK: ucmd . /tmp/mtd.sh; [ -n "${bootloader}" ] && echo export nandboot=${bootloader} >> /tmp/mtd.sh 2:31-0000000000000000>Okay (0.006s) 2:31-0000000000000000>Start Cmd:FBK: ucmd . /tmp/mtd.sh; [ -n "${kernel}" ] && echo export nandkernel=${kernel} >> /tmp/mtd.sh 2:31-0000000000000000>Okay (0.008s) 2:31-0000000000000000>Start Cmd:FBK: ucmd . /tmp/mtd.sh; [ -n "${dtb}" ] && echo export nanddtb=${dtb} >> /tmp/mtd.sh 2:31-0000000000000000>Okay (0.006s) 2:31-0000000000000000>Start Cmd:FBK: ucmd . /tmp/mtd.sh; [ -n "${rootfs}" ] && echo export nandrootfs=${rootfs} >> /tmp/mtd.sh 2:31-0000000000000000>Okay (0.008s) 2:31-0000000000000000>Start Cmd:FBK: ucmd chmod 755 /tmp/mtd.sh 2:31-0000000000000000>Okay (0.007s) 2:31-0000000000000000>Start Cmd:FBK: ucmd cat /tmp/mtd.sh export name=dev export bootloader=0 export config=1 export kernel=2 export dtb=3 export rootfs=4 export nandboot=0 export nandkernel=2 export nanddtb=3 export nandrootfs=4 2:31-0000000000000000>Okay (0.007s) 2:31-0000000000000000>Start Cmd:FBK: ucmd mount -t debugfs debugfs /sys/kernel/debug || true 2:31-0000000000000000>Okay (0.01s) 2:31-0000000000000000>Start Cmd:FBK: ucmd . /tmp/mtd.sh; flash_erase /dev/mtd${nandkernel} 0 0 Erasing 40960 Kibyte @ 0 -- 100 % complete 2:31-0000000000000000>Okay (0.856s) 2:31-0000000000000000>Start Cmd:FBK: acmd . /tmp/mtd.sh; nandwrite -p /dev/mtd${nandkernel} - 2:31-0000000000000000>Okay (0.051s) 2:31-0000000000000000>Start Cmd:FBK: ucp Image.bin t:- 33%Writing data to block 0 at offset 0x0 Writing data to block 1 at offset 0x20000 Writing data to block 2 at offset 0x40000 Writing data to block 3 at offset 0x60000 Writing data to block 4 at offset 0x80000 Writing data to block 5 at offset 0xa0000 Writing data to block 6 at offset 0xc0000 Writing data to block 7 at offset 0xe0000 Writing data to block 8 at offset 0x100000 Writing data to block 9 at offset 0x120000 Writing data to block 10 at offset 0x140000 Writing data to block 11 at offset 0x160000 Writing data to block 12 at offset 0x180000 Writing data to block 13 at offset 0x1a0000 Writing data to block 14 at offset 0x1c0000 Writing data to block 15 at offset 0x1e0000 Writing data to block 16 at offset 0x200000 Writing data to block 17 at offset 0x220000 Writing data to block 18 at offset 0x240000 Writing data to block 19 at offset 0x260000 Writing data to block 20 at offset 0x280000 Writing data to block 21 at offset 0x2a0000 Writing data to block 22 at offset 0x2c0000 Writing data to block 23 at offset 0x2e0000 Writing data to block 24 at offset 0x300000 Writing data to block 25 at offset 0x320000 Writing data to block 26 at offset 0x340000 Writing data to block 27 at offset 0x360000 Writing data to block 28 at offset 0x380000 Writing data to block 29 at offset 0x3a0000 Writing data to block 30 at offset 0x3c0000 Writing data to block 31 at offset 0x3e0000 Writing data to block 32 at offset 0x400000 Writing data to block 33 at offset 0x420000 Writing data to block 34 at offset 0x440000 Writing data to block 35 at offset 0x460000 Writing data to block 36 at offset 0x480000 Writing data to block 37 at offset 0x4a0000 Writing data to block 38 at offset 0x4c0000 Writing data to block 39 at offset 0x4e0000 Writing data to block 40 at offset 0x500000 Writing data to block 41 at offset 0x520000 Writing data to block 42 at offset 0x540000 Writing data to block 43 at offset 0x560000 Writing data to block 44 at offset 0x580000 Writing data to block 45 at offset 0x5a0000 Writing data to block 46 at offset 0x5c0000 Writing data to block 47 at offset 0x5e0000 Writing data to block 48 at offset 0x600000 Writing data to block 49 at offset 0x620000 Writing data to block 50 at offset 0x640000 Writing data to block 51 at offset 0x660000 Writing data to block 52 at offset 0x680000 Writing data to block 53 at offset 0x6a0000 Writing data to block 54 at offset 0x6c0000 Writing data to block 55 at offset 0x6e0000 Writing data to block 56 at offset 0x700000 Writing data to block 57 at offset 0x720000 Writing data to block 58 at offset 0x740000 Writing data to block 59 at offset 0x760000 Writing data to block 60 at offset 0x780000 Writing data to block 61 at offset 0x7a0000 Writing data to block 62 at offset 0x7c0000 Writing data to block 63 at offset 0x7e0000 Writing data to block 64 at offset 0x800000 Writing data to block 65 at offset 0x820000 Writing data to block 66 at offset 0x840000 Writing data to block 67 at offset 0x860000 Writing data to block 68 at offset 0x880000 Writing data to block 69 at offset 0x8a0000 Writing data to block 70 at offset 0x8c0000 Writing data to block 71 at offset 0x8e0000 Writing data to block 72 at offset 0x900000 Writing data to block 73 at offset 0x920000 Writing data to block 74 at offset 0x940000 Writing data to block 75 at offset 0x960000 Writing data to block 76 at offset 0x980000 Writing data to block 77 at offset 0x9a0000 Writing data to block 78 at offset 0x9c0000 Writing data to block 79 at offset 0x9e0000 Writing data to block 80 at offset 0xa00000 Writing data to block 81 at offset 0xa20000 Writing data to block 82 at offset 0xa40000 Writing data to block 83 at offset 0xa60000 Writing data to block 84 at offset 0xa80000 Writing data to block 85 at offset 0xaa0000 Writing data to block 86 at offset 0xac0000 Writing data to block 87 at offset 0xae0000 Writing data to block 88 at offset 0xb00000 Writing data to block 89 at offset 0xb20000 Writing data to block 90 at offset 0xb40000 Writing data to block 91 at offset 0xb60000 Writing data to block 92 at offset 0xb80000 65%t offset 0xba0000k 93 a Writing data to block 94 at offset 0xbc0000 Writing data to block 95 at offset 0xbe0000 Writing data to block 96 at offset 0xc00000 Writing data to block 97 at offset 0xc20000 Writing data to block 98 at offset 0xc40000 Writing data to block 99 at offset 0xc60000 Writing data to block 100 at offset 0xc80000 Writing data to block 101 at offset 0xca0000 Writing data to block 102 at offset 0xcc0000 Writing data to block 103 at offset 0xce0000 Writing data to block 104 at offset 0xd00000 Writing data to block 105 at offset 0xd20000 Writing data to block 106 at offset 0xd40000 Writing data to block 107 at offset 0xd60000 Writing data to block 108 at offset 0xd80000 Writing data to block 109 at offset 0xda0000 Writing data to block 110 at offset 0xdc0000 Writing data to block 111 at offset 0xde0000 Writing data to block 112 at offset 0xe00000 Writing data to block 113 at offset 0xe20000 Writing data to block 114 at offset 0xe40000 Writing data to block 115 at offset 0xe60000 Writing data to block 116 at offset 0xe80000 Writing data to block 117 at offset 0xea0000 Writing data to block 118 at offset 0xec0000 Writing data to block 119 at offset 0xee0000 Writing data to block 120 at offset 0xf00000 Writing data to block 121 at offset 0xf20000 Writing data to block 122 at offset 0xf40000 Writing data to block 123 at offset 0xf60000 Writing data to block 124 at offset 0xf80000 Writing data to block 125 at offset 0xfa0000 Writing data to block 126 at offset 0xfc0000 Writing data to block 127 at offset 0xfe0000 Writing data to block 128 at offset 0x1000000 Writing data to block 129 at offset 0x1020000 Writing data to block 130 at offset 0x1040000 Writing data to block 131 at offset 0x1060000 Writing data to block 132 at offset 0x1080000 Writing data to block 133 at offset 0x10a0000 Writing data to block 134 at offset 0x10c0000 Writing data to block 135 at offset 0x10e0000 Writing data to block 136 at offset 0x1100000 Writing data to block 137 at offset 0x1120000 Writing data to block 138 at offset 0x1140000 Writing data to block 139 at offset 0x1160000 Writing data to block 140 at offset 0x1180000 Writing data to block 141 at offset 0x11a0000 Writing data to block 142 at offset 0x11c0000 Writing data to block 143 at offset 0x11e0000 Writing data to block 144 at offset 0x1200000 Writing data to block 145 at offset 0x1220000 Writing data to block 146 at offset 0x1240000 Writing data to block 147 at offset 0x1260000 Writing data to block 148 at offset 0x1280000 Writing data to block 149 at offset 0x12a0000 Writing data to block 150 at offset 0x12c0000 Writing data to block 151 at offset 0x12e0000 Writing data to block 152 at offset 0x1300000 Writing data to block 153 at offset 0x1320000 Writing data to block 154 at offset 0x1340000 Writing data to block 155 at offset 0x1360000 Writing data to block 156 at offset 0x1380000 Writing data to block 157 at offset 0x13a0000 Writing data to block 158 at offset 0x13c0000 Writing data to block 159 at offset 0x13e0000 Writing data to block 160 at offset 0x1400000 Writing data to block 161 at offset 0x1420000 Writing data to block 162 at offset 0x1440000 Writing data to block 163 at offset 0x1460000 Writing data to block 164 at offset 0x1480000 Writing data to block 165 at offset 0x14a0000 Writing data to block 166 at offset 0x14c0000 Writing data to block 167 at offset 0x14e0000 Writing data to block 168 at offset 0x1500000 Writing data to block 169 at offset 0x1520000 Writing data to block 170 at offset 0x1540000 Writing data to block 171 at offset 0x1560000 Writing data to block 172 at offset 0x1580000 Writing data to block 173 at offset 0x15a0000 Writing data to block 174 at offset 0x15c0000 Writing data to block 175 at offset 0x15e0000 Writing data to block 176 at offset 0x1600000 Writing data to block 177 at offset 0x1620000 Writing data to block 178 at offset 0x1640000 Writing data to block 179 at offset 0x1660000 Writing data to block 180 at offset 0x1680000 Writing data to block 181 at offset 0x16a0000 Writing data to block 182 at offset 0x16c0000 97%3 at offset 0x16e0000 Writing data to block 184 at offset 0x1700000 Writing data to block 185 at offset 0x1720000 Writing data to block 186 at offset 0x1740000 Writing data to block 187 at offset 0x1760000 Writing data to block 188 at offset 0x1780000 Writing data to block 189 at offset 0x17a0000 Writing data to block 190 at offset 0x17c0000 Writing data to block 191 at offset 0x17e0000 Writing data to block 192 at offset 0x1800000 Writing data to block 193 at offset 0x1820000 Writing data to block 194 at offset 0x1840000 Writing data to block 195 at offset 0x1860000 Writing data to block 196 at offset 0x1880000 Writing data to block 197 at offset 0x18a0000 Writing data to block 198 at offset 0x18c0000 Writing data to block 199 at offset 0x18e0000 Writing data to block 200 at offset 0x1900000 Writing data to block 201 at offset 0x1920000 Writing data to block 202 at offset 0x1940000 Writing data to block 203 at offset 0x1960000 Writing data to block 204 at offset 0x1980000 Writing data to block 205 at offset 0x19a0000 Writing data to block 206 at offset 0x19c0000 Writing data to block 207 at offset 0x19e0000 Writing data to block 208 at offset 0x1a00000 Writing data to block 209 at offset 0x1a20000 Writing data to block 210 at offset 0x1a40000 Writing data to block 211 at offset 0x1a60000 Writing data to block 212 at offset 0x1a80000 Writing data to block 213 at offset 0x1aa0000 Writing data to block 214 at offset 0x1ac0000 Writing data to block 215 at offset 0x1ae0000 Writing data to block 216 at offset 0x1b00000 Writing data to block 217 at offset 0x1b20000 Writing data to block 218 at offset 0x1b40000 Writing data to block 219 at offset 0x1b60000 Writing data to block 220 at offset 0x1b80000 Writing data to block 221 at offset 0x1ba0000 Writing data to block 222 at offset 0x1bc0000 Writing data to block 223 at offset 0x1be0000 Writing data to block 224 at offset 0x1c00000 Writing data to block 225 at offset 0x1c20000 Writing data to block 226 at offset 0x1c40000 Writing data to block 227 at offset 0x1c60000 Writing data to block 228 at offset 0x1c80000 Writing data to block 229 at offset 0x1ca0000 Writing data to block 230 at offset 0x1cc0000 Writing data to block 231 at offset 0x1ce0000 Writing data to block 232 at offset 0x1d00000 Writing data to block 233 at offset 0x1d20000 Writing data to block 234 at offset 0x1d40000 Writing data to block 235 at offset 0x1d60000 Writing data to block 236 at offset 0x1d80000 Writing data to block 237 at offset 0x1da0000 Writing data to block 238 at offset 0x1dc0000 Writing data to block 239 at offset 0x1de0000 Writing data to block 240 at offset 0x1e00000 Writing data to block 241 at offset 0x1e20000 Writing data to block 242 at offset 0x1e40000 Writing data to block 243 at offset 0x1e60000 Writing data to block 244 at offset 0x1e80000 Writing data to block 245 at offset 0x1ea0000 Writing data to block 246 at offset 0x1ec0000 Writing data to block 247 at offset 0x1ee0000 Writing data to block 248 at offset 0x1f00000 Writing data to block 249 at offset 0x1f20000 Writing data to block 250 at offset 0x1f40000 Writing data to block 251 at offset 0x1f60000 Writing data to block 252 at offset 0x1f80000 Writing data to block 253 at offset 0x1fa0000 Writing data to block 254 at offset 0x1fc0000 Writing data to block 255 at offset 0x1fe0000 Writing data to block 256 at offset 0x2000000 Writing data to block 257 at offset 0x2020000 Writing data to block 258 at offset 0x2040000 Writing data to block 259 at offset 0x2060000 Writing data to block 260 at offset 0x2080000 Writing data to block 261 at offset 0x20a0000 Writing data to block 262 at offset 0x20c0000 Writing data to block 263 at offset 0x20e0000 Writing data to block 264 at offset 0x2100000 Writing data to block 265 at offset 0x2120000 Writing data to block 266 at offset 0x2140000 Writing data to block 267 at offset 0x2160000 Writing data to block 268 at offset 0x2180000 Writing data to block 269 at offset 0x21a0000 Writing data to block 270 at offset 0x21c0000 Writing data to block 271 at offset 0x21e0000 100%2:31-0000000000000000>Okay (13.24s) 2:31-0000000000000000>Start Cmd:FBK: sync at offset 0x2200000 Writing data to block 273 at offset 0x2220000 Writing data to block 274 at offset 0x2240000 Writing data to block 275 at offset 0x2260000 Writing data to block 276 at offset 0x2280000 2:31-0000000000000000>Okay (0.038s) 2:31-0000000000000000>Start Cmd:FBK: ucmd . /tmp/mtd.sh; flash_erase /dev/mtd${nanddtb} 0 0 Erasing 128 Kibyte @ 0 -- 100 % complete 2:31-0000000000000000>Okay (0.015s) 2:31-0000000000000000>Start Cmd:FBK: ucp imx95-19x19-evk.dtb t:/tmp/dtb 100%2:31-0000000000000000>Okay (0.015s) 2:31-0000000000000000>Start Cmd:FBK: ucmd . /tmp/mtd.sh; nandwrite -p /dev/mtd${nanddtb} /tmp/dtb Writing data to block 0 at offset 0x0 2:31-0000000000000000>Okay (0.047s) 2:31-0000000000000000>Start Cmd:FBK: ucmd . /tmp/mtd.sh; flash_erase /dev/mtd${nandrootfs} 0 0 Erasing 204672 Kibyte @ 0 -- 100 % complete 2:31-0000000000000000>Okay (4.231s) 2:31-0000000000000000>Start Cmd:FBK: ucmd ubidetach /dev/ubi_ctrl -m ${nandrootfs} || true 2:31-0000000000000000>Okay (0.019s) 2:31-0000000000000000>Start Cmd:FBK: ucmd . /tmp/mtd.sh; ubiattach /dev/ubi_ctrl -m ${nandrootfs} UBI device number 0, total 1599 LEBs (203034624 bytes, 193.6 MiB), available 1555 LEBs (197447680 bytes, 188.3 MiB), LEB size 126976 bytes (124.0 KiB) 2:31-0000000000000000>Okay (0.384s) 2:31-0000000000000000>Start Cmd:FBK: ucmd ubimkvol /dev/ubi0 -N nandrootfs -m Set volume size to 197447680 Volume ID 0, size 1555 LEBs (197447680 bytes, 188.3 MiB), LEB size 126976 bytes (124.0 KiB), dynamic, name "nandrootfs", alignment 1 2:31-0000000000000000>Okay (0.051s) 2:31-0000000000000000>Start Cmd:FBK: ucmd mkdir -p /mnt/mtd 2:31-0000000000000000>Okay (0.008s) 2:31-0000000000000000>Start Cmd:FBK: ucmd mount -t ubifs ubi0:nandrootfs /mnt/mtd 2:31-0000000000000000>Okay (0.204s) 2:31-0000000000000000>Start Cmd:FBK: acmd export EXTRACT_UNSAFE_SYMLINKS=1; tar --zstd --warning=no-timestamp -x -C /mnt/mtd 2:31-0000000000000000>Okay (0.052s) 2:31-0000000000000000>Start Cmd:FBK: ucp core-image-base-imx95-19x19-lpddr5-evk.rootfs-20260429064745.tar.zst t:- 100%2:31-0000000000000000>Okay (192.3s) 2:31-0000000000000000>Start Cmd:FBK: sync   3. Flashing NOR The bootloader flashed to NOR must use the newly added imx95_19x19_evk_spinand_defconfig . Therefore, imx95-evk.inc must be modified to enable this. 3.1 UUU Script uuu_version 1.2.39 # @_flexspi.bin | bootloader # @_image [_flexspi.bin] | image burn to flexspi, default is the same as bootloader # This command will be run when i.MX6/7 i.MX8MM, i.MX8MQ SDP: boot -f .\imx-boot-nor.bin-flash_a55_flexspi # This command will be run when ROM support stream mode # i.MX8QXP, i.MX8QM, skip QSPI header SDPS: boot -f .\imx-boot-nor.bin-flash_a55_flexspi -skipfhdr # These commands will be run when use SPL and will be skipped if no spl # SDPU will be deprecated. please use SDPV instead of SDPU # { SDPU: delay 1000 SDPU: write -f .\imx-boot-nor.bin-flash_a55_flexspi -offset 0x10000 -skipfhdr SDPU: jump # } # These commands will be run when use SPL and will be skipped if no spl # if (SPL support SDPV) # { SDPV: delay 1000 SDPV: write -f .\imx-boot-nor.bin-flash_a55_flexspi -skipspl -skipfhdr SDPV: jump # } #######################second################################# FB: ucmd setenv fastboot_buffer ${loadaddr} FB: download -f .\imx-boot-imx95-19x19-lpddr5-evk-fspi.bin-flash_a55_flexspi FB: ucmd if test ! -n "$fastboot_bytes"; then setenv fastboot_bytes $filesize; else true; fi # Check Image if include flexspi header FB: ucmd if qspihdr dump ${fastboot_buffer}; then setenv qspihdr_exist yes; else setenv qspihdr_exist no; fi; # Check Image size if larger than 16M, then use uboot command to write image FB: ucmd if itest ${fastboot_bytes} -gt 1000000; then setenv qspihdr_large yes; else setenv qspihdr_large no; fi; FB[-t 60000]: ucmd if test ${qspihdr_exist} = yes -a ${qspihdr_large} = no; then qspihdr init ${fastboot_buffer} ${fastboot_bytes} safe; else true; fi; #if uboot can't support qspihdr command, use uboot image to write qspi image, which require image include qspi flash header FB: ucmd if test ${qspihdr_exist} = no; then sf probe; else true; fi; FB[-t 40000]: ucmd if test ${qspihdr_exist} = no; then sf erase 0 +${fastboot_bytes}; else true; fi; FB[-t 20000]: ucmd if test ${qspihdr_exist} = no; then sf write ${fastboot_buffer} 0 ${fastboot_bytes}; else true; fi; # if Image is larger than 16M, use uboot command to write image FB: ucmd if test ${qspihdr_large} = yes; then sf probe; else true; fi; FB: write -f .\imx-boot-imx95-19x19-lpddr5-evk-fspi.bin-flash_a55_flexspi -format "if test ${qspihdr_large} = yes; then sf erase @off +@size; sf write ${fastboot_buffer} @off @size; else true; fi;" -blksz 1 -each 0x100000 FB: done   3.2 U-Boot Patches The functionality implemented is: in the SPL stage, activate NOR FLASH (this is the default code setting), so that uboot.bin can be read from NOR during the SPL stage; then upon entering U-Boot, override the pinctrl settings in the DTB so that the FlexSPI driver uses the NAND pins, and then bring up the NAND on the M.2 connector during U-Boot initialization. imx95_19x19_evk_spinand_defconfig is based on the FSPI defconfig with MTD NAND configuration enabled in U-Boot. diff --git a/arch/arm/dts/imx95-19x19-evk-u-boot.dtsi b/arch/arm/dts/imx95-19x19-evk-u-boot.dtsi index 3c0c2d7b0f2..0d8fb0c3978 100644 --- a/arch/arm/dts/imx95-19x19-evk-u-boot.dtsi +++ b/arch/arm/dts/imx95-19x19-evk-u-boot.dtsi @@ -182,3 +182,7 @@ assigned-clock-parents = <0>, <&scmi_clk IMX95_CLK_HSIOPLL_VCO>, <&scmi_clk IMX95_CLK_SYSPLL1_PFD1_DIV2>; }; + +#ifdef CONFIG_MTD_SPI_NAND +#include "imx95-19x19-evk-spinand.dtsi" +#endif \ No newline at end of file diff --git a/board/freescale/imx95_evk/imx95_evk.c b/board/freescale/imx95_evk/imx95_evk.c index 9790c610ac7..333e051c090 100644 --- a/board/freescale/imx95_evk/imx95_evk.c +++ b/board/freescale/imx95_evk/imx95_evk.c @@ -22,6 +22,8 @@ #include <i2c.h> #include <dm/uclass.h> #include <dm/uclass-internal.h> +#include <dm.h> +#include <dm/device.h> extern int board_fix_fdt_fuse(void *fdt); @@ -383,6 +385,25 @@ void netc_init(void) pci_init(); } +static void flexspi_nor_fixup(void) +{ + struct gpio_desc desc; + int ret; + + ret = dm_gpio_lookup_name("GPIO5_10", &desc); + if (ret) + return; + + ret = dm_gpio_request(&desc, "XSPI1_SS0_B"); + if (ret) + return; + + dm_gpio_set_dir_flags(&desc, GPIOD_IS_OUT); + dm_gpio_set_value(&desc, 1); + + printf("flexspi_nor_fixup\n"); +} + static void flexspi_nor_steup(void) { struct gpio_desc desc; @@ -453,6 +474,78 @@ void lvds_backlight_on(void) dm_i2c_write(dev, 0x8, &reg, 1); } +static int fdt_switch_flexspi_pinctrl_to_nand(void *fdt) +{ + int off; + const void *prop; + int len; + int ret; + const char *flexspi_path = "/soc/bus@42000000/spi@425e0000"; + + off = fdt_path_offset(fdt, flexspi_path); + if (off < 0) { + printf("FDT: failed to find flexspi node %s, err=%d\n", + flexspi_path, off); + return off; + } + + prop = fdt_getprop(fdt, off, "pinctrl-1", &len); + if (!prop || len <= 0) { + printf("FDT: no pinctrl-1 found under %s\n", flexspi_path); + return -FDT_ERR_NOTFOUND; + } + + ret = fdt_setprop(fdt, off, "pinctrl-0", prop, len); + if (ret < 0) { + printf("FDT: failed to overwrite pinctrl-0, err=%d\n", ret); + return ret; + } + + printf("FDT: switched %s pinctrl-0 <- pinctrl-1 (NAND)\n", + flexspi_path); + + return 0; +} + +static void delete_fdt_flash0(void *fdt) +{ + int i = 0; + int nodeoff, ret; + static const char * const spi_nodes[] = { + "/soc/bus@42000000/spi@425e0000/flash@0" + }; + + printf("delete_fdt_flash0\n"); + + for (i = 0; i < ARRAY_SIZE(spi_nodes); i++) { + nodeoff = fdt_path_offset(fdt, spi_nodes[i]); + if (nodeoff >= 0) { +delete_node: + ret = fdt_del_node(fdt, nodeoff); + if (ret == -FDT_ERR_NOSPACE) { + ret = fdt_increase_size(fdt, 512); + if (!ret) { + nodeoff = fdt_path_offset(fdt, spi_nodes[i]); + if (nodeoff >= 0) + goto delete_node; + } + } + + if (ret) + printf("failed to delete node %s, ret=%d\n", + spi_nodes[i], ret); + else + printf("deleted node %s\n", spi_nodes[i]); + } + } +} + +static void fdt_fixup_flexspi(void *fdt) +{ + delete_fdt_flash0(fdt); + fdt_switch_flexspi_pinctrl_to_nand(fdt); +} + int board_init(void) { int ret; @@ -475,17 +568,50 @@ int board_init(void) netc_init(); - flexspi_nor_steup(); + // avoid NAND erase affect NOR with same FLEXSPI1_A_SS0_B + flexspi_nor_fixup(); power_on_m7("mx95evkrpmsg"); + printf("board_init\n"); + lvds_backlight_on(); return 0; } +static void debug_probe_fspi_nand(void) +{ + struct udevice *bus; + struct udevice *child; + int ret; + + printf("debug_probe_fspi_nand: start\n"); + + ret = uclass_get_device_by_name(UCLASS_SPI, "spi@425e0000", &bus); + printf("get spi bus ret=%d, bus=%p\n", ret, bus); + if (ret) + return; + + ret = device_probe(bus); + printf("probe spi bus ret=%d\n", ret); + + child = NULL; + device_find_first_child(bus, &child); + while (child) { + printf("child name=%s\n", child->name); + ret = device_probe(child); + printf("probe child %s ret=%d\n", child->name, ret); + device_find_next_child(&child); + } + + printf("debug_probe_fspi_nand: done\n"); +} + int board_late_init(void) { + printf("board_late_init\n"); + debug_probe_fspi_nand(); if (IS_ENABLED(CONFIG_ENV_IS_IN_MMC)) board_late_mmc_env_init(); @@ -645,6 +771,8 @@ static int board_fix_19x19_evk(void *fdt) int ret; const char *netcfg = "mx95netc"; + fdt_fixup_flexspi(fdt); + ret = scmi_misc_cfginfo(&msel, cfgname); if (!ret) { debug("SM: %s\n", cfgname); diff --git a/drivers/spi/nxp_fspi.c b/drivers/spi/nxp_fspi.c index 078b97f6544..07fb96cbfcc 100644 --- a/drivers/spi/nxp_fspi.c +++ b/drivers/spi/nxp_fspi.c @@ -1177,6 +1177,7 @@ static int nxp_fspi_default_setup(struct nxp_fspi *f) static int nxp_fspi_probe(struct udevice *bus) { + printf("------------>nxp_fspi_probe\n"); struct nxp_fspi *f = dev_get_priv(bus); f->devtype_data = @@ -1241,6 +1242,7 @@ static int nxp_fspi_of_to_plat(struct udevice *bus) #if CONFIG_IS_ENABLED(CLK) int ret; #endif + printf("------------>nxp_fspi_of_to_plat\n"); fdt_addr_t iobase; fdt_addr_t iobase_size; diff --git a/dts/upstream/src/arm64/freescale/imx95-19x19-evk.dts b/dts/upstream/src/arm64/freescale/imx95-19x19-evk.dts index 6086cb7fa5a..10e9f76c5af 100644 --- a/dts/upstream/src/arm64/freescale/imx95-19x19-evk.dts +++ b/dts/upstream/src/arm64/freescale/imx95-19x19-evk.dts @@ -194,11 +194,12 @@ }; &flexspi1 { - pinctrl-names = "default"; + pinctrl-names = "default", "nand"; pinctrl-0 = <&pinctrl_flexspi1>; + pinctrl-1 = <&pinctrl_flexspi1_nand>; status = "okay"; - flash@0 { + flash0: flash@0 { compatible = "jedec,spi-nor"; reg = <0>; pinctrl-names = "default"; @@ -445,6 +446,18 @@ >; }; + pinctrl_flexspi1_nand: flexspi1nandgrp { + fsl,pins = < + IMX95_PAD_XSPI1_SS0_B__GPIO5_IO_BIT10 0x3fe + IMX95_PAD_SD3_CMD__FLEXSPI1_A_SS0_B 0x3fe + IMX95_PAD_SD3_CLK__FLEXSPI1_A_SCLK 0x3fe + IMX95_PAD_SD3_DATA0__FLEXSPI1_A_DATA_BIT0 0x3fe + IMX95_PAD_SD3_DATA1__FLEXSPI1_A_DATA_BIT1 0x3fe + IMX95_PAD_SD3_DATA2__FLEXSPI1_A_DATA_BIT2 0x3fe + IMX95_PAD_SD3_DATA3__FLEXSPI1_A_DATA_BIT3 0x3fe + >; + }; + pinctrl_flexspi1_reset: flexspi1-reset-grp { fsl,pins = < IMX95_PAD_XSPI1_SS1_B__GPIO5_IO_BIT11 0x3fe   3.3 imx95-evk.inc Content require conf/machine/include/imx-base.inc require conf/machine/include/arm/armv8-2a/tune-cortexa55.inc MACHINE_FEATURES += "pci wifi bluetooth optee" MACHINE_FEATURES:append:use-nxp-bsp = " nxpwifi-all-pcie nxpwifi-all-sdio jailhouse dpdk xen" KERNEL_DEVICETREE = " \ freescale/${KERNEL_DEVICETREE_BASENAME}.dtb \ " UBOOT_DTB_NAME = "${KERNEL_DEVICETREE_BASENAME}.dtb" IMX_DEFAULT_BOOTLOADER:use-nxp-bsp = "u-boot-imx" IMX_DEFAULT_BOOTLOADER:use-mainline-bsp = "u-boot-fslc" LOADADDR = "" UBOOT_SUFFIX = "bin" UBOOT_MAKE_TARGET = "" SPL_BINARY = "spl/u-boot-spl.bin" UBOOT_CONFIG ??= "sd" UBOOT_CONFIG[sd] = "${UBOOT_CONFIG_BASENAME}_defconfig,sdcard" UBOOT_CONFIG[sd-ecc] = "${UBOOT_CONFIG_BASENAME}_defconfig,sdcard" UBOOT_CONFIG[fspi] = "${UBOOT_CONFIG_BASENAME}_spinand_defconfig"///////////////////here UBOOT_CONFIG[spinand] = "${UBOOT_CONFIG_BASENAME}_spinand_defconfig"////////////////here ATF_PLATFORM = "imx95" OEI_CORE = "m33" OEI_SOC = "mx95" OEI_BOARD ?= "mx95lp5" DDR_TYPE ?= "lpddr5" IMXBOOT_VARIANTS = "alt jailhouse netc rpmsg sof" # Multiple system manager configs by IMXBOOT_VARIANT SYSTEM_MANAGER_CONFIG = \ "${@bb.utils.contains('IMXBOOT_VARIANT', 'alt', 'mx95alt', \ bb.utils.contains('IMXBOOT_VARIANT', 'jailhouse', 'mx95evkjailhouse', \ bb.utils.contains('IMXBOOT_VARIANT', 'netc', 'mx95netc', \ bb.utils.contains('IMXBOOT_VARIANT', 'rpmsg', 'mx95evkrpmsg', \ bb.utils.contains('IMXBOOT_VARIANT', 'sof', 'mx95evksof', \ 'mx95evk', d), d), d), d), d)}" # imx-boot (flash.bin) targets based on UBOOT_CONFIG and IMXBOOT_VARIANT IMXBOOT_TARGETS_SD = " \ ${@bb.utils.contains('IMXBOOT_VARIANT', 'alt', '${IMXBOOT_TARGETS_BASENAME}_alt', \ bb.utils.contains('IMXBOOT_VARIANT', 'jailhouse', '${IMXBOOT_TARGETS_BASENAME}_jailhouse', \ bb.utils.contains('IMXBOOT_VARIANT', 'netc', '${IMXBOOT_TARGETS_BASENAME}_netc', \ bb.utils.contains('IMXBOOT_VARIANT', 'rpmsg', '${IMXBOOT_TARGETS_BASENAME}_lpboot_sm_a55', \ bb.utils.contains('IMXBOOT_VARIANT', 'sof', '${IMXBOOT_TARGETS_BASENAME}_a55', \ '${IMXBOOT_TARGETS_BASENAME}_all ${IMXBOOT_TARGETS_BASENAME}_a55', d), d), d), d), d)} \ " IMXBOOT_TARGETS = " \ ${@bb.utils.contains('UBOOT_CONFIG', 'fspi', '${IMXBOOT_TARGETS_BASENAME}_a55_flexspi', \ bb.utils.contains('UBOOT_CONFIG', 'sd-ecc', '${IMXBOOT_TARGETS_BASENAME}_all', \ '${IMXBOOT_TARGETS_SD}', d), d)} \ " IMX_BOOT_SOC_TARGET = "iMX95" IMX_BOOT_SEEK = "32" # We have to disable SERIAL_CONSOLE due to auto-serial-console SERIAL_CONSOLES = "115200;ttyLP0" IMX_DEFAULT_BSP = "nxp"   4. NOR Boot Test After NOR boot, U-Boot activates the NAND on the M.2 connector, successfully reads the kernel and device tree from NAND. After entering the kernel, the rootfs is successfully mounted. U-Boot SPL 2025.04-g4ddbad60eff3-dirty (Mar 19 2026 - 03:13:58 +0000) SYS Boot reason: por, origin: -1, errid: -1 SYS shutdown reason: por, origin: -1, errid: -1 Normal Boot Trying to boot from SPI ------------>nxp_fspi_of_to_plat ------------>nxp_fspi_probe Boot stage: Primary Image set: 0, offset: 0x1000 Load image from QSPI 0xde400------------------------------->NOR BOOT NOTICE: BL31: v2.12.0(release):lf-6.12.49-2.2.0 NOTICE: BL31: Built : 10:35:59, Apr 21 2026 U-Boot 2025.04-g4ddbad60eff3-dirty (Mar 19 2026 - 03:13:58 +0000) CPU: i.MX9596 rev2.0 at 1800MHz CPU: Extended Industrial temperature grade (-40C to 125C) at 28C LM Boot reason: por, origin: -1, errid: -1 LM shutdown reason: por, origin: -1, errid: -1 Model: NXP i.MX95 19X19 board DRAM: delete_fdt_flash0 deleted node /soc/bus@42000000/spi@425e0000/flash@0 FDT: switched /soc/bus@42000000/spi@425e0000 pinctrl-0 <- pinctrl-1 (NAND) 15.8 GiB TCPC: Vendor ID [0x1fc9], Product ID [0x5110], Addr [I2C6 0x50] PCIE-2: Link down PCIE-3: Link down cfg name not match mx95evkrpmsg:mx95evk, ignore board_init Core: 317 devices, 38 uclasses, devicetree: separate MMC: FSL_SDHC: 0, FSL_SDHC: 1 Loading Environment from nowhere... OK [*]-Video Link 0clk disp1pix already disabled adv7535_mipi2hdmi hdmi@3d: Can't find cec device id=0x3c fail to probe panel device hdmi@3d probe video device failed, ret -19 [0] display-controller@4b400000, video [1] channel@0, video_bridge [2] bridge@8, video_bridge [3] dsi@4acf0000, video_bridge [4] hdmi@3d, panel clk disp1pix already disabled adv7535_mipi2hdmi hdmi@3d: Can't find cec device id=0x3c fail to probe panel device hdmi@3d probe video device failed, ret -19 In: serial Out: serial Err: serial BuildInfo: - SM firmware Build 763, Commit de30901b, Apr 15 2026 01:18:07 - ELE firmware version 2.0.4-9ca4d997 board_late_init debug_probe_fspi_nand: start ------------>nxp_fspi_of_to_plat ------------>nxp_fspi_probe get spi bus ret=0, bus=00000000fd4a13d0 probe spi bus ret=0 child name=mt29f4g01abbfd12@0 probe child mt29f4g01abbfd12@0 ret=0----------------->SWITCH TO NAND debug_probe_fspi_nand: done UID: 182ba9e87d9840babd9d12161b48e82d Net: eth0: enetc-0 [PRIME], eth1: enetc-2 Fastboot: Normal Normal Boot Hit any key to stop autoboot: 0 u-boot=> setenv bootargs 'console=ttyLP0,115200 earlycon ubi.mtd=rootfs root=ubi0:nandrootfs rootfstype=ubifs rootwait rw' u-boot=> mtd read kernel ${loadaddr} 0 0x2800000 Reading 41943040 byte(s) (20480 page(s)) at offset 0x00000000 u-boot=> mtd read dtb ${fdt_addr} 0 0x20000 Reading 131072 byte(s) (64 page(s)) at offset 0x00000000 u-boot=> booti ${loadaddr} - ${fdt_addr} ------------------>read kernel, dtb in NAND ## Flattened Device Tree blob at 93000000 Booting using the fdt blob at 0x93000000 Working FDT set to 93000000 Loading Device Tree to 000000009ffe5000, end 000000009ffffeaf ... OK Working FDT set to 9ffe5000 clk disp1pix already disabled adv7535_mipi2hdmi hdmi@3d: Can't find cec device id=0x3c fail to probe panel device hdmi@3d probe video device failed, ret -19 Starting kernel ... [ 0.000000] Booting Linux on physical CPU 0x0000000000 [0x412fd050] [ 0.000000] Linux version 6.18.2-1.0.0-gf49f45233f7b-dirty (oe-user@oe-host) (aarch64-poky-linux-gcc (GCC) 15.2.0, GNU ld (GNU Binutils) 2.45.0.20250908) #1 SMP PREEMPT Tue Apr 28 08:20:17 UTC 2026 [ 0.000000] KASLR enabled [ 0.000000] Machine model: NXP i.MX95 19X19 board [ 0.000000] efi: UEFI not found. [ 0.000000] Reserved memory: created CMA memory pool at 0x00000000c3000000, size 960 MiB [ 0.000000] OF: reserved mem: initialized node linux,cma, compatible id shared-dma-pool [ 0.000000] OF: reserved mem: 0x00000000c3000000..0x00000000feffffff (983040 KiB) map reusable linux,cma [ 0.000000] earlycon: lpuart32 at MMIO32 0x0000000044380000 (options '') ................... [ 2.416067] spi-nand spi1.0: Winbond SPI NAND was found. [ 2.428075] spi-nand spi1.0: 256 MiB, block size: 128 KiB, page size: 2048, OOB size: 128 [ 2.450050] 5 fixed-partitions partitions found on MTD device spi1.0 [ 2.450059] Creating 5 MTD partitions on "spi1.0": [ 2.463548] 0x000000000000-0x000000800000 : "bootloader" [ 2.529065] 0x000000800000-0x000001000000 : "config" [ 2.543539] 0x000001000000-0x000003800000 : "kernel" [ 2.580906] 0x000003800000-0x000003820000 : "dtb" [ 2.586513] 0x000003820000-0x00010381ffff : "rootfs" [ 2.591493] mtd: partition "rootfs" extends beyond the end of device "spi1.0" -- size truncated to 0xc7e0000 [ 2.748893] mtd: setting mtd4 (rootfs) as root device [ 4.909898] ubi0: attaching mtd4 [ 5.406361] ubi0: scanning is finished [ 5.454338] ubi0: attached mtd4 (name "rootfs", size 199 MiB) [ 5.460134] ubi0: PEB size: 131072 bytes (128 KiB), LEB size: 126976 bytes [ 5.467131] ubi0: min./max. I/O unit sizes: 2048/2048, sub-page size 2048 [ 5.473950] ubi0: VID header offset: 2048 (aligned 2048), data offset: 4096 [ 5.480935] ubi0: good PEBs: 1599, bad PEBs: 0, corrupted PEBs: 0 [ 5.487037] ubi0: user volume: 1, internal volumes: 1, max. volumes count: 128 [ 5.494255] ubi0: max/mean erase counter: 10/1, WL threshold: 4096, image sequence number: 2909496578 [ 5.503473] ubi0: available PEBs: 0, total reserved PEBs: 1599, PEBs reserved for bad PEB handling: 40 [ 5.512840] ubi0: background thread "ubi_bgt0d" started, PID 135 [ 5.594576] UBIFS (ubi0:0): Mounting in unauthenticated mode [ 5.600411] UBIFS (ubi0:0): background thread "ubifs_bgt0_0" started, PID 141 [ 5.617312] UBIFS (ubi0:0): recovery needed [ 5.801795] UBIFS (ubi0:0): recovery completed [ 5.806343] UBIFS (ubi0:0): UBIFS: mounted UBI device 0, volume 0, name "nandrootfs" [ 5.814101] UBIFS (ubi0:0): LEB size: 126976 bytes (124 KiB), min./max. I/O unit sizes: 2048 bytes/2048 bytes [ 5.824021] UBIFS (ubi0:0): FS size: 195923968 bytes (186 MiB, 1543 LEBs), max 1555 LEBs, journal size 9777152 bytes (9 MiB, 77 LEBs) [ 5.836024] UBIFS (ubi0:0): reserved for root: 4952683 bytes (4836 KiB) [ 5.842640] UBIFS (ubi0:0): media format: w5/r0 (latest is w5/r0), UUID 02E616B2-3C31-4F48-A886-9B4D26DB37C1, small LPT model [ 5.854616] VFS: Mounted root (ubifs filesystem) on device 0:23. [ 5.860973] devtmpfs: mounted [ 5.864349] Freeing unused kernel memory: 2112K [ 5.868991] Run /sbin/init as init process [ 5.874243] Run /etc/init as init process [ 5.879058] Run /bin/init as init process [ 5.884114] Run /bin/sh as init process  
View full article
Attached slides introduce the i.MX95 Power management with following topics: SoC Power Architecture Power Management with BSP Power on/off & Reboot Suspend Implementation Low Power Run
View full article
GUI Guider version:  1.9.x, 1.10.x LVGL version: v8.x.x , v9.x.x Host software requirements: Ubuntu 20.04, Ubuntu 22.04 or Debian 12 Target  software requirements:  BSP 6.6 or higher  Hardware requirements: FRDM i.MX 93 Development Board i.MX 93 Evaluation Kit FRDM i.MX 91 Development Board i.MX 91 Evaluation Kit i.MX95  Steps: 1. Export your project from the folder GUI-Guider-Projects to your Linux PC. 2. Build an image for iMX9 using The Yocto Project. Based on iMX Yocto Porject Users Guide set directories and download the repo a. Based on iMX Yocto Porject Users Guide set directories and download the repo $ mkdir imx-bsp-6.6 $ cd imx-bsp-6.6 $: repo init -u https://github.com/nxp-imx/imx-manifest -b imx-linux-scarthgap -m imx-6.6.52-2.2.0.xml $ repo sync Use distro fsl-imx-xwayland and select machine imx93evk and use this commnad with a build folder name: $ MACHINE=imx93evk DISTRO=fsl-imx-xwayland source ./imx-setup-release.sh - b bld-imx93evk b. Use bitbake command to start the build process. Also, add the -c populate_sdk to get the toolchain. $ bitbake imx-image-full -c populate_sdk  c. Install the Yocto toolchain located on <build-folder>/tmp/deploy/sdk/.  $ sudo sh ./fsl-imx-xwayland-glibc-x86_64-imx-image-full-armv8a-imx93evk-toolchain-6.6-scarthgap.sh d. Install ninja utility on the build host $ sudo apt update $ sudo apt upgrade -y $ sudo apt install ninja-build   3. Once your Yocto SDK has been generated and installed, you can build the required binaries using the script attached to this post.      a) Place the script           Copy the script into the same directory where your meta-gui-guider folder is located.      b) Run the script to build the Gui Guider binary           The script includes several options to rebuild, clean, or use a different toolchain in                case you are working with a Yocto SDK version other than the default one (6.6-scarthgap). Build Options Build the Gui Guider binary using the default Yocto SDK ./guider_1.9_project_builder.sh Build the Gui Guider binary using another Yocto SDK version ./guider_1.9_project_builder.sh -t <yocto_sdk_path>/sysroots/x86_64-pokysdk-linux/usr/share/cmake/armv8a-poky-linux-toolchain.cmake Prepare the source code before building ./guider_1.9_project_builder.sh -p Clean the previous build and recompile (Use -t if needed to specify a different toolchain) ./guider_1.9_project_builder.sh -c   4. The generated Gui Guider binary can be found at the following path: /meta-gui-guider/recipes-graphics/gui-guider/gui-guider/build/gui_guider Copy this binary to your board using either USB or SCP, and then execute it directly on the target device.   Using this method provides the flexibility to modify the source code before compilation. This is important because, by default, some configuration options are not available when using Gui Guider directly or when compiling inside Yocto. If you encounter any issues during this process, please open a new thread so we can assist you. Best regards, Chavira
View full article
This patch series enables the external 3.3 V and 5 V power rails used by the Raspberry Pi expansion connector on the i.MX93-QSB, i.MX93-FRDM, and i.MX91-FRDM boards. These regulators were already defined in the device tree but left disabled by default. By activating them, the RPI-compatible expansion header can properly power external modules, HATs, and add‑on boards. Changes by board: i.MX93-QSB Enables the 3.3 V and 5 V external supply lines used by the RPI connector.   i.MX93-FRDM Enables the 3.3 V and 5 V external supply lines used by the RPI connector.   i.MX91-FRDM Enables the 3.3 V and 5 V external supply lines used by the RPI connector.   Purpose: Provide proper power to the Raspberry Pi compatible expansion port. Improve hardware compatibility for users attaching external HATs or modules. Align all i.MX9 reference boards to use a consistent power‑tree configuration for the RPI connector.
View full article
The purpose of this document is to provide extended guidance for selection of compatible LPDDR4 memory devices that are supported by the Ara240 (aka Ara-2) processors. In all cases, it is strongly recommended to follow the DRAM layout guidelines outlined in the specific SoC requirement documents. LPDDR4 - maximum supported densities SoC Max Data bus width Maximum density Number of Interfaces Assumed memory organization Notes Ara240 64-bit 128Gb/16GB 2 Dual rank, Dual channel device with 17-row addresses 1   LPDDR4 - list of validated memories The validation process is an ongoing effort - regular updates of the table are expected. SoC Density Memory Vendor Validated Memory Part# Notes Ara240 64Gb/(8GB) Total 128Gb/(16GB) (2 x 64Gb/8GB) Micron   MT53E2G32D4DE-046 AUT:C  MT53E2G32D4DE-046 WT:C - 64Gb/(8GB) Total 128Gb/(16GB) (2 x 64Gb/8GB)   FORESEE FLXC4008G-30  2 16Gb/(2GB) Total: 32Gb/(4GB) (2 x 16Gb/2GB) Micron MT53E512M32D1ZW-046BAUT:B     - 32Gb/(4GB) Total 64Gb/8GB (2 x 32Gb/4GB)   Micron MT53E1G32D2NP-046 WT:B - 16Gb/(2GB) Total: 32Gb/(4GB) (2 x 16Gb/2GB) SK Hynix H54G46CYRQX053N - 32Gb/(4GB) Total 64Gb/8GB (2 x 32Gb/4GB) SK Hynix H54G56CYRB-X247 421Y H54G56CYRB-X247 316A - 4Gb/(512MB) Total 8Gb/1GB (2 x 4Gb/1GB) SK Hynix H54G26AYRBX256 - 16Gb/(2GB) Total: 32Gb/(4GB) (2 x 16Gb/2GB) Samsung K4F6E3S4HB-KHCL      - 32Gb/(4GB) Total 64Gb/8GB (2 x 32Gb/4GB) ISSI IS43LQ32K01B 2 32Gb/(4GB) Total 64Gb/8GB (2 x 32Gb/4GB) Samsung K4UBE3D4AB-MGCL - 8Gb/(1GB) Total 16Gb/2GB (2 x 8Gb/1GB)   Winbond W66DP2RQQAHJ 2   Note: This device supports operation with LPDDR4 memories only. LPDDR4x operation is not supported. Dual‑mode memories that support both LPDDR4 and LPDDR4x are allowed as long as the device can operate in LPDDR4 mode, including using LPDDR4 I/O voltage levels and initialization sequences.   Note 1: The numbers are based purely on the IP documentation for the DDR Controller and the DDR PHY, on the settings of the implementation parameters chosen for their integration into the SoC, SoC reference manual and on the JEDEC standards JESD209-4C (LPDDR4). Therefore, they are not backed by validation, unless said otherwise and there is no guarantee that an SoC with the specific density and/or desired internal organization is offered by the memory vendors. Should the customers choose to use the maximum density and assume it in the intended use case, they do it at their own risk. Note 2: The memory part number did not undergo full JEDEC verification however, it passed all functional testing items. Note 3: Memory devices with binary densities (e.g., 1 GB, 2 GB, 4 GB) are preferred because they simplify memory management by aligning with system addressing schemes and reducing software complexity. Note 4: All memory parts are in production unless stated otherwise. Checked June 2026 Note 5: The processor does not support BYTE Mode (x8) memories.       
View full article
There are two ways to enable support for the imx95-19x19-evk board:   1.  Directly replace the flash.bin from the Yocto release. 1). depoly LSDK2512 on imx95-15x15-evk board which is supported in Debian LSDK2512     A:    $ flex-installer -i pf -d /dev/sdX -F     B: $ flex-installer -i auto -m imx95evk -d /dev/sdX   2). Download prebuild flash.bin for imx95-19x19-evk board from Yocto release:     A: download: https://www.nxp.com/webapp/sps/download/license.jsp? colCode=L6.12.20-2.0.0_MX95&appType=file1&DOWNLOAD_ID=null     B: Extract the downloaded file to obtain the flash.bin file: imx-boot-imx95-19x19-lpddr5-evk-sd.bin-flash_all   3). Overwrite flash.bin     $ sudo umount /dev/sdX; sudo dd if=imx-boot-imx95-19x19-lpddr5-evk-sd.bin-flash_all of=/dev/sdX bs=1024 seek=32   4). Insert the prepared SD card into the board and power it on. After entering the U-Boot prompt, set the boot command:     => setenv bootcmd "setenv bootargs 'root=/dev/mmcblk1p3 rw rootwait console=ttyLP0,115200 earlycon';ext2load mmc 1:1 0x90400000 Image;ext2load mmc 1:1 0x93000000 imx95-19x19-evk.dtb;booti 0x90400000 - 0x93000000"; saveenv     => reset   The Debian system will start automatically.   2. Build the BSP image using FlexBuild: 1).  clone the Flexbuild source code and apply the patch as attached. 2). build the bsp and boot images:       $ bld bsp -m imx95evk       $ bld boot -m imx95evk or download the pre-built image at: http://sun.ap.freescale.net/images/debian/lsdk2512/firmware_imx95evk_19x19_sdboot.img 3). install the image:       $ ./flex-installer -f firmware_imx95evk_sdboot.img -d /dev/sdX -m imx95evk -b boot_IMX_arm64_lts_6.12.20.tar.zst -r rootfs_lsdk2512_debian_imx95evk.tar.zst 4).  Insert the prepared SD card into the board and power it on. After entering the U-Boot prompt, run the following command to boot board:       u-boot=> bootflow scan -lb
View full article
System Manager configuration via Config tools for i.MX. Create a new project, modify, view or edit available resources for your specific core. What will you learn How to create a new System Manager project Viewing and managing resources Creating and assigning templates Configuration of System Manager Tip: you can skip to a specific chapter   Introduction   New System Manager project     System Manager views   System Manager templates   Assigning a resource   Creating custom template   Exporting code     Download the tools here: https://www.nxp.com/design/design-center/development-boards-and-designs/i-mx-evaluation-and-development-boards/config-tools-for-i-mx-applications-processors:CONFIG-TOOLS-IMX   https://www.nxp.com/products/i.MX95
View full article
Legacy Interrupts in PCI have become a thing of the past in the PCI world, now that we have more efficient MSI interrupts in PCI Express, being used extensively across applications. However they are still used primarily for backward compatibility and boot-up support. Legacy Interrupts[INTx] used to be physical signals in PCI, however PCIe devices do not have physical INTx pins. So to support these legacy interrupts, PCIe emulates them logically. Almost like a virtual INTx mechanism. We shall see how these interrupts are realized in PCI Express, in such a way that developers/enthusiasts can get a hands-on following this guide. This blog has the following agendas:- 1. Why do we need to care about Legacy INTx style interrupts in PCIe? 2. System Overview 3. How are INTx legacy interrupts realized in PCIe? 4. Enabling and testing INTx emulation on iMX8MM
View full article
The purpose of this page is to provide supportive information for the selection of suitable camera modules that are supported by the i.MX 8M Plus (i.MX8MP). The guide is attached in this page. This helps customers evaluate project feasibility and integration aspects when considering i.MX 8MP SoCs for their products. It is strongly recommended to consult with NXP and the camera module vendor before finalizing the choice of the camera part number to ensure compatibility, availability, longevity, and pricing requirements. NXP Supported Sensors: Sensor Vendor Image Sensor Max Resolution Camera Module OmniVision OS08A20 8MP IMX-OS08A20 EXPI-OS08A20 OmniVision OV2775 2MP   Sony IMX219 8MP   Sony IMX477 12.3MP   Onsemi AR0144 1MP AR0144 Onsemi AR1335 13MP     Partner Enabled Sensors:   Partner Sensor Vendor Image Sensor Max Resolution ISP Tuning Camera Module Location FRAMOS Sony IMX415 8MP ✔   Munich, Germany/ Canada/USA Sony IMX662 2MP FSM:GO Sony IMX678 8MP Sony IMX900 3.2MP Sony IMX676 12MP Innowave Onsemi AR1335 13MP ✔   Austin, Texas, USA/Israel Sony IMX258 13MP Camera Modules Sony IMX219 8MP OmniVision OV5645 5MP   OmniVision OV2710 2MP   Basler Onsemi AR0821 8MP   Basler   Onsemi AR0521 5MP   Onsemi Onsemi AR0830 8MP   Image Sensors, Module available through Future Electronics   Onsemi AR0544 5MP Onsemi AR0821 8MP Onsemi AR0822 8MP Onsemi AR0145 1MP Onsemi AR0235 2MP Onsemi AR1335 13MP PHYTEC Onsemi AR0144 1MP     Germany/ China/India/ USA Onsemi AR0234 2.3MP   Onsemi AR0521 5MP   E-consystems Sony IMX662 2.4MP     Riverside, CA, USA/India Sony IMX900 3.2MP   Onsemi AR0234 2.3MP   CIS Corporation Sony IMX715 12MP ✔   Japan Sony IMX570 0.32MP   Onsemi AR0234CS 2MP   Sony Sony IMX500 12MP     Japan HINO Engg Sony IMX415 8MP ✔   Japan Sony IMX662 2MP   Leopard Imaging Sony IMX500 12MP ✔   Fremont, CA, USA/China   Note: CIS Corporation and HINO Engg currently only support customers in Japan market.
View full article
lspci output on iMX95EVK as PCIe RC Please take a good look at the snippet above. It is taken from the console of iMX95 after executing 'lspci' on a specific PCIe device[iMX8MM as PCIe EP] that gets enumerated as BDF[Bus Device Function] 01:00.0. This blog attempts to debunk the mystery revolving around the "Memory at " info of the lspci output. We will discuss what this address is, why it is used and its relevance in the PCIe world. This blog will focus on the following agendas: - 1. PCIe parent and child relationship in Linux Device Tree 2. What is CPU and PCIe address space and the need for address space translation?  3. Assigning resources to a PCIe device in Linux 4. How is address space translation carried out in Linux PCI Subsystem?   PCIe parent and child relationship in Linux Device Tree In the Linux device tree, PCIe parent and child relationship defines how PCIe Root Complex and Endpoints are positioned in the system. A PCIe parent node in the device tree represents a PCIe controller (Root Complex / Host-Bridge). Taking reference from a PCIe node present in the device tree source of imx95: -   pcie@4c300000 {                         compatible = "fsl,imx95-pcie";                         reg = <0x00 0x4c300000 0x00 0x10000 0x00 0x4c360000 0x00 0x20000 0x00 0x60100000 0x00 0xfe00000>;                         reg-names = "dbi\0atu\0config";                         #address-cells = <0x03>   …  }   pcie@4c300000 represents a Designware PCIe controller Root Complex which is a parent to the devices/bridge that will be connected to it. -- 'compatible' property identifies the specific PCIe controller. Its corresponding driver resides in drivers/pci/controller/dwc/pci-imx6.c -- 'reg' property specifies the memory mapped registers of the PCIe controller. Child nodes under PCIe RC represent devices on the PCIe bus. They can be fixed function devices like Wi-fi, Ethernet, NVMe or they can be PCIe bridges which further can have devices connected to it. Taking reference from 'arch/arm64/boot/dts/freescale/imx95.dtsi'   pcie_4ca00000: pcie@4ca00000 {                         compatible = "pci-host-ecam-generic";                         reg = <0x0 0x4ca00000 0x0 0x100000>;                         /* Must be 3. */              …              …              enetc_port0: ethernet@0,0 {                                 compatible = "fsl,imx95-enetc";                                 reg = <0x000000 0 0 0 0>;                                 clocks = <&scmi_clk IMX95_CLK_ENET>,                                          <&scmi_clk IMX95_CLK_ENETREF>;                                 clock-names = "ipg_clk", "enet_ref_clk";                                 nvmem-cells = <&eth_mac0>;                                 nvmem-cell-names = "mac-address";                                 status = "disabled";                         }; }   ethernet@0,0 is a PCIe device at bus 0, device 0, function 0. It is a child of PCIe RC which is memory mapped at 0x4ca00000   These child devices/bridges can either be dynamically discovered using PCI enumeration or they can be statically described in a device tree as seen in the device-tree snippet above in which "ethernet@0,0" entry statically tells the RC that the ethernet child device is connected to it. These child nodes are nested within a PCI parent node of the device tree as seen in the above example.   What is CPU and PCIe address space and the need for address space translation ? CPU address space is the system's physical memory map as seen by the processor. Example of CPU Physical Address Space viewed by Cortex-A55 on iMX95:-   Start address      End address    Module 0x48000000       0x4812FFFF    GIC Programming registers 0x4AA00000      0x4AAFFFFF    Neutron SRAM 0x4AC10000      0x4AC1FFFF    Camera domain block control 0x4E080000       0x4E08FFFF    DDR Controller This address space is kind of a global system view which is managed by system firmware/OS. These addresses are fixed by hardware-design. On the other hand, PCIe address space is local to PCI bus, managed by PCIe subsystem. The  addresses in this space are dynamically assigned. An example of PCIe address space that could look like the following:- 0x00000000   -    0x0FFFFFFF 0x10000000   -    0x1FFFFFFF 0x20000000   -    0x2FFFFFFF It is evident from the above explanation that CPU and PCIe address space operate in a separate and independent address domains. So the CPU cannot access the space of PCIe device unless a translation mechanism is in place. In one of the upcoming sections we will get to that as well but please spare a few minutes and ponder the question below:- Question : Why do you need separate address spaces for CPU and PCIe? Answer : One of the major reasons is modularity. We have separate spaces so that PCIe devices can be designed independently of the CPU architecture. Same card will work in different system. It will always have the flexibility of CPU remapping the PCIe space as and when needed. Also, different address spaces prevent devices to access arbitrary system memory. Based on the discussion in this section, it is evident that the PCIe address space is inherently different from the CPU address space and truth be told- it has its advantages. Therefore we need an entity to translate to/fro these address spaces. Here comes 'iATU' - Internal Address Translation Unit. On iMX SOCs, these hardware units are responsible for carrying out the address translation. These units are a part of Synopsys DesignWare PCIe Controller, providing programmable address translation windows for inbound and outbound transactions. For the readers who are uninitiated on the inbound and outbound transactions in pcie, please spare some time go through this technical blog - Understanding PCIe Outbound/Inbound windows with a use-case - NXP Community Note: - Address translation simply ensures that the CPU can access a PCIe device's memory and vice-versa.   Up until here, the readers must have got a basic picture of PCIe Address Translation. Before jumping into the nitty-gritty of this translation in the Linux PCI subsystem, let's discuss how the resources are assigned to a PCIe device.   Assigning resources to a PCIe device in Linux PCIe devices do not have a direct CPU instruction interface so they communicate through memory-mapped regions. Devices need memory for DMA operations or for MSI/MSIX interrupts. Different devices have different needs, so resources in PCIe could be MMIO where device registers are mapped or memory regions needed for DMA transfer. In linux, pci_assign_resource function of PCI subsystem is responsible for assigning IO and memory resources to the PCIe devices during system initialisation after PCIe devices are enumerated. It is called for all the devices on a PCI bus and based on the PCI devices' resource requirement, it assigns them. But how does the PCI subsystem in linux figure out what resources does the PCIe devices need ? - Every PCIe device has a configuration space defined by the PCIe specification. This includes   BAR[Base Address Registers] - To indicate what type of resource[IO/Mem] does  the device needs and the size of resource. Capabilities - To broadcast the device capabilities such as MSI Interrupts, ASPM low power states etc. Reading the BARs from the PCIe device will tell us what kind and size of the resources are needed by the device. // To determine the size of resource from the BAR of PCIe device:- Step-1: Write all 1's to the target BAR register. Step-2: Read back the value and clear the lower 4 bits (for a memory BAR) or 2 bits (for an I/O BAR), as these are status bits, not part of the size calculation Step-3 Perform Bitwise NOT on the value and add 1 to it. Step-4: The returned value indicates the size. Taking an example to understand this:- Let's assume that after reading back the value in Step-2 above, the BAR returns 0xFFFFF000. The lower 4 bits are already cleared. Step-3  we perform bitwise NOT on the value -> ~(0xFFFFF000) = 0x00000FFF Adding 1 to it : 0x00000FFF + 1 = 0x00001000 The obtained value 0x1000 = 4096 bytes indicates the size, meaning the BAR requires a 4KB memory region. // To determine the type of resource from the BAR of PCIe device:-   A Base Address Register (BAR) in PCI configuration space: Bit 0 → Resource type: 1 = I/O space 0 = Memory space For memory BARs: 00 = 32-bit 10 = 64-bit Bits 1–2 → Addressing type: Bit 3 → Prefetchable flag   Interpreting the value 0xFFFFF000, we get:-   Bit 0 = 0 → Memory space Bits 1–2 = 00 → 32-bit address Bit 3 = 0 → Prefetchable Upper bits → Base address (after masking)   pci_read_bases [drivers/pci/probe.c] in linux PCI subsystem is responsible to figure out the BAR memory size and type requirement during device enumeration. Needless to say, the above sequence of writing to the Endpoint's BAR and identifying the size and type of resource is executed on the PCIe RC. We have the following setup :- iMX95 <------> iMX8MM [RC]                     [EP] After PCIe RC has the size of the BAR that is required, the pci_assign_resource function allocates a memory range and then sets up translation from this memory range to the PCIe address space. we started this blog with a snippet, that shows the following lspci log:-   Referring to the above, please note that the RC driver has allocated: - 0x910100000 - 0x910110000 as the non-prefetchable memory address range, size=64KB The above memory address range is in the PCIe 1 Outbound space memory mapped on iMX95 SoC: -   The range 0x910100000 - 0x910110000 will be mapped to the PCIe address space of the End-point. This essentially means that if the cpu generates any address in between this range [inclusive of start and end-address], a PCIe TLP will be sent by the PCIe controller on the RC to the End-point on the bus. It could be a read or write to the memory of Endpoint. The address to write/read would be decided based on the address space translation. We shall discuss in-detail how this translation is exercised in the linux kernel in the next section.   How is address space translation carried out in Linux PCI Subsystem?   We start with some important questions: - Where is the range 0x910100000 - 0x910110000 specified ? How does the kernel know that it has to map the PCIe 1 Outbound space and not PCIe2 Outbound space or any other address space for that matter? -- Like all good things in Linux, this also starts with a 'device tree binary'. A dtb is passed by Uboot to the kernel so that it could get the hardware description of our board. Since we are using Torradex 's Verdin iMX95 EVK Board as Root Complex, this is the dtb that we are using - imx95-19x19-verdin-adv7535.dtb I will be attaching a working dtb with this blog so that the readers can use it if needed. This dtb includes - arch/arm64/boot/dts/freescale/imx95.dtsi Let's have a look at a particular pcie node of interest: -   'ranges' property is the answer to the questions that were asked in this section earlier.  - This property defines the address translation rules between the parent's address space and the child PCI address space.   Note:- This blog focuses only on 'ranges' property since it is relevant to our discussion. So the readers are advised to look elsewhere if they want to understand other device-tree properties of the PCIe node.  Let's decode the ranges property : It has the following format:- <PCI address><CPU address> <PCI size>      3 cells               2 cells             2 cells             So one entry will have 7 cells. In our dtsi we have 2 entries. 1st is for IO space translation and the 2nd is for Mem space translation. Referring to the second entry  :-   0x82000000 0x0 0x10000000 0x9 0x10000000 0 0x10000000 |------PCI address---------------| |-CPU address-| |---PCI size---|   The above gives us the following info: - MEM Space prefetchable <   0x82000000 0x00 0x10000000   // PCIe address: 0x10000000   0x09 0x10000000              // CPU/system address: 0x910000000   0x00 0x10000000              // Size: 256MB >;   0x82000000 = 1000 0010 0000 0000 0000 0000 0000 0000   Bits 31–30 (10) → Configuration space type: This indicates memory space. Bit 29 (0) → Non-relocatable Bit 28 (1) → Prefetchable = No (0 means non-prefetchable) Bits 27–24 (0010) → Address space type = Memory So, 0x82000000 means: PCI memory space Non-prefetchable 32-bit address space   Note:- For those of you wondering why lspci output mentions [size=64K] and dts says 256 MB. This is because 256MB is the maximum address space available for the PCIe devices. It is upto the Endpoint device, how large address space does it require and accordingly it gets allocated.     Similary IO space translation is also created from the 1st entry in 'ranges':- < 0x81000000 0x00 0x00 → PCI I/O address: 0x00000000 0x00 0x6ff00000 → CPU/system address: 0x6ff00000 0x00 0x100000 → Size: 1MB >;   we observe the same in the dmesg output of iMX95 Verdin EVK Linux console:-   So the MEM Space mapping is from CPU Address 0x910000000 - 0x091fffffff translated to PCIe Address 0x10000000 - 0x1fffffff It is only fair that we mention the driver that uses the 'ranges' property. The 'ranges' property get parsed in "pci_parse_request_of_pci_ranges -> devm_of_pci_get_host_bridge_resources" of "drivers/pci/of.c"     devm_of_pci_get_host_bridge_resources, for each range automatically  manages the memory allocated for these resources. It ensures that the resources are freed when the device is detached or the driver is removed. We have got the answer what & why is the cpu and pci address range the way it is. But in the lspci, you see 0x910100000 and not 0x910000000 which is what the intended start range is supposed to be as per the dtb. Why is that ? To answer this - we need to go back to the PCIe device enumeration. During PCIe enumeration, in the linux PCI driver the bar resources were determined like we had discussed earlier and then the PCI core driver may assign addresses keeping alignment requirements in mind that is why EP's BAR0 was assigned a PCI bus address as 0x10100000 with a 1MB[0x100000] offset from 0x10000000. And keeping the device tree pci translation window in mind:- 0x10100000 translates to 0x910100000 This translation doesn't happen on its own. Device tree binary just mentions the translation window specifics such as the CPU address space to translate to and the PCI address space to translate from. The actual translation is done via iATU. This is done in the dw_pcie_iatu_setup function of drivers/pci/controller/dwc/pcie-designware-host.c by creating the outbound window using dw_pcie_prog_outbound_atu function. Translation is configured on the RC successfully but there is still something missing. .. .. Inbound window !! Without an inbound window on the Endpoint i.e iMX8MM, the writes/reads to 0x910100000 would be meaningless. On iMX8MM we are using PCI Endpoint test driver which is quite popular in linux community and I would urge the readers to visit this page if they want more info - 9. PCI Endpoint Framework — The Linux Kernel documentation pci_epc_map_addr function in drivers/pci/endpoint/pci-epc-core.c creates inbound window by mapping PCI address [0x10100000] to physical address in EP's memory. That's how the reads and writes go through. If there's no Inbound window configured, something like this unfolds in case of read:-   So now everything is set up. Translation windows are configured in the PCI drivers and you are at linux console. The following sequence unfolds when the CPU issues a memory read:-   In case of memory writes:- The following happens on the Endpoint: - The beauty is that this entire translation happens transparently in hardware - your driver just reads/writes to the CPU address, and the PCI host controller handles all the translation automatically! -- How do we test the Address Translation ?   To test reads and writes, either we can make some changes in the driver itself or use devmem5 user-space binary. We are going to make minor driver side changes on iMX8MM and use devmem5 on the RC. iMX8MM is the PCIe Endpoint and we are using end-point test driver to configure it as such. If  you want to do the same, please follow this blog - Enabling PCIe End-point framework on iMX95 torradex board and iMX8MM EVK - NXP Community On the contrary if you want to make iMX95 as RC and iMX8MM Endpoint, feel free to follow this blog - How to configure iMX95EVK as PCIe Endpoint and test it using PCIe Endpoint Test Framework - NXP Community Two things we are going to do next: - 1. On iMX8MM EP, we are going to write some random values  in the drivers/pci/endpoint/pci-epf-core.c, make the following changes in pci_epf_alloc_space function: -     'space' is the virtual address and 'phys_addr' is the physical address that is contiguous. Please note that it is a crude way to test this translation. There are better ways to do it. Build the kernel after the changes and boot the board with it. Make iMX8MM an Endpoint using PCI Endpoint Test Framework. 2. On iMX95 Verdin EVK [PCIe RC], we are going to read the address 0x910100000 using devmem5 to verify that we can observe the same data on the RC.   That's it for today. This was a long blog and if you feel overwhelmed by the details, please feel free to drop in the DMs or comments so that I can try to make it easier. Until next time! Gaurav Sharma  
View full article
Overview The purpose of this document is to provide guidance for FlexIO 8080 display capability. Generally, the 8080 bus interface consists of one chip-select line (CS), one writing-latch line (WR), one reading-latch line (RD), one data/command-select line (RS, also called D/C), and 8 or 16 bidirectional data lines (Data Bus). Since The FlexIO instance of i.MX 943 support only 16 pins, the demo can only support 8 bit 8080 mode(two pin should be used as WR and RD signal.   Below are pins used in the 8 bit 8080 display. Panel Setup The panel in the example is X-LCD-PAR-S035. To use 8 bit 8080 mode, need ser IM[2:0] to be 011. Connection and Software i.MX 943 Need pull down SPI8_SEL1 and SPI8_SEL3 of PCA6416 in SW to select Arduino for 8080 pins D[7:4]. Here is the patch for system manager. For quick verification, use flash_m70 when building bootloader. diff --git a/configs/mx94evk.cfg b/configs/mx94evk.cfg index 9d46976..90bf089 100755 --- a/configs/mx94evk.cfg +++ b/configs/mx94evk.cfg @@ -499,6 +499,9 @@ ENC_PLL OWNER ENDAT2_1 OWNER ENDAT2_2 OWNER ENDAT3_1 OWNER +GPIO2 OWNER +GPIO3 OWNER +FLEXIO1 OWNER FLEXIO3 OWNER FLEXIO4 OWNER FLEXPWM1 OWNER @@ -515,6 +518,7 @@ HIPERFACE_SAFE1_2 OWNER HIPERFACE_SAFE2_1 OWNER HIPERFACE_SAFE2_2 OWNER IRQSTEER_M7_0 OWNER +LPI2C6 OWNER LPIT1 OWNER LPTMR1 OWNER LPTMR2 OWNER @@ -557,6 +561,25 @@ XBAR_DSC3 OWNER PIN_GPIO_IO24 OWNER PIN_GPIO_IO25 OWNER +# 8080 +PIN_GPIO_IO00 OWNER +PIN_GPIO_IO01 OWNER +PIN_GPIO_IO02 OWNER +PIN_GPIO_IO03 OWNER +PIN_GPIO_IO08 OWNER +PIN_GPIO_IO09 OWNER +PIN_GPIO_IO10 OWNER +PIN_GPIO_IO11 OWNER +PIN_GPIO_IO12 OWNER +PIN_GPIO_IO13 OWNER +PIN_GPIO_IO14 OWNER +PIN_GPIO_IO15 OWNER +PIN_GPIO_IO38 OWNER + +# I2C6 +PIN_GPIO_IO28 OWNER   Attached imx943_flexio_8080_8bit.zip is patch for m70 demo based on SDK_25_06_00_MCIMX943-EVK.   i.MX 93 Need pull up EXP_SEL(pin4 R4) of ADP5585 in SW to route some pins. Attached imx93_flexio_8080_8bit.zip is patch for m33 demo based on SDK_25_06_00_MCIMX93-EVK. The running status is similar as i.MX943.
View full article
Our default BSP code can support below resolution:       https://github.com/nxp-imx/linux-imx/blob/cbfe1a744dc4a794e79396c7079339a54f89c8f2/drivers/phy/freescale/phy-fsl-samsung-hdmi.c If customer want to add new pixel clock about their  panel, they can ask our support to generate the new parameters about it, and then add the result to below struct: const struct phy_config samsung_phy_pll_cfg[] = {}. After add the result to the struct, you need to re-compile the kernel and boot your board, then run the "modetest -c" command Check whether the changes are effective when you run the modetest -c command, the following code show as below, You can see all the resolutions currently supported by your monitor.   How to change the panel display resolution: 1) Run the below command at the uboot period: setenv mmcargs 'setenv bootargs console=${console} root=${mmcroot} video=HDMI-A-1:1920x1080-32@30' video=HDMI-A-1:3840x2160-32@30: Set video output parameters: HDMI-A-1: Specifies the use of the HDMI interface. 3840x2160: The resolution is 3840x2160 (4K). -32: The color depth is 32 bits. @30: The refresh rate is 30Hz. saveenv boot 2) Change the westom.ini file at the /etc/xdg/weston location, Change the resolution you want in [output] part. [output] #name=HDMI-A-1 #mode=640x480@60 #transform=rotate-90 3)Reboot the board, and run the "modetest -p" command see if your change is effective
View full article
We are pleased to announce that Config Tools for i.MX v25.06 are now available. Downloads & links To download the installer for all platforms, please login to our download site via:  https://www.nxp.com/design/designs/config-tools-for-i-mx-applications-processors:CONFIG-TOOLS-IMX Please refer to  Documentation  for installation and quick start guides. For further information about DDR config and validation, please go to this  blog post. Release Notes Full details on the release (features, known issues...) • DDR – Support for i.MX 91 is added. – Synchronized with BSP Q2 release – Support for the i.MX 91 FRDM board is added. – Support for the i.MX 93 FRDM board is added. – Spectrum support for i.MX 95 and i.MX 943 is spread. – The Address mirroring option in the UI for all mscale devices with DDR3L and DDR4 is exposed. – DDR3L support for i.MX 8M and i.MX 8MM is added. – Linux support for code generation (beta) is added. • SerDes tool – i.MX 943 support (Beta) is added. • Clocks – Support for read-only element settings is added. – Filtering all settings of Initialization modules in the Details view is supported. • Peripherals – A wizard to export the Registers view data in the CSV format is supported. – Performance of the tool is improved. • An ability to export/import Expansion Boards and Expansion Headers is added.
View full article
Hello everyone, in this post we will control one (or more) WS2812 LEDs from a Linux UserSpace application, communicating with Cortex M33 through RPMSG.  Required materials: FRDM-IMX93 WS2812 LED/Strip Attached wsled.c (userspace application) Attached ws2812_m33_project (Source code of firmware for M33)   Environment: Linux Kernel 6.6 arm-gnu-toolchain-13.3.rel1-x86_64-arm-none-eabi SDK 24.12.00   This is the block diagram of the application:        CORTEX M33 SIDE.  From WS2812  LED datasheet, we can see the timing must be precise, that is the reason we will use the Cortex M33 (Real time applications):    As we can see, the timing just accept tolerance of 150ns, that is the reason is preferred to use the Cortex M33 instead of control with Linux that is in charge of other tasks.    The function that we will implement to send Zero and One is:  void WS2812B_send_bit(uint8_t bit) { if (bit) { // Send "1" RGPIO_PinWrite(WS2812B_LED_RGPIO, WS2812B_LED_RGPIO_PIN, 1); for (int i = 0; i < HIGH_ONE_CYCLES; i++) __asm__("NOP"); RGPIO_PinWrite(WS2812B_LED_RGPIO, WS2812B_LED_RGPIO_PIN, 0); for (int i = 0; i < LOW_ONE_CYCLES; i++) __asm__("NOP"); } else { // Send "0" RGPIO_PinWrite(WS2812B_LED_RGPIO, WS2812B_LED_RGPIO_PIN, 1); for (int i = 0; i < HIGH_ZERO_CYCLES; i++) __asm__("NOP"); RGPIO_PinWrite(WS2812B_LED_RGPIO, WS2812B_LED_RGPIO_PIN, 0); for (int i = 0; i < LOW_ZERO_CYCLES; i++) __asm__("NOP"); } }     Testing and measuring the toggle timing with the RGPIO driver of Cortex M33, we could find the best number of NOP instructions to adjust with the required timing according to datasheet, and the results with core running at 200MHz are:    Parameter  Number of NOP times  HIGH_ONE_CYCLES  22  (T1H: 700 ns)  LOW_ONE_CYCLES  12  (T1L: 600 ns)  LOW_ZERO_CYCLES  20  (T0L: 800 ns)  HIGH_ZERO_CYCLES  6    (T0H: 350 ns)      Zero:   One:   Taking in mind this information, we can start to develop our application. From Cortex M33, we created a little protocol, that will wait for instructions to do.    For example, the expected string to fill the RPMSG buffer is:    Index  Purpose  Example  app_buf[0]  Command ('c' or 't')  'c' = store color in buffer  't' = show colors on LEDs  app_buf[1]  Red component (0–255)  0xFF  app_buf[2]  Green component (0–255)  0x00  app_buf[3]  Blue component (0–255)  0x80  app_buf[4]  LED index (target LED position)  e.g. 0, 1, 2    Commands:    'c'  "Color store"  This command stores the RGB color value into a local buffer, targeting a specific LED (app_buf[4]).  It doesn't update the LED strip immediately, it just prepares the data.  Example of RPMSG received buffer from Cortex A (Linux):   app_buf = { 'c', 0xFF, 0x00, 0x00, 2 };  // Store red color for LED 2     't'  "Transfer"  This command sends the full color buffer to the WS2812 strip, updating the LED colors.  The RGB values in the buffer are ignored, it simply triggers an update based on previously stored data.  Example of RPMSG received buffer from Cortex A (Linux):  app_buf = { 't', 0, 0, 0, 0 };  // Transfer the buffered colors to the LED strip     You can modify the code to add your custom commands like change number of LEDs on the strip, or change the GPIO, etc. Currently, the number of WS2812 LEDs supported is defined in software by NUM_RGB_LEDS. As default is 8 LEDs.    I will attach the full code for Cortex M33 firmware, it was tested with arm-gnu-toolchain-13.3.rel1-x86_64-arm-none-eabi and SDK 2_15, SDK 2_16 and SDK 24.    In this example, the EXP_GPIO_IO24 of FRDM-IMX93 was used to control the LED Strip.   CORTEX A55 SIDE.  For Cortex A55 (Linux side), we developed an userspace application, that will create the structure for the buffer to send to the Cortex M33 and send through RPMSG using the imx_rpmsg_tty included on the NXP BSP. You can find the userspace application attached.    As we know, the imx_rpmsg_tty creates the tty channel called ttyRPMSG31 under /dev. So, this userspace application communicates directly with the device /dev/ttyRPMSG31 to send the buffer with the required structure for Cortex M33.    EXAMPLE OF USAGE.    STEP 1. Compile firmware for Cortex M33 and store in FRDM-IMX93 under /lib/firmware to use with remoteproc:   STEP 2.  Compile or cross-compile the userspace application (attached.)  To compile on the platform:  root@imx93evk:~# gcc wsled.c -o wsled root@imx93evk:~# ls wsled wsled.c Also, we can copy the wsled under /bin to practicity. root@imx93evk:~# wsled Error: -c <red> <green> <blue> is required. WS2812 Usage: wsled -c <red> <green> <blue> [-n <led_position>] Load the color of exact LED to the buffer wsled -t Shows the colors to the LEDs   STEP 3. To run the entire example: boot the board and load the firmware for cortex M33 with remoteproc: root@imx93evk:~# cd /sys/class/remoteproc/remoteproc0 root@imx93evk:/sys/class/remoteproc/remoteproc0# echo ws2812_m33.elf > firmware root@imx93evk:/sys/class/remoteproc/remoteproc0# echo start > state  Then, we will receive this from Cortex M33 terminal: RPMSG String Communication Channel FreeRTOS RTOS M33 clock is at: 200000000 Hz Nameservice sent, ready for incoming messages from Cortex-A55! WSLED   Load the imx_rpmsg_tty module in Linux to initialize RPMSG: root@imx93evk:~# modprobe imx_rpmsg_tty   Then, we will have the hello world message from Cortex A (Linux side), but with our buffer format in Cortex M33 console: CMD: h [1]:0x65 [2]:0x6c [3]:0x6c [4]: 111 LEN = 12   Finally, we are ready change colors of the LEDs: Load the buffer (LED 1 = RED, LED 2 = Green, LED 3 = Blue). root@imx93evk:~# wsled -c 0x55 0x00 0x00 -n 1 root@imx93evk:~# wsled -c 0x00 0x55 0x00 -n 2 root@imx93evk:~# wsled -c 0x00 0x00 0x55 -n 3   Show colors on LEDs. root@imx93evk:~# wsled -t    
View full article