Skip to content

Add IPC4 support for NXP i.MX platforms - #11435

Open
dbaluta wants to merge 18 commits into
thesofproject:mainfrom
dbaluta:imx_ipc4_support
Open

dbaluta wants to merge 18 commits into
thesofproject:mainfrom
dbaluta:imx_ipc4_support

Conversation

@dbaluta

@dbaluta dbaluta commented Nov 10, 2026 •

Copy link
Copy Markdown
Collaborator

This patchseries adds IPC4 support for NXP i.MX platforms, i.MX8MP, i.MX8ULP, i.MX8QXP, i.MX8QM which enabled SOF on HIFI4 DSP and i.MX95, i.MX8MP which enable SOF via M7 core.

The patches are in 3 main areas:

  • I.MX plafatform support: here we implement a notification mechanism similar to IPC3 were the DSP sends a period elapsed notirication to the application processor.
  • rimage support, we introduce rimage config v1.1 which is similar with v1.0 but adds an ext-manifiest header.
  • topology: IPC4 uses tplg2 format. Add simple topology for capture and playback.

A host without a DMA position register (i.MX) needs to publish its byte
counter so the driver can derive the ALSA PCM pointer. Add host_byte_cnt[]
to struct ipc4_fw_registers, indexed by host gateway id, carved out of
reserved space to preserve the following fields' offsets.

Signed-off-by: Daniel Baluta <daniel.baluta@nxp.com>
i.MX has no host DMA like Intel HDA; the transfer is driven by a software
DMA over the ALSA buffer. In copier_host_create() read the PCM buffer
physical address from a GTW_IMX_HOST_CONFIG_ID TLV in gtw_cfg.config_data,
install it as a single element and use one-shot copy, as the IPC3 path does.
host_common_params() keeps one period per element for that case. Gated on
CONFIG_IMX.

Signed-off-by: Daniel Baluta <daniel.baluta@nxp.com>
i.MX has no host DMA to raise a period interrupt, so the DSP host copier
emits a vendor notification (type 200) once per host period carrying the
host gateway id. The kernel maps it to the substream and calls
snd_sof_pcm_period_elapsed().

Signed-off-by: Daniel Baluta <daniel.baluta@nxp.com>
i.MX has no host DMA and no HDA link position registers. On each host DMA
callback, write the host byte counter into the FW registers window
(host_byte_cnt[gateway_id]) so the host driver can derive the PCM pointer,
and send the vendor period-elapsed notification once per ALSA period so the
driver runs snd_sof_pcm_period_elapsed(). Both are i.MX only; a gateway id
beyond the byte counter slots is rejected at copier creation.

Signed-off-by: Daniel Baluta <daniel.baluta@nxp.com>
i.MX SAI/ESAI/MICFIL feed a Zephyr SDMA channel, unlike the Intel gateways.
Set the two DMA parameters the IPC3 path already sets:

* dai_config_dma_channel(): arm the channel on the DAI handshake low byte
  (the SDMA event source), or the FIFO request never triggers it;
* ipc_dai_data_config(): set the DMA burst to the DAI FIFO depth.

Signed-off-by: Daniel Baluta <daniel.baluta@nxp.com>
Add IPC4 connector node types for the i.MX SAI link: output (28) and
input (29). Direction comes from the node type parity, so 27 is unused.
Add the matching topology2 constants and dai-copier node_type values.

Signed-off-by: Daniel Baluta <daniel.baluta@nxp.com>
On i.MX the kernel passes the DAI configuration from topology as a
GTW_IMX_DAI_CONFIG_ID TLV (struct sof_ipc_dai_config) in the DAI copier
gateway config, after the gateway attributes.

Create SAI link DAI copiers as SOF_DAI_IMX_SAI, taking dai.format from the
TLV, and pass the TLV to dai_set_config() for SAI, ESAI and MICFIL.

Requires the matching kernel change.

Signed-off-by: Daniel Baluta <daniel.baluta@nxp.com>
The Linux SOF IPC4 loader reads an extended manifest at the start of the
firmware file to discover the firmware modules: it builds its module ID
to UUID table from the module entries and uses it to instantiate the
copier, gain and other modules. Intel images get these entries from the
signed manifest; i.MX images are not signed and have no such manifest.

Add an i.MX IPC4 ext-manifest writer, written to <out>.xman and placed
in front of the image:

  - an "$AE1" extended manifest header (struct fw_ext_man_cavs_header,
    version 4.0) covering only itself;
  - a 48-byte gap: the kernel finds the fw header at the ext-manifest
    length plus its manifest_fw_hdr_offset, which must not be zero;
  - an "$AM1" fw binary header (struct sof_man_fw_header) with the
    firmware version and module count;
  - one struct sof_man_module per record of the base firmware ".module"
    ELF section, with the module ID set to the table index. i.MX uses no
    module config blocks or segments, so those fields are zero.

Select it with a new rimage config version 1.1: the v1.0 simple image
plus this ext-manifest. v1.0 and v1.1 share one parser. Per-SoC configs
are added with each platform's IPC4 support.

Signed-off-by: Daniel Baluta <daniel.baluta@nxp.com>
i.MX has no IMR-resident rimage manifest for ipc4_get_comp_drv() to walk.
Each i.MX platform links its module manifest table into the image, with
the module ID equal to the table index (base FW is entry 0).

Add platform_ipc4_get_module() for the platforms to provide, and resolve
module IDs through it on i.MX, the same way the fuzzer build resolves
them through its own lookup.

Signed-off-by: Daniel Baluta <daniel.baluta@nxp.com>
Add an optional extra_conf field to PlatformConfig. When set, the file is
appended to EXTRA_CONF_FILE for that platform, so a build target can
apply a Kconfig overlay on top of the board defaults, e.g. to select a
different IPC version.

Signed-off-by: Daniel Baluta <daniel.baluta@nxp.com>
The 8-byte IPC4 primary/extension header does not fit the 4-byte MU data
register. Carry it in an SRAM slot in front of each mailbox payload
(MAILBOX_HOSTBOX_HDR_BASE / MAILBOX_DSPBOX_HDR_BASE, provided by each
platform) and keep using the MU only as a doorbell:

  - read the host header from the hostbox slot via
    ipc_platform_compact_read_msg();
  - write the DSP header to the dspbox slot before sending, followed by
    the payload, if any;
  - imx_ipc4_boot_complete() sends SOF_IPC4_FW_READY as a notification.

Also add the IPC4 code that is the same on all i.MX platforms:

  - the module manifest table, emitted into the ".module" section for
    rimage and resolved at runtime via platform_ipc4_get_module();
  - clear the SW register (LLP) window in platform_ipc_init(): it is not
    part of the loaded image, so it keeps stale slots across reloads.

Signed-off-by: Daniel Baluta <daniel.baluta@nxp.com>
Add IPC4 support for the i.MX8MP HiFi4 DSP on top of the shared i.MX IPC4
transport:

  - memory.h/mailbox.h: an 8-byte IPC4 header slot at the start of the
    inbox and outbox (MAILBOX_*_HDR_BASE), and the SW register (LLP)
    window with its accessors. The SW registers reuse the exception
    window, which only IPC3 uses. The IPC3 layout is unchanged.
  - clk.h: CPU_LOWEST_FREQ_IDX and HW_CFG_VERSION for the IPC4 base FW.
  - platform.c: send FW_READY via imx_ipc4_boot_complete(); the IPC3
    fw_ready and memory window descriptors are IPC3 only.
  - keep the ".module" manifest table in a loaded section and select the
    imx8m_ipc4 rimage config, which adds the IPC4 ext-manifest.
  - an IPC4 board overlay and an opt-in 'imx8m-ipc4' build target. The
    default 'imx8m' target stays IPC3.

Signed-off-by: Daniel Baluta <daniel.baluta@nxp.com>
Add IPC4 support for the i.MX8QM/i.MX8QXP HiFi4 DSPs on top of the shared
i.MX IPC4 transport, as for imx8m:

  - memory.h/mailbox.h: an 8-byte IPC4 header slot at the start of the
    inbox and outbox, and the SW register (LLP) window with its
    accessors, reusing the IPC3-only exception window. The IPC3 layout is
    unchanged.
  - platform.h/clk.h: skip the IPC3 fw_status box under IPC4; add
    CPU_LOWEST_FREQ_IDX and HW_CFG_VERSION for the IPC4 base FW.
  - platform.c: send FW_READY via imx_ipc4_boot_complete().
  - keep the ".module" manifest table in a loaded section and select the
    imx8_ipc4 / imx8x_ipc4 rimage configs.
  - IPC4 board overlays and opt-in 'imx8-ipc4' / 'imx8x-ipc4' build
    targets. The default 'imx8' / 'imx8x' targets stay IPC3.

Signed-off-by: Daniel Baluta <daniel.baluta@nxp.com>
Add IPC4 support for the i.MX95 Cortex-M7 on top of the shared i.MX IPC4
transport:

  - mailbox.h: an 8-byte IPC4 header slot at the start of the inbox and
    outbox, and the SW register (LLP) window with its accessors.
  - platform.h/clk.h: the DMA trace buffer size, and CPU_LOWEST_FREQ_IDX
    and HW_CFG_VERSION for the IPC4 base FW.
  - platform.c: send FW_READY via imx_ipc4_boot_complete().
  - keep the ".module" manifest table in a loaded section and select the
    imx95_ipc4 rimage config.
  - an IPC4 board overlay and an opt-in 'imx95-ipc4' build target. The
    default 'imx95' target stays IPC3.

Signed-off-by: Daniel Baluta <daniel.baluta@nxp.com>
Add IPC4 support for the i.MX8ULP HiFi4 DSP on top of the shared i.MX IPC4
transport, as for imx8/imx8m:

  - memory.h/mailbox.h: an 8-byte IPC4 header slot at the start of the
    inbox and outbox, and the SW register (LLP) window with its
    accessors, reusing the IPC3-only exception window. i.MX8ULP has a
    larger 0x2800 debug window, so the SW register window is at offset
    0x4800; the kernel imx8ulp_chip_info must match it.
  - platform.h/clk.h: skip the IPC3 fw_status box under IPC4; add
    CPU_LOWEST_FREQ_IDX and HW_CFG_VERSION for the IPC4 base FW.
  - platform.c: send FW_READY via imx_ipc4_boot_complete().
  - keep the ".module" manifest table in a loaded section and select the
    imx8ulp_ipc4 rimage config.
  - an IPC4 board overlay and an opt-in 'imx8ulp-ipc4' build target. The
    default 'imx8ulp' target stays IPC3.

Signed-off-by: Daniel Baluta <daniel.baluta@nxp.com>
Add the IPC4 WM8960 topologies for the i.MX8MP EVK (WM8960 on SAI3),
playback and duplex, plus the shared i.MX topology infrastructure: the
hw_config_imx SAI helper and the dai-copier-io pipeline include. Register
the sof-imx8mp-wm8960[-duplex] targets. The imx8-wm8960 sources are reused
by the i.MX8QM/8QXP targets on SAI1.

Signed-off-by: Daniel Baluta <daniel.baluta@nxp.com>
Wire up the WM8960 IPC4 topologies for the i.MX8QM/i.MX8QXP MEK boards
(codec on SAI1): register the sof-imx8-wm8960[-duplex] targets reusing the
imx8-wm8960 sources, and give the duplex capture path an explicit indexed
pcm_caps direction so the module adapter accepts it.

Signed-off-by: Daniel Baluta <daniel.baluta@nxp.com>
Add the i.MX95 + WM8962 IPC4 topologies (playback and duplex) and register
them in the imx8 production tplg targets. The SAI back-end hw_config declares
the WM8962 as bit-clock/frame-sync provider (SAI as consumer), matching the
board wiring.

Signed-off-by: Daniel Baluta <daniel.baluta@nxp.com>
@dbaluta
dbaluta requested a review from lbetlej as a code owner November 10, 2026 12:36
Copilot AI balanced review requested due to automatic review settings November 10, 2026 12:36

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Unchecked TLV lengths can cause out-of-bounds reads, while incorrect i.MX mailbox mapping and SAI configuration handling break ABI reporting and DAI setup.

4 open issues
What changed in this PR

This PR extends SOF’s IPC4 support to NXP i.MX platforms, connecting firmware messaging and audio transport with image packaging and topology2 definitions.

Changes:

  • Add i.MX IPC4 mailbox transport, module lookup, host DMA counters, and period-elapsed notifications.
  • Introduce rimage v1.1 configurations, extended-manifest generation, and opt-in IPC4 build targets.
  • Add playback and duplex topologies for WM8960 and WM8962 codecs with reusable SAI pipeline definitions.
File Description
zephyr/​CMakeLists.txt Select IPC4 image targets and retain module manifests.
tools/​topology/​topology2/​production/​tplg-targets-imx8.cmake Register playback and duplex topology targets.
tools/​topology/​topology2/​include/​pipelines/​dai-copier-io.conf Add reusable scheduled DAI pipelines.
tools/​topology/​topology2/​include/​dais/​hw_config_imx.conf Define i.MX DAI clock and format attributes.
tools/​topology/​topology2/​include/​components/​dai-copier.conf Accept SAI gateway node types.
tools/​topology/​topology2/​include/​common/​common_definitions.conf Define SAI gateway class IDs.
tools/​topology/​topology2/​imx95-wm8962.conf Add i.MX95 playback topology.
tools/​topology/​topology2/​imx95-wm8962-duplex.conf Add i.MX95 playback and capture topology.
tools/​topology/​topology2/​imx8-wm8960.conf Add scheduled SAI pipeline and hardware configuration.
tools/​topology/​topology2/​imx8-wm8960-duplex.conf Add i.MX8 playback and capture topology.
tools/​rimage/​src/​include/​rimage/​ext_manifest_gen.h Declare the i.MX IPC4 manifest writer.
tools/​rimage/​src/​ext_manifest.c Generate IPC4 manifests from module records.
tools/​rimage/​src/​adsp_config.c Support v1.1 image configurations.
tools/​rimage/​config/​imx95_ipc4.toml Define i.MX95 IPC4 image layout.
tools/​rimage/​config/​imx8x_ipc4.toml Define i.MX8QXP IPC4 image layout.
tools/​rimage/​config/​imx8ulp_ipc4.toml Define i.MX8ULP IPC4 image layout.
tools/​rimage/​config/​imx8m_ipc4.toml Define i.MX8MP IPC4 image layout.
tools/​rimage/​config/​imx8_ipc4.toml Define i.MX8QM IPC4 image layout.
src/​platform/​imx95/​platform.c Select IPC4 boot notification handling.
src/​platform/​imx95/​linker/​module-section.ld Retain module records in the firmware image.
src/​platform/​imx95/​include/​platform/​platform.h Define local trace-buffer size.
src/​platform/​imx95/​include/​platform/​lib/​mailbox.h Add IPC4 header slots and register accessors.
src/​platform/​imx95/​include/​platform/​lib/​clk.h Supply IPC4 clock and hardware constants.
src/​platform/​imx8ulp/​platform.c Select IPC4 boot notification handling.
src/​platform/​imx8ulp/​linker/​module-section.ld Retain module records in the firmware image.
src/​platform/​imx8ulp/​include/​platform/​platform.h Restrict legacy panic signaling to IPC3.
src/​platform/​imx8ulp/​include/​platform/​lib/​memory.h Reserve IPC4 headers and software registers.
src/​platform/​imx8ulp/​include/​platform/​lib/​mailbox.h Add IPC4 mailbox and register accessors.
src/​platform/​imx8ulp/​include/​platform/​lib/​clk.h Supply IPC4 clock and hardware constants.
src/​platform/​imx8m/​platform.c Select IPC4 boot notification handling.
src/​platform/​imx8m/​linker/​module-section.ld Retain module records in SDRAM.
src/​platform/​imx8m/​include/​platform/​lib/​memory.h Reserve IPC4 headers and software registers.
src/​platform/​imx8m/​include/​platform/​lib/​mailbox.h Add IPC4 mailbox and register accessors.
src/​platform/​imx8m/​include/​platform/​lib/​clk.h Supply IPC4 clock and hardware constants.
src/​platform/​imx8/​platform.c Select IPC4 boot notification handling.
src/​platform/​imx8/​linker/​module-section.ld Retain module records in the firmware image.
src/​platform/​imx8/​include/​platform/​platform.h Restrict legacy panic signaling to IPC3.
src/​platform/​imx8/​include/​platform/​lib/​memory.h Reserve IPC4 headers and software registers.
src/​platform/​imx8/​include/​platform/​lib/​mailbox.h Add IPC4 mailbox and register accessors.
src/​platform/​imx8/​include/​platform/​lib/​clk.h Supply IPC4 clock and hardware constants.
src/​kernel/​ipc/​ipc4/​notification.c Send i.MX host-period notifications.
src/​kernel/​drivers/​imx/​ipc.c Implement IPC4 transport and module manifest lookup.
src/​ipc/​ipc4/​helper.c Resolve i.MX module IDs to component drivers.
src/​ipc/​ipc4/​dai.c Configure i.MX DMA and parse DAI configuration TLVs.
src/​include/​sof/​platform.h Declare i.MX IPC4 platform interfaces.
src/​include/​ipc4/​notification.h Define the i.MX period notification interface.
src/​include/​ipc4/​gateway.h Define SAI gateways and i.MX configuration payloads.
src/​include/​ipc4/​fw_reg.h Allocate host byte-counter registers.
src/​audio/​host-zephyr.c Preserve i.MX DMA rings and reset reporting state.
src/​audio/​copier/​host_copier.h Enable period tracking for i.MX hosts.
src/​audio/​copier/​copier.c Recognize SAI gateway types.
src/​audio/​copier/​copier_host.c Configure host buffers and publish period progress.
src/​audio/​copier/​copier_dai.c Create SAI copiers from gateway configuration.
scripts/​xtensa-build-zephyr.py Add opt-in i.MX IPC4 targets and overlays.
app/​boards/​imx95_evk_mimx9596_m7_ddr_ipc4.conf Add i.MX95 IPC4 overlay.
app/​boards/​imx8ulp_evk_mimx8ud7_adsp_ipc4.conf Add i.MX8ULP IPC4 overlay.
app/​boards/​imx8qxp_mek_mimx8qx6_adsp_ipc4.conf Add i.MX8QXP IPC4 overlay.
app/​boards/​imx8qm_mek_mimx8qm6_adsp_ipc4.conf Add i.MX8QM IPC4 overlay.
app/​boards/​imx8mp_evk_mimx8ml8_adsp_ipc4.conf Add i.MX8MP IPC4 and driver settings.

Review effort: Balanced

if (dcfg && dlen >= sizeof(struct sof_ipc_dai_config))
dai.format = ((struct sof_ipc_dai_config *)dcfg)->format;
}
dai.type = SOF_DAI_IMX_SAI;
Comment on lines +148 to +153
if (total > prefix)
tlv_value_get((const uint8_t *)copier_cfg->gtw_cfg.config_data + prefix,
total - prefix, GTW_IMX_HOST_CONFIG_ID,
(void **)&host_cfg, &host_cfg_len);

if (host_cfg && host_cfg_len >= sizeof(*host_cfg) && host_cfg->phy_addr) {
Comment on lines +70 to +71
#define MAILBOX_SW_REG_BASE SRAM_SW_REG_BASE
#define MAILBOX_SW_REG_SIZE SRAM_SW_REG_SIZE
Comment on lines +245 to +247
ret = copier_host_imx_dma_setup(hd, copier_cfg);
if (ret < 0)
goto e_conv;
@dbaluta

dbaluta commented Nov 10, 2026

Copy link
Copy Markdown
Collaborator Author

@lyakh @lgirdwood @RanderWang One of the first open issues is this change:

@@ -179,7 +182,8 @@ struct ipc4_fw_registers {
        union ipc4_rom_info rom_info;  /**< ROM version and load capabilities (at offset 0x18). */
        uint32_t abi_ver;              /**< Layout version (IPC4_FW_REGS_ABI_VER at offset 0x1C). */
        uint8_t slave_core_sts[IPC4_MAX_SUPPORTED_ADSP_CORES]; /**< Status byte per secondary core. */
-       uint32_t rsvd2[6];             /**< Reserved padding. */
+       uint32_t rsvd2[2];             /**< Reserved padding. */
+       uint64_t host_byte_cnt[IPC4_MAX_HOST_BYTE_CNT_SLOTS]; /**< Host DMA byte counter per host gateway. */

Here we are borrowing 32 bytes in order to pass DMA byte counter as on i.MX there is no actual DMA between Host and Application Processor.

@lgirdwood lgirdwood left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would recommend moving the mailbox to zephyr since the HW macros and IP drivers are being removed from SOF codebase and moved to Zephyr.

*ptr = src;
}

/* IPC4 SW registers (copier LLP); carved out of mailbox SRAM */

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

btw, the mailbox stuff should all go in Zephyr - all the non zephyr drivers are deprecated to be removed.

Comment on lines +102 to +110
#define SRAM_OUTBOX_HDR_BASE SDRAM1_BASE
#define SRAM_OUTBOX_BASE (SRAM_OUTBOX_HDR_BASE + SRAM_IPC4_HDR_SIZE)
#define SRAM_OUTBOX_SIZE (0x1000 - SRAM_IPC4_HDR_SIZE)
#define SRAM_OUTBOX_OFFSET SRAM_IPC4_HDR_SIZE

#define SRAM_INBOX_HDR_BASE (SRAM_OUTBOX_BASE + SRAM_OUTBOX_SIZE)
#define SRAM_INBOX_BASE (SRAM_INBOX_HDR_BASE + SRAM_IPC4_HDR_SIZE)
#define SRAM_INBOX_SIZE (0x1000 - SRAM_IPC4_HDR_SIZE)
#define SRAM_INBOX_OFFSET (SRAM_OUTBOX_OFFSET + SRAM_OUTBOX_SIZE + SRAM_IPC4_HDR_SIZE)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is now in DT for zephyr

@intel-sofci

Copy link
Copy Markdown

PR 11435: test results

Run date: 2026-11-10 13:03 UTC

Tested commit: aae837feffe6693fe9ccd8676ea9d103ac90acc7

mtl pass rate lnl pass rate ptl pass rate wcl pass rate nvl pass rate

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants