i.MX Solutions Knowledge Base

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

i.MX Solutions Knowledge Base

Labels

Discussions

Sort by:
Some customer need to run standalone application in i.MX side. This article describe how to run standalone application in uboot and kernel, how to improve application running performance. It takes i.MX8MP as example, which is also suitable for other i.MX platform.
View full article
   Yocto Project Configuration The most modern and NXP-recommended method for developing with the LS1028A is the Layerscape Linux Distribution POC (LLDP) based on Yocto. Unlike the LSDK (which uses Flexbuild), LLDP uses Yocto/Bitbake and is the long-term supported path. 1 Host Requirements Requirement Details Operating System Ubuntu 20.04 LTS (Focal) — official recommendation RAM Minimum 8 GB (16 GB+ recommended) Disk Space Minimum 100 GB free CPU Minimum 4 cores (more cores = faster builds) Tools git, repo, python3, wget, curl, build-essential Install dependencies on Ubuntu: sudo apt-get update && sudo apt-get install -y  gawk wget git diffstat unzip texinfo gcc-multilib \   build-essential chrpath socat cpio python3 python3-pip  python3-pexpect xz-utils debianutils iputils-ping \   python3-git python3-jinja2 libegl1-mesa libsdl1.2-dev  pylint xterm rsync curl locales zstd liblz4-tool \   repo ca-certificates   # Configure git (required by repo) git config --global user.name "Your Name" git config --global user.email "[email protected]"   2 Download the LLDP Repository (Yocto for LS1028A) # Create working directory mkdir ~/lldp-ls1028a && cd ~/lldp-ls1028a   # Initialize repo with the LLDP manifest (Kirkstone, kernel 5.15) repo init -u https://github.com/nxp-qoriq/yocto-sdk.git \           -b kirkstone \           -m ls-5.15.71-2.2.0_distro.xml   # Sync all repositories (may take 30-60 minutes) repo sync Note: For the latest version (LLDP L6.1.1, kernel 6.1), check the updated manifest at: https://github.com/nxp-qoriq/yocto-sdk   3 Set Up the Build Environment for LS1028A # Initialize Yocto environment for the LS1028A # (run from the lldp-ls1028a/ directory) DISTRO=fsl-qoriq-distro MACHINE=ls1028ardb source distro-setup-env # This automatically creates and enters the build directory # You are now in: ~/lldp-ls1028a/build_ls1028ardb/   4 local.conf File — GPU Configuration The conf/local.conf file inside the build directory controls compilation options. For the LS1028A with GPU, verify or add: # Edit the configuration file nano conf/local.conf Key parameters for GPU and desktop: # Target machine MACHINE = "ls1028ardb"   # Distribution with GPU and Wayland support DISTRO = "fsl-qoriq-distro"   # Enable display and GPU features DISTRO_FEATURES:append = " wayland opengl"   # GPU driver: use Etnaviv (open-source) for LS1028A # DO NOT use imx-gpu-viv (i.MX only, requires ARCH_MXC) PREFERRED_PROVIDER_virtual/libgl = "mesa" PREFERRED_PROVIDER_virtual/libgles1 = "mesa" PREFERRED_PROVIDER_virtual/libgles2 = "mesa" PREFERRED_PROVIDER_virtual/egl = "mesa"   # Enable OpenCL support via Vivante GPU IMAGE_INSTALL:append = " clinfo"   # Accept NXP proprietary licenses (required for GPU firmware) LICENSE_FLAGS_ACCEPTED = "nxp-proprietary"   # Parallel build threads (adjust to your host PC) BB_NUMBER_THREADS = "8" PARALLEL_MAKE = "-j8"   # (Optional) Use ccache to speed up recompilations INHERIT += "ccache"   5 Required Yocto Layers (bblayers.conf) Verify that conf/bblayers.conf includes these layers: cat conf/bblayers.conf It must contain at least: BBLAYERS ?= " \   ${BSPDIR}/sources/poky/meta \   ${BSPDIR}/sources/poky/meta-poky \   ${BSPDIR}/sources/meta-openembedded/meta-oe \   ${BSPDIR}/sources/meta-openembedded/meta-multimedia \   ${BSPDIR}/sources/meta-openembedded/meta-python \   ${BSPDIR}/sources/meta-openembedded/meta-networking \   ${BSPDIR}/sources/meta-freescale \   ${BSPDIR}/sources/meta-qoriq \   ${BSPDIR}/sources/meta-nxp-desktop \ " The meta-nxp-desktop layer is what provides GPU support for the LS1028A with the ls-image-desktop image.   6 Build the Image with GPU Support # Recommended: Desktop image with full GPU support (LS1028A only) # Includes: GNOME desktop, Weston/Wayland, Vivante GPU drivers, OpenCL bitbake ls-image-desktop   # Alternative: download all packages first before building # (useful for catching network errors before the long build) bitbake ls-image-desktop --runall fetch bitbake ls-image-desktop   # Minimal: main image without desktop (no GPU by default) bitbake ls-image-main   # Lite: minimal image bitbake ls-image-lite Estimated build time: Between 4 and 8 hours on the first build (depending on host hardware). Incremental builds are much faster.   7 Install the Image to the SD Card After compilation, output files are located in: tmp/deploy/images/ls1028ardb/ # Identify the SD card (verify with lsblk) lsblk   # Install image using flex-installer (included in the SDK) flex-installer \   -b tmp/deploy/images/ls1028ardb/boot_ls1028ardb.tgz \   -f tmp/deploy/images/ls1028ardb/firmware_ls1028ardb_sdboot.img \   -r tmp/deploy/images/ls1028ardb/ls-image-desktop-ls1028ardb.tar.zst \   -d /dev/sdX    # replace with your SD device   Practical Example: OpenCL Application on LS1028A This example shows how to compile and run a program that uses the GC7000UL GPU to add two vectors with OpenCL.   8.1 Source Code: vector_add.cl (OpenCL Kernel) Create the kernel file on the LS1028A board: # On the LS1028A (via serial or SSH) cat > /home/root/vector_add.cl << 'EOF' __kernel void vector_add(     __global const float* a,     __global const float* b,     __global float* c,     const int n) {     int gid = get_global_id(0);     if (gid < n) {         c[gid] = a[gid] + b[gid];     } }   8.2 Source Code: vector_add.c (OpenCL Host) cat > /home/root/vector_add.c << 'EOF' #include <stdio.h> #include <stdlib.h> #include <string.h> #include <CL/cl.h>   #define VECTOR_SIZE 1024   int main() {     cl_platform_id   platform;     cl_device_id     device;     cl_context       context;     cl_command_queue queue;     cl_program       program;     cl_kernel        kernel;     cl_mem           buf_a, buf_b, buf_c;     cl_int           err;       // 1. Get Vivante GPU platform and device     err = clGetPlatformIDs(1, &platform, NULL);     err = clGetDeviceIDs(platform, CL_DEVICE_TYPE_GPU, 1, &device, NULL);       // Print device name     char device_name[128];     clGetDeviceInfo(device, CL_DEVICE_NAME, sizeof(device_name), device_name, NULL);     printf("GPU detected: %s\n", device_name);       // 2. Create context and command queue     context = clCreateContext(NULL, 1, &device, NULL, NULL, &err);     queue   = clCreateCommandQueue(context, device, 0, &err);       // 3. Read kernel source from file     FILE* f = fopen("vector_add.cl", "r");     fseek(f, 0, SEEK_END);     size_t src_size = ftell(f);     rewind(f);     char* src=(char*)malloc(src_size + 1);     fread(src, 1, src_size, f);     src[src_size] = '\0';     fclose(f);       // 4. Compile OpenCL program     program = clCreateProgramWithSource(context, 1, (const char**)&src, &src_size, &err);     err = clBuildProgram(program, 1, &device, NULL, NULL, NULL);     if (err != CL_SUCCESS) {         char log[2048];         clGetProgramBuildInfo(program, device, CL_PROGRAM_BUILD_LOG,                               sizeof(log), log, NULL);         printf("Compilation error:\n%s\n", log);         return 1;     }     kernel = clCreateKernel(program, "vector_add", &err);       // 5. Prepare input data     float* h_a = (float*)malloc(VECTOR_SIZE * sizeof(float));     float* h_b = (float*)malloc(VECTOR_SIZE * sizeof(float));     float* h_c = (float*)malloc(VECTOR_SIZE * sizeof(float));     for (int i = 0; i < VECTOR_SIZE; i++) {         h_a[i] = (float)i;         h_b[i] = (float)(VECTOR_SIZE - i);     }       // 6. Create GPU buffers     buf_a = clCreateBuffer(context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR,                            VECTOR_SIZE * sizeof(float), h_a, &err);     buf_b = clCreateBuffer(context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR,                            VECTOR_SIZE * sizeof(float), h_b, &err);     buf_c = clCreateBuffer(context, CL_MEM_WRITE_ONLY,                            VECTOR_SIZE * sizeof(float), NULL, &err);       // 7. Set kernel arguments and execute on GPU     int n = VECTOR_SIZE;     clSetKernelArg(kernel, 0, sizeof(cl_mem), &buf_a);     clSetKernelArg(kernel, 1, sizeof(cl_mem), &buf_b);     clSetKernelArg(kernel, 2, sizeof(cl_mem), &buf_c);     clSetKernelArg(kernel, 3, sizeof(int), &n);       size_t global_size = VECTOR_SIZE;     err = clEnqueueNDRangeKernel(queue, kernel, 1, NULL,                                   &global_size, NULL, 0, NULL, NULL);     clFinish(queue);       // 8. Read result     clEnqueueReadBuffer(queue, buf_c, CL_TRUE, 0,                         VECTOR_SIZE * sizeof(float), h_c, 0, NULL, NULL);       // 9. Verify result (each element should equal VECTOR_SIZE = 1024)     int ok = 1;     for (int i = 0; i < VECTOR_SIZE; i++) {         if (h_c[i] != (float)VECTOR_SIZE) { ok = 0; break; }     }     printf("Result: %s\n", ok ? "CORRECT - GPU works!" : "CALCULATION ERROR");     printf("Example: a[0]=%.0f + b[0]=%.0f = c[0]=%.0f\n",            h_a[0], h_b[0], h_c[0]);       // Free resources     clReleaseMemObject(buf_a); clReleaseMemObject(buf_b); clReleaseMemObject(buf_c);     clReleaseKernel(kernel); clReleaseProgram(program);     clReleaseCommandQueue(queue); clReleaseContext(context);     free(h_a); free(h_b); free(h_c); free(src);     return 0; }   8.3 Compile and Run on the LS1028A On the LS1028A board (connected via serial or SSH): # Install build tools and OpenCL headers apt-get install -y gcc clinfo ocl-icd-libopencl1 opencl-headers   # Compile gcc -o vector_add vector_add.c -lOpenCL -I/usr/include   # Run ./vector_add Expected output: GPU detected: Vivante OpenCL Device GC7000UL.6202.0000 Result: CORRECT - GPU works! Example: a[0]=0 + b[0]=1024 = c[0]=1024   12.4 Yocto Recipe to Include the Example in the Image To include the example directly in the Yocto image, create a recipe in your custom layer: mkdir -p ~/lldp-ls1028a/sources/meta-my-layer/recipes-examples/opencl-vector/files cp vector_add.c vector_add.cl \    ~/lldp-ls1028a/sources/meta-my-layer/recipes-examples/opencl-vector/files/ Recipe file opencl-vector_1.0.bb: SUMMARY = "OpenCL vector addition example for LS1028A GPU" LICENSE = "MIT" LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"   SRC_URI = "file://vector_add.c \            file://vector_add.cl"   DEPENDS = "virtual/opencl-icd opencl-headers"   S = "${WORKDIR}"   do_compile() {     ${CC} ${CFLAGS} -o vector_add vector_add.c -lOpenCL ${LDFLAGS} }   do_install() {     install -d ${D}${bindir}     install -m 0755 vector_add ${D}${bindir}/     install -d ${D}/home/root     install -m 0644 vector_add.cl ${D}/home/root/ }   FILES:${PN} += "/home/root/vector_add.cl" Add to local.conf and rebuild: IMAGE_INSTALL:append = " opencl-vector" bitbake ls-image-desktop   Practical Example: OpenGL ES Rendering with Wayland/Weston This example shows how to render an animated triangle using OpenGL ES 2.0 with EGL on the Weston (Wayland) compositor — the standard "Hello World" of embedded graphics on the GC7000UL GPU. 9.1 Graphics Stack Diagram C Application      ↓ OpenGL ES 2.0  (libGLESv2.so — Vivante GC7000UL)      ↓ EGL 1.4        (libEGL.so — interface between GLES and Wayland)      ↓ Wayland Client (libwayland-client, libwayland-egl)      ↓ Weston Compositor (DRM/KMS + Mali-DP500)      ↓ DisplayPort → 4K Monitor   9.2 Install Dependencies On the LS1028A (with ls-image-desktop): apt-get install -y libgles2-mesa-dev libegl1-mesa-dev libwayland-dev libwayland-egl-backend-dev gcc pkg-config   9.3 Source Code: triangle_gles.c cat > /home/root/triangle_gles.c << 'EOF' /**  * OpenGL ES 2.0 + EGL + Wayland example  * Renders a colored spinning triangle on the Vivante GC7000UL GPU of the LS1028A  * Compile: gcc -o triangle_gles triangle_gles.c -lwayland-client -lwayland-egl -lEGL -lGLESv2 -lm  */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <math.h> #include <wayland-client.h> #include <wayland-egl.h> #include <EGL/egl.h> #include <GLES2/gl2.h>   #define WIDTH  800 #define HEIGHT 600   static struct wl_display       *wl_display    = NULL; static struct wl_compositor    *wl_compositor = NULL; static struct wl_shell         *wl_shell      = NULL; static struct wl_surface       *wl_surface    = NULL; static struct wl_shell_surface *shell_surface = NULL; static struct wl_egl_window    *egl_window    = NULL;   static EGLDisplay egl_display; static EGLContext egl_context; static EGLSurface egl_surface;   static const char *vertex_shader_src=     "attribute vec2 a_position;          \n"     "attribute vec3 a_color;             \n"     "varying vec3 v_color;               \n"     "uniform float u_angle;              \n"     "void main() {                       \n"     "  float c = cos(u_angle);           \n"     "  float s = sin(u_angle);           \n"     "  vec2 rot = vec2(                  \n"     "    a_position.x*c - a_position.y*s,\n"     "    a_position.x*s + a_position.y*c \n"     "  );                                \n"     "  gl_Position = vec4(rot, 0.0, 1.0);\n"     "  v_color = a_color;                \n"     "}                                   \n";   static const char *fragment_shader_src=     "precision mediump float;            \n"     "varying vec3 v_color;               \n"     "void main() {                       \n"     "  gl_FragColor = vec4(v_color, 1.0);\n"     "}                                   \n";   /* Vertices: position (x,y) + color (r,g,b) */ static const float vertices[] = {      0.0f,  0.8f,  1.0f, 0.0f, 0.0f,   /* Top    - Red   */     -0.7f, -0.5f,  0.0f, 1.0f, 0.0f,   /* Left   - Green */      0.7f, -0.5f,  0.0f, 0.0f, 1.0f,   /* Right  - Blue  */ };   static void registry_global(void *data, struct wl_registry *reg,                              uint32_t name, const char *iface, uint32_t ver) {     if (strcmp(iface, "wl_compositor") == 0)         wl_compositor = wl_registry_bind(reg, name, &wl_compositor_interface, 1);     else if (strcmp(iface, "wl_shell") == 0)         wl_shell = wl_registry_bind(reg, name, &wl_shell_interface, 1); } static void registry_global_remove(void *d, struct wl_registry *r, uint32_t n) {} static const struct wl_registry_listener registry_listener = {     registry_global, registry_global_remove };   static GLuint compile_shader(GLenum type, const char *src) {     GLuint shader = glCreateShader(type);     glShaderSource(shader, 1, &src, NULL);     glCompileShader(shader);     GLint ok; glGetShaderiv(shader, GL_COMPILE_STATUS, &ok);     if (!ok) {         char log[512]; glGetShaderInfoLog(shader, 512, NULL, log);         printf("Shader error: %s\n", log); exit(1);     }     return shader; }   int main() {     wl_display = wl_display_connect(NULL);     if (!wl_display) { printf("Error: could not connect to Wayland\n"); return 1; }       struct wl_registry *registry = wl_display_get_registry(wl_display);     wl_registry_add_listener(registry, &registry_listener, NULL);     wl_display_dispatch(wl_display);     wl_display_roundtrip(wl_display);       wl_surface = wl_compositor_create_surface(wl_compositor);     shell_surface = wl_shell_get_shell_surface(wl_shell, wl_surface);     wl_shell_surface_set_toplevel(shell_surface);       egl_display = eglGetDisplay((EGLNativeDisplayType)wl_display);     eglInitialize(egl_display, NULL, NULL);     eglBindAPI(EGL_OPENGL_ES_API);       EGLint config_attribs[] = {         EGL_SURFACE_TYPE,    EGL_WINDOW_BIT,         EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,         EGL_RED_SIZE,   8, EGL_GREEN_SIZE, 8,         EGL_BLUE_SIZE,  8, EGL_ALPHA_SIZE, 0,         EGL_DEPTH_SIZE, 16, EGL_NONE     };     EGLConfig egl_config; EGLint num_configs;     eglChooseConfig(egl_display, config_attribs, &egl_config, 1, &num_configs);       EGLint ctx_attribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };     egl_context = eglCreateContext(egl_display, egl_config, EGL_NO_CONTEXT, ctx_attribs);     egl_window  = wl_egl_window_create(wl_surface, WIDTH, HEIGHT);     egl_surface = eglCreateWindowSurface(egl_display, egl_config,                                           (EGLNativeWindowType)egl_window, NULL);     eglMakeCurrent(egl_display, egl_surface, egl_surface, egl_context);       printf("GPU: %s\n", glGetString(GL_RENDERER));     printf("OpenGL ES Version: %s\n", glGetString(GL_VERSION));       GLuint vs = compile_shader(GL_VERTEX_SHADER,   vertex_shader_src);     GLuint fs = compile_shader(GL_FRAGMENT_SHADER, fragment_shader_src);     GLuint program = glCreateProgram();     glAttachShader(program, vs); glAttachShader(program, fs);     glLinkProgram(program); glUseProgram(program);       GLint pos_loc   = glGetAttribLocation(program,  "a_position");     GLint color_loc = glGetAttribLocation(program,  "a_color");     GLint angle_loc = glGetUniformLocation(program, "u_angle");       glViewport(0, 0, WIDTH, HEIGHT);       float angle = 0.0f;     int frames = 0;     printf("Rendering spinning triangle (Ctrl+C to exit)...\n");       while (1) {         wl_display_dispatch_pending(wl_display);         glClearColor(0.1f, 0.1f, 0.15f, 1.0f);         glClear(GL_COLOR_BUFFER_BIT);         glUniform1f(angle_loc, angle);         glEnableVertexAttribArray(pos_loc);         glVertexAttribPointer(pos_loc,   2, GL_FLOAT, GL_FALSE, 5*sizeof(float), vertices);         glEnableVertexAttribArray(color_loc);         glVertexAttribPointer(color_loc, 3, GL_FLOAT, GL_FALSE, 5*sizeof(float), vertices + 2);         glDrawArrays(GL_TRIANGLES, 0, 3);         eglSwapBuffers(egl_display, egl_surface);         angle += 0.02f;         if (angle > 6.2832f) angle -= 6.2832f;         frames++;         if (frames % 300 == 0)             printf("Frame %d — angle: %.2f rad\n", frames, angle);     }       eglDestroyContext(egl_display, egl_context);     eglDestroySurface(egl_display, egl_surface);     eglTerminate(egl_display);     wl_display_disconnect(wl_display);     return 0; }   9.4 Compile and Run # Compile gcc -o triangle_gles triangle_gles.c \     -lwayland-client -lwayland-egl \     -lEGL -lGLESv2 -lm   # Make sure Weston is running and set Wayland environment export XDG_RUNTIME_DIR=/run/user/0 export WAYLAND_DISPLAY=wayland-0   # Run ./triangle_gles Expected terminal output: GPU: Vivante GC7000UL OpenGL ES Version: OpenGL ES 3.1 V6.4.3.p4.398061 Rendering spinning triangle (Ctrl+C to exit)... Frame 300 — angle: 6.00 rad Frame 600 — angle: 5.68 rad A RGB triangle spinning on a dark background will appear on screen, rendered by the GC7000UL GPU. Bio_TICFSL_0-1789407894776.png       9.5 Yocto Recipe SUMMARY = "OpenGL ES 2.0 spinning triangle example — LS1028A" LICENSE = "MIT" LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"   SRC_URI = "file://triangle_gles.c"   DEPENDS = "virtual/libgles2 virtual/egl wayland"   S = "${WORKDIR}"   do_compile() {     ${CC} ${CFLAGS} -o triangle_gles triangle_gles.c \         -lwayland-client -lwayland-egl -lEGL -lGLESv2 -lm ${LDFLAGS} }   do_install() {     install -d ${D}${bindir}     install -m 0755 triangle_gles ${D}${bindir}/ }   9.6 Yocto Recipe for OpenCV with GPU Add to local.conf: IMAGE_INSTALL:append = " opencv python3-opencv" PACKAGECONFIG:append:pn-opencv = " opencl" bitbake ls-image-desktop   Regards  
View full article
This post walks through end-to-end steps to enable and verify TX PAUSE frame (IEEE 802.3x flow control) generation on the i.MX95 / i.MX9x series using DPDK 25.11 with the enetc4 VF driver and a Spirent traffic generator. I also share an optional debug patch that lowers the PAUSE trigger threshold for quick lab reproduction and adds register readback prints to dmesg. --- Overview -------- On i.MX95 the ENETC4 Ethernet controller uses a PF/VF split: - The kernel PF driver (fsl_enetc4, Linux 6.18+) owns the MAC, PHY negotiation, and PAUSE configuration. - The DPDK VF driver (net/enetc, DPDK 25.11) owns the receive rings in the DPDK application. When the link partner negotiates PAUSE, the kernel PF configures the MAC and notifies the DPDK VF via a mailbox message. The VF then enables congestion signaling on its Rx rings. When incoming traffic fills those rings past the configured threshold, the hardware automatically emits PAUSE frames toward the sender. The trigger chain looks like this: High-rate ingress traffic fills VF Rx rings --> ICM fill level crosses PPAUONTR threshold --> MAC emits IEEE 802.3x PAUSE frame to link partner --> link partner pauses its transmitter --- Hardware Setup -------------- - i.MX95 EVK (or any i.MX9x board with ENETC4) - 10G SFP+ DAC cable or fiber between i.MX95 ENETC4 port and Spirent TestCenter port - Spirent TestCenter (or equivalent traffic generator with flow control capture) Software versions used in this guide: - Kernel: Linux 6.18+ with fsl_enetc4 PF driver - DPDK: 25.11 (net/enetc VF PMD) - ethtool: 6.x --- Step 1 — Enable PAUSE on the Kernel PF Interface ------------------------------------------------- The kernel PF interface (typically eth1 for ENETC4 port 1) must have TX PAUSE enabled before the link comes up so that phylink can negotiate it with the link partner. # Identify the kernel PF interface ip link show | grep -E "eth[0-9]" # Enable TX and RX PAUSE (autoneg lets the link partner also advertise PAUSE, it is off since we are using spirent) ethtool -A eth1 tx on rx on autoneg off # Bring the link up ip link set eth1 up # After link is up, verify PAUSE was negotiated ethtool -a eth1 Expected output: Pause parameters for eth1: Autonegotiate: off RX: on TX: on If TX shows "off" after link up, the link partner may not have advertised PAUSE capability. Try forcing it: ethtool -A eth1 tx on rx on autoneg off --- Step 2 — Verify ethtool Statistics Are Available ------------------------------------------------- Confirm that the ethtool stats interface is working before starting traffic: ethtool -S eth1 | grep -E "txpf|rxpf|pause" You should see counters like txpf_frames and rxpf_frames (both 0 at this point). If you see "no stats available", verify your kernel build includes the ethtool ops for enetc4. --- Step 3 — Bind the DPDK VF to igb_uio ----------------------------------- note bootargs: must have iommu_passthrough=1 # Load the VFIO driver modprobe igb_uio echo 1 > /sys/bus/pci/devices/0002\:00\:10.0/sriov_numvfs echo igb_uio > /sys/bus/pci/devices/0002\:00\:12.0/driver_override echo 0002:00:12.0 > /sys/bus/pci/drivers/fsl_enetc_vf/unbind echo 0002:00:12.0 > /sys/bus/pci/drivers/igb_uio/bind ip link set eth1 vf 0 trust on --- Step 4 — Allocate Hugepages ----------------------------- # 4 x 1 GB hugepages (recommended for 10G line-rate testing) echo 4 > /sys/kernel/mm/hugepages/hugepages-1048576kB/nr_hugepages mount -t hugetlbfs none /dev/hugepages # Verify allocation grep HugePages /proc/meminfo # HugePages_Total: 4 # HugePages_Free: 4 --- Step 5 — Start testpmd ------------------------ For PAUSE testing the goal is to build up backpressure in the VF Rx rings so the ICM congestion threshold is crossed. Use rxonly mode with a small Rx descriptor count so the ring fills up quickly under load. testpmd \ -l 0-3 -n 4 \ -a 0002:00:12.0 \ -- \ --rxd=256 \ --txd=512 \ --nb-cores=2 \ --rxq=1 --txq=1 \ --forward-mode=rxonly \ --stats-period=5 Inside the testpmd prompt: testpmd> set fwd rxonly testpmd> start testpmd is now receiving and the DPDK VF Rx rings will fill under high-rate ingress traffic, generating the congestion signal that drives PAUSE frame emission. --- check stats via: ethtool --include-statistics -a eth1   Step 6 — Configure Spirent TestCenter --------------------------------------- Spirent port sending TO i.MX95 (ingress traffic): - Frame size: 64 bytes or smaller (smaller frames fill rings faster) - Rate: 100% line rate (10 Gbps) - Frame type: Ethernet II / IPv4 - Destination MAC: MAC address of the i.MX95 ENETC4 VF interface - Destination IP: IP address assigned to the i.MX95 interface Spirent port receiving FROM i.MX95 (PAUSE capture): - Port Properties → Flow Control → Enable IEEE 802.3x PAUSE - Enable Capture → Filter EtherType: 0x8808 - Results → Port Results → watch "Flow Control Frames Received" This counter increments every time a PAUSE frame arrives from i.MX95. - Optional: Results → Flow Analysis → check "Pause Duration (quanta)" Expected value: ~32767 (0x7FFF) Alternative capture without Spirent license: # On any PC with a tap on the wire tcpdump -i eth0 'ether proto 0x8808' -v # PAUSE frame: dst 01:80:c2:00:00:01, EtherType 0x8808, opcode 0x0001 --- Step 7 — Verify PAUSE Frames Are Being Sent --------------------------------------------- Start Spirent at 100% line rate, then on the i.MX95 host run: watch -n 1 'ethtool -S eth1 | grep -E "txpf|rxpf"' Expected output when PAUSE is active: txpf_frames: <increasing> <-- TX PAUSE frames sent by i.MX95 On Spirent, "Flow Control Frames Received" should be incrementing at the same time. --- Optional — Debug Patch for Faster Lab Reproduction ---------------------------------------------------- I am attaching a patch file to this post. This useful for bring-up and debug — this is not required for production use.   Adds dev_info() prints to enetc4_set_tx_pause() and enetc_set_congestion_mode() in the kernel driver. After link-up you will see in dmesg: fsl_enetc4 0000:00:00.0: enetc4_set_tx_pause: tx_pause=1 fsl_enetc4 0000:00:00.0: PPAUONTR = 0x00001000 fsl_enetc4 0000:00:00.0: PPAUOFFTR = 0x00000400 fsl_enetc4 0000:00:00.0: PM_CMD_CFG(0) = 0x000000c3 TX_EN=1 RX_EN=1 TXP=0 fsl_enetc4 0000:00:00.0: set_congestion_mode: enable=1 num_rx_rings=1 fsl_enetc4 0000:00:00.0: ring[0] readback rbmr=0x00000010 This confirms the kernel PF configured the MAC and set the RBMR congestion mode bit on the PF rings. The DPDK VF should receive the same setting via mailbox. also Lowers the PAUSE trigger threshold to PPAUONTR=4096 bytes so that PAUSE frames are generated at much lower traffic rates — useful for quick lab tests without needing a full 10G line-rate traffic generator. Also adds ICM register definitions (PRXBCR, PRXBCHWMR) so you can observe the ICM fill level via ethtool -S. After applying this patch, check ICM fill level during traffic: ethtool -S eth1 | grep -E "prxbcr|prxbchwmr" # prxbcr_bytes: <live fill level> # prxbchwmr_bytes: <peak fill since boot> When prxbchwmr_bytes >= 4096, the threshold has been crossed and PAUSE should fire.   --- Key Register Reference (ENETC4) --------------------------------- Note: ENETC4 register offsets start at 0x5000 for MAC/PM registers. This is different from ENETC v1 which uses 0x8000. Use ethtool -S for PM counters since PF BAR0 is IOMMU-protected on i.MX95. Register Offset Description PM_CMD_CFG(0) 0x5008 MAC config register (TXP = BIT 15) PM_TXPF(0) 0x5218 TX PAUSE frames sent (64-bit) PM_RXPF(0) 0x5118 RX PAUSE frames received (64-bit) PPAUONTR 0x108 ICM fill level threshold to START PAUSE PPAUOFFTR 0x10C ICM fill level threshold to STOP PAUSE PRXBCR 0x128 Current ICM RX fill level (live, read-only) PRXBCHWMR 0x12C ICM RX peak fill since boot (read-only) For VF Rx ring registers, VF BAR0 is accessible via devmem2: # Check RBMR of VF ring 0 — BIT 4 = CM (congestion mode) # Replace VF_BAR0 with your actual address (find via /sys/bus/pci/devices/.../resource0) devmem2 <VF_BAR0 + 0x8100> w # Expected when PAUSE is active: 0x00000010 --- Environment ----------- SoC: i.MX95, i.MX943 (i.MX9x series with ENETC4) Kernel: Linux 6.18+ (fsl_enetc4 PF driver) DPDK: 25.11 (net/enetc VF PMD) Tool: testpmd, ethtool 6.x, Spirent TestCenter Hope this helps. Happy to answer questions on the setup.
View full article
Android HW-assisted Address Sanitizer for Memory Overflow checking       Hardware-assisted AddressSanitizer (HWASan) is a memory error detection tool.     HWASan is based on the memory tagging approach, where a small random tag value is associated both with pointers and with ranges of memory addresses. For a memory access to be valid, the pointer and memory tags have to match.     HWASan uses a lot less RAM compared to ASan, which makes it suitable for whole system sanitization.   Here show an example: Use HWAsan for WiFi-HAL Memory Overflow issue hunting in Android-13.0.0_2.3.0_auto BSP.     Test environment:         SW:   Android-13.0.0_2.3.0_auto_car2, pre-built image.         HW:  88W9098 WiFi/BT EVK (PCIe) + i.MX8QXP EVK.       Run 88W9098 WiFi/BT on i.MX8QXP EVK, after ~2 hours, got memory leakage.       To locate root cause, enabled HWASan, re-build Android-13.0.0_2.3.0_auto BSP, run again, Got HWAddressSanitizer report: “heap-buffer-overflow”.          --Reason>  "Empty or null ScanResult list"  ->           --Then>      "Attempt to retrieve OsuProviders with invalid scanResult List" ->          --Result>    "heap-buffer-overflow"         HWASan help to locate root cause of Memory Overflow issue, on WiFi AP Scan code.         Attach file:            "Android_HW-assisted-Address-Sanitizer_for_memory-overflow_checking.pdf"
View full article
Steps to add support for WPA3 R3 in supplicant and hostapd
View full article
Dynamic voltage and frequency scaling (DVFS) is a power management technique that allows dynamically reducing power consumption of a CPU by dynamically scaling down supply voltage and CPU frequency. Because the internal DCDC of the i.MX RT1170 cannot cover the needed maximum current requirement at the junction temperature of 125 °C, the DVFS technique can be used to reduce current drain for compatibility with the internal DCDC. Lowering the processor frequency dynamically can help reduce the chip input current demand and ensure that the chip can continue to work at the junction temperature of 125 °C. The demo is attached. Only IAR and armgcc versions are enabled. The corresponding Application Note can be downloaded in the below link. https://www.nxp.com/docs/en/application-note/AN13267.pdf
View full article
Hello guys, this is digi international i.MX53 connect core dev board , i took three years weekends and spent lot of money on it, it's based on Qt and GStreamer , top of the line, have fun with the i.mx monsters, cheers daniele
View full article
This video is an overview of the Altia user interface development software chain. We start with graphics in Adobe Photoshopand end running Altia-generated source code on the Freescale i.MX 6. Altia also supports Vybrid, MPC5645S (Rainbow), MPC5606S (Spectrum), i.MX53 and more.
View full article
This video shows NovTech implementation of the video in (CSI Port) and video out (HDMI Port) of the i.MX6 with real time image processing.  While playback of 1080p movie (stored in an SD Card) the IPU unit of the i.MX6 takes the real time images arrives on the CSI input, and combine both video stream to one using the 'green screen' concept.
View full article
Adeneo Embedded is among the only SI to provide a Windows Embedded Compact 2013 solution on i.MX6 and to have developed a fast boot implementation of WEC2013 on the i.MX6 SDP. Fast boot is a common request from customers but a complicated one to implement. Adeneo has implemented fast boot features on several operating systems on the i.MX6. Contact: [email protected]
View full article
Hi guys, here you can see Adeneo Embedded's demo Andrea's Tablet working on Android OS on Freescale's i.MX6 Sabre SDP platform The video features an Adeneo Embedded launcher with Open GL, a video player application, picture viewer application and an audio player application. Want more info ? Meet us on our website: www.adeneo-embedded.com
View full article
This full featured BSP comes with all the core improvements that were made on the SABRE Lite BSP along with support for most of the features available for the SABRE board platform. Please contact Adeneo Embedded for access to the BSP as binary OS images or evaluation source code version at [email protected]
View full article
Adeneo Embedded adds CSI camera support to their i.MX6 Windows Embedded Compact 7 (WEC7) BSP. Camera interface on the i.MX6 is one of highly requested features among customers and in order to cater to this demand Adeneo Embedded developed a camera driver for CSI interface on WEC7.
View full article
Hey guys! Here's Adeneo Embedded's Cube OpenGL demo of the WEC7 Congatec board!   Enjoy !
View full article
Boundary Devices has a variety of i.MX6 solutions. The SABRE Lite and Nitrogen6X boards are great tools for hardware and software evaluation. The Nitrogen6X_SOM is a low cost, highly integrated System-on-Module that is ideal for customers looking for rapid product development while maintaining the flexibility of a custom design. The Nitrogen6X_SOM is shown here running the QNX operating system with QT and Storyboard Suite from Crank Software on a 7" 800x480 display.
View full article
As part of a close collaboration with Freescale, Adeneo Embedded is releasing Freescale i.MX6 BSPs for Windows Embedded Compact 7 on a set of hardware devices :   i.MX6 Nitrogen6X i.MX6 SabreLite i.MX6 Sabre SDB i.MX6 Sabre SDP Share, subscribe and don't forget to comment !
View full article
This video is showing BCM PPC10W-6MXQ ARM Panel PC equipped with i.MX6 Cortex A9 Quad Core ARM motherboard supporting secondary display via HDMI output
View full article
The Opal Development Kit include 4 protected digital inputs and outputs. This video demonstrates these, including a simple Windows Embedded Compact 7 demo application. The source for this is available in the downloads section at devicesolutions.net/opaldevkit. Get more information about the Opal CPU module and development kit at devicesolutions.net/opal.
View full article
This is a reference design showcasing a secondary vehicle dashboard with on-board diagnostics information along with all entertainment and features: Wifi, Bluetooth, GPS, GSM, microSD, USB 2.0 Host, Ethernet, SATA 3.0 and HDMI 1080p Contact [email protected] for more information
View full article