From f3eae4a0a309772be64536dd864692339d36b267 Mon Sep 17 00:00:00 2001 From: Sumit Batra Date: Wed, 19 Nov 2025 20:20:09 +0530 Subject: [PATCH 1/6] west.yml: bump hal_nxp rev to include S32K3 C40 flash support Update hal_nxp SHA so Zephyr uses the revision that adds S32K3 C40 flash controller support. Signed-off-by: Sumit Batra --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index b2d75948d4bb9..45a4b96e006c4 100644 --- a/west.yml +++ b/west.yml @@ -210,7 +210,7 @@ manifest: groups: - hal - name: hal_nxp - revision: 6d6ab91d5cc71c872353af1957d19f3d930df0fd + revision: 59a3b6c6ec1aa4ed11c2a4ba75f197f3b3a9c43d path: modules/hal/nxp groups: - hal From 0d40dffbed553047560a8c90d080e56a36dea2ca Mon Sep 17 00:00:00 2001 From: Sumit Batra Date: Wed, 19 Nov 2025 20:21:43 +0530 Subject: [PATCH 2/6] drivers: flash: Add MCUX C40 flash controller driver Add flash controller driver for the on-chip C40 flash controller The driver is backed by the MCUX C40 HAL and implements read/erase/program, page layout, and an optional protection policy that can lock well-known regions (IVT/MCUboot) derived from devicetree. Key details: - Selects FLASH_HAS_DRIVER_ENABLED / FLASH_HAS_EXPLICIT_ERASE / FLASH_HAS_PAGE_LAYOUT. - Runs erase/program from SRAM when XIP by relocating both the shim and the MCUX HAL source if CODE_DATA_RELOCATION_SRAM=y. - Optional protection pass at init (FLASH_MCUX_C40_APPLY_PROTECTION), which aligns windows to sector boundaries and applies lock/unlock using the HAL. This is useful on XIP systems to keep IVT/bootloader ranges read-only; can be disabled if a bootloader or security policy manages protection instead. Files: - drivers/flash/flash_mcux_c40.c (new) - drivers/flash/CMakeLists.txt (+zephyr_code_relocate when needed, Compliance fixes) - drivers/flash/Kconfig.mcux (enable flash driver, reloc & protection) - modules/hal_nxp/mcux/mcux-sdk-ng/drivers/drivers.cmake Signed-off-by: Sumit Batra --- drivers/flash/CMakeLists.txt | 11 + drivers/flash/Kconfig.mcux | 28 ++ drivers/flash/flash_mcux_c40.c | 387 ++++++++++++++++++ .../mcux/mcux-sdk-ng/drivers/drivers.cmake | 4 + 4 files changed, 430 insertions(+) create mode 100644 drivers/flash/flash_mcux_c40.c diff --git a/drivers/flash/CMakeLists.txt b/drivers/flash/CMakeLists.txt index 09c7187ad1e81..36771f13521a6 100644 --- a/drivers/flash/CMakeLists.txt +++ b/drivers/flash/CMakeLists.txt @@ -184,6 +184,17 @@ if(CONFIG_FLASH_NXP_S32_QSPI_NOR OR CONFIG_FLASH_NXP_S32_QSPI_HYPERFLASH) zephyr_library_include_directories(${ZEPHYR_BASE}/drivers/memc) endif() +zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_MCUX_C40 flash_mcux_c40.c) + +if(CONFIG_SOC_FLASH_MCUX_C40 AND CONFIG_CODE_DATA_RELOCATION) + # Relocate the Zephyr driver to RAM when relocation is enabled + zephyr_code_relocate(FILES ${CMAKE_CURRENT_LIST_DIR}/flash_mcux_c40.c LOCATION RAM) + if(DEFINED ZEPHYR_HAL_NXP_MODULE_DIR) + # Relocate the HAL driver to RAM + zephyr_code_relocate(FILES ${ZEPHYR_HAL_NXP_MODULE_DIR}/mcux/mcux-sdk-ng/drivers/flash_c40/fsl_c40_flash.c LOCATION RAM) + endif() +endif() + if(CONFIG_SOC_FLASH_RENESAS_RA_HP) zephyr_library_sources(soc_flash_renesas_ra_hp.c) zephyr_library_sources_ifdef(CONFIG_FLASH_EX_OP_ENABLED soc_flash_renesas_ra_hp_ex_op.c) diff --git a/drivers/flash/Kconfig.mcux b/drivers/flash/Kconfig.mcux index 17a2e7772cb44..513add2657aae 100644 --- a/drivers/flash/Kconfig.mcux +++ b/drivers/flash/Kconfig.mcux @@ -130,3 +130,31 @@ config FLASH_MCUX_XSPI select FLASH_HAS_EXPLICIT_ERASE help Enable the mcux xspi flash driver. + +# MCUX C40 internal flash driver +config SOC_FLASH_MCUX_C40 + bool "MCUX C40 flash driver" + default y + depends on DT_HAS_NXP_C40_FLASH_CONTROLLER_ENABLED + depends on DT_HAS_NXP_C40_FLASH_ENABLED + select FLASH_HAS_DRIVER_ENABLED + select FLASH_HAS_EXPLICIT_ERASE + select FLASH_HAS_PAGE_LAYOUT + # C40 uses controller commands, not CPU stores to flash + # so we are not relaxing MPU for ROM writes. + # Relocate driver/HAL when XIP so erase/program run from SRAM: + imply CODE_DATA_RELOCATION if XIP + imply CODE_DATA_RELOCATION_SRAM if XIP + help + Enable the NXP MCUX C40 internal flash driver + Provides Zephyr flash driver using MCUX C40 HAL. + +config SOC_FLASH_MCUX_C40_APPLY_PROTECTION + bool "Apply default protection windows (IVT/MCUboot) at init" + depends on SOC_FLASH_MCUX_C40 + default y if XIP + help + When enabled, the driver locks/unlocks protection for well-known + regions derived from devicetree (e.g. ivt_header, ivt_pad, mcuboot) + during driver init. Useful on XIP systems to keep IVT/bootloader + areas read-only. Disable if your bootloader/policy manages this. diff --git a/drivers/flash/flash_mcux_c40.c b/drivers/flash/flash_mcux_c40.c new file mode 100644 index 0000000000000..075aca0c495df --- /dev/null +++ b/drivers/flash/flash_mcux_c40.c @@ -0,0 +1,387 @@ +/* + * Copyright 2025 NXP + * + * SPDX-License-Identifier: Apache-2.0 + * + * NXP flash controller driver for C40 flash part + */ + +#define DT_DRV_COMPAT nxp_c40_flash_controller + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(flash_mcux_c40, CONFIG_FLASH_LOG_LEVEL); + +#include + +static inline int mcux_to_errno(status_t s) +{ + switch (s) { + case kStatus_FLASH_Success: + return 0; + case kStatus_FLASH_InvalidArgument: + case kStatus_FLASH_SizeError: + case kStatus_FLASH_AlignmentError: + case kStatus_FLASH_AddressError: + return -EINVAL; + case kStatus_FLASH_AccessError: + case kStatus_FLASH_ProtectionViolation: + case kStatus_FLASH_CommandFailure: + return -EIO; + case kStatus_FLASH_EraseKeyError: + return -EPERM; + default: + return -EIO; + } +} + +struct prot_range { + uint32_t off; + uint32_t len; + const char *name; +}; + +struct mcux_c40_cfg { + uint32_t base; /* flash memory-mapping address */ + uint32_t size; /* total bytes covered by this instance */ + uint32_t erase_block; /* 8 KiB on C40 */ + uint32_t write_block; /* 8 bytes min. program unit */ + const struct flash_parameters *params; +#if defined(CONFIG_SOC_FLASH_MCUX_C40_APPLY_PROTECTION) + const struct prot_range *prot_tbl; + size_t prot_cnt; +#endif +}; + +struct mcux_c40_data { + struct k_spinlock lock; + flash_config_t cfg; /* MCUX HAL context */ +}; + +static inline bool intersects(uint32_t a_off, uint32_t a_len, uint32_t b_off, uint32_t b_len) +{ + const uint32_t a_end = a_off + a_len; + const uint32_t b_end = b_off + b_len; + + return (a_off < b_end) && (b_off < a_end); +} + +static int flash_mcux_c40_read(const struct device *dev, off_t off, void *buf, size_t len) +{ + const struct mcux_c40_cfg *cfg = dev->config; + + if ((off < 0) || ((size_t)off + len > cfg->size)) { + return -EINVAL; + } + + memcpy(buf, (const void *)(cfg->base + (uintptr_t)off), len); + return 0; +} + +static int flash_mcux_c40_write(const struct device *dev, off_t off, const void *buf, size_t len) +{ + const struct mcux_c40_cfg *cfg = dev->config; + struct mcux_c40_data *data = dev->data; + k_spinlock_key_t key; + status_t st; + + /* Bounds check */ + if ((off < 0) || ((size_t)off + len > cfg->size)) { + return -EINVAL; + } + + /* The HAL enforces alignment to C40 constraints: + * Minimum write chunk is C40_WRITE_SIZE_MIN (8 bytes). + * Writes are most efficient in quad-page (128 bytes). + * We perform a light check: write must be multiple of write_block, + * and start aligned to write_block. For more flexibility, you could + * implement a read-modify-write cache; for now we map 1:1 to HAL. + */ + if (((uintptr_t)off % cfg->write_block) != 0 || (len % cfg->write_block) != 0) { + return -EINVAL; + } + + key = k_spin_lock(&data->lock); + + barrier_dsync_fence_full(); + + z_barrier_isync_fence_full(); + + st = FLASH_Program(&data->cfg, (uint32_t)(cfg->base + (uintptr_t)off), (uint32_t *)buf, + (uint32_t)len); + + barrier_dsync_fence_full(); + + k_spin_unlock(&data->lock, key); + + /* The array changed behind the CPU; drop stale D-cache lines covering the range */ + sys_cache_data_invd_range((void *)(cfg->base + (uintptr_t)off), len); + + return mcux_to_errno(st); +} + +static int flash_mcux_c40_erase(const struct device *dev, off_t off, size_t len) +{ + const struct mcux_c40_cfg *cfg = dev->config; + struct mcux_c40_data *data = dev->data; + k_spinlock_key_t key; + status_t st; + + if ((off < 0) || ((size_t)off + len > cfg->size)) { + return -EINVAL; + } + if (((uintptr_t)off % cfg->erase_block) != 0 || (len % cfg->erase_block) != 0) { + return -EINVAL; + } + + key = k_spin_lock(&data->lock); + + barrier_dsync_fence_full(); + + z_barrier_isync_fence_full(); + + st = FLASH_Erase(&data->cfg, (uint32_t)(cfg->base + (uintptr_t)off), (uint32_t)len, + kFLASH_ApiEraseKey); + + barrier_dsync_fence_full(); + + k_spin_unlock(&data->lock, key); + + sys_cache_data_invd_range((void *)(cfg->base + (uintptr_t)off), len); + return mcux_to_errno(st); +} + +static const struct flash_parameters *flash_mcux_c40_get_parameters(const struct device *dev) +{ + const struct mcux_c40_cfg *cfg = dev->config; + + return cfg->params; +} + +#ifdef CONFIG_FLASH_PAGE_LAYOUT +static void flash_mcux_c40_pages_layout(const struct device *dev, + const struct flash_pages_layout **layout, size_t *layout_size) +{ + const struct mcux_c40_cfg *cfg = dev->config; + static struct flash_pages_layout l; + + l.pages_count = cfg->size / cfg->erase_block; + l.pages_size = cfg->erase_block; + + *layout = &l; + *layout_size = 1; +} +#endif + +/* Optional “lock policy” executed at init (opt-in via Kconfig) */ +#if defined(CONFIG_SOC_FLASH_MCUX_C40_APPLY_PROTECTION) +static __attribute__((noinline)) status_t flash_c40_apply_protection(struct mcux_c40_data *data, + uint32_t flash_base, + uint32_t total_sz, uint32_t erase_sz, + const struct prot_range *pr, + size_t npr) +{ + uint32_t off; + uint32_t abs; + k_spinlock_key_t key; + size_t i; + bool lock_it; + flash_config_t *fcfg = &data->cfg; + + for (off = 0; off < total_sz; off += erase_sz) { + status_t ps; + + lock_it = false; + + for (i = 0; i < npr; i++) { + if (intersects(off, erase_sz, pr[i].off, pr[i].len)) { + lock_it = true; + break; + } + } + abs = flash_base + off; + + ps = FLASH_GetSectorProtection(fcfg, abs); + if (lock_it) { + status_t s; + + if (ps != kStatus_FLASH_SectorLocked) { + key = k_spin_lock(&data->lock); + + /* Didn't use ISB here since there is no + * instruction side stream change + */ + barrier_dsync_fence_full(); + + s = FLASH_SetSectorProtection(fcfg, abs, true); + + barrier_dsync_fence_full(); + + k_spin_unlock(&data->lock, key); + + if (s != kStatus_FLASH_Success) { + return s; + } + } + } else { + status_t s; + + if (ps != kStatus_FLASH_SectorUnlocked) { + key = k_spin_lock(&data->lock); + + barrier_dsync_fence_full(); + + s = FLASH_SetSectorProtection(fcfg, abs, false); + + barrier_dsync_fence_full(); + + k_spin_unlock(&data->lock, key); + if (s != kStatus_FLASH_Success) { + return s; + } + } + } + } + return kStatus_FLASH_Success; +} +#endif /* CONFIG_SOC_FLASH_MCUX_C40_APPLY_PROTECTION */ + +static int flash_mcux_c40_init(const struct device *dev) +{ + const struct mcux_c40_cfg *cfg = dev->config; + struct mcux_c40_data *data = dev->data; + status_t st; + + st = FLASH_Init(&data->cfg); + if (st != kStatus_FLASH_Success) { + LOG_ERR("FLASH_Init failed: %d", (int)st); + return mcux_to_errno(st); + } + + LOG_DBG("C40 flash: base=0x%lx size=0x%lx erase=0x%lx write=0x%lx", + (unsigned long)cfg->base, (unsigned long)cfg->size, (unsigned long)cfg->erase_block, + (unsigned long)cfg->write_block); + +#if defined(CONFIG_SOC_FLASH_MCUX_C40_APPLY_PROTECTION) + /* Align protected windows to sector boundaries */ + struct prot_range prot_aligned[8]; + size_t nprot_al = 0; + size_t i; + uint32_t s; + uint32_t e; + uint32_t sa; + uint32_t ea; + + for (i = 0; i < cfg->prot_cnt && nprot_al < ARRAY_SIZE(prot_aligned); i++) { + s = cfg->prot_tbl[i].off; + e = s + cfg->prot_tbl[i].len; + sa = ROUND_DOWN(s, cfg->erase_block); + ea = ROUND_UP(e, cfg->erase_block); + if (sa >= cfg->size) { + continue; + } + if (ea > cfg->size) { + ea = cfg->size; + } + + prot_aligned[nprot_al] = (struct prot_range){ + .off = sa, + .len = ea - sa, + .name = cfg->prot_tbl[i].name, + }; + nprot_al++; + } + + st = flash_c40_apply_protection(data, cfg->base, cfg->size, cfg->erase_block, prot_aligned, + nprot_al); + if (st != kStatus_FLASH_Success) { + LOG_ERR("Protection apply failed: %d", (int)st); + return mcux_to_errno(st); + } + LOG_DBG("Protection policy applied (%u window%s)", (unsigned int)nprot_al, + (nprot_al == 1 ? "" : "s")); +#endif + return 0; +} + +static const struct flash_driver_api mcux_c40_api = { + .read = flash_mcux_c40_read, + .write = flash_mcux_c40_write, + .erase = flash_mcux_c40_erase, + .get_parameters = flash_mcux_c40_get_parameters, +#ifdef CONFIG_FLASH_PAGE_LAYOUT + .page_layout = flash_mcux_c40_pages_layout, +#endif +}; + +/* Controller node for this instance */ +#define C40_CTRL_NODE(inst) DT_DRV_INST(inst) + +#define C40_FLASH_NODE(inst) DT_INST_CHILD(inst, flash_0) + +/* Get the partition table properties of this instance's flash */ +#define C40_PROT_ENTRY(lbl, inst) \ + COND_CODE_1( \ + DT_NODE_HAS_STATUS(DT_NODELABEL(lbl), okay), \ + (COND_CODE_1( \ + DT_SAME_NODE( \ + DT_PARENT(DT_NODELABEL(lbl)), \ + C40_FLASH_NODE(inst)), \ + ({ .off = (uint32_t)FIXED_PARTITION_OFFSET(lbl), \ + .len = (uint32_t)FIXED_PARTITION_SIZE(lbl), \ + .name = #lbl },), \ + ()) \ + ), \ + ()) + +#if defined(CONFIG_SOC_FLASH_MCUX_C40_APPLY_PROTECTION) +#define C40_MAKE_PROT_TBL(inst) \ + static const struct prot_range mcux_c40_prot_##inst[] = { \ + /* keep IVT and bootloader areas read-only on XIP systems */ \ + C40_PROT_ENTRY(ivt_header, inst) \ + C40_PROT_ENTRY(ivt_pad, inst) /* if present */ \ + C40_PROT_ENTRY(mcuboot, inst) /* or boot_partition */ \ + C40_PROT_ENTRY(boot_partition, inst) \ + }; \ + enum { mcux_c40_prot_cnt_##inst = ARRAY_SIZE(mcux_c40_prot_##inst) } +#else +#define C40_MAKE_PROT_TBL(inst) +#endif + +#define C40_PARAMS(inst) \ + static const struct flash_parameters mcux_c40_params_##inst = { \ + .write_block_size = DT_PROP(C40_FLASH_NODE(inst), write_block_size), \ + .erase_value = 0xFF, \ + } + +#define C40_INIT(inst) \ + C40_MAKE_PROT_TBL(inst); \ + C40_PARAMS(inst); \ + static const struct mcux_c40_cfg mcux_c40_cfg_##inst = { \ + .base = DT_REG_ADDR(C40_FLASH_NODE(inst)), \ + .size = DT_REG_SIZE(C40_FLASH_NODE(inst)), \ + .erase_block = DT_PROP(C40_FLASH_NODE(inst), erase_block_size), \ + .write_block = DT_PROP(C40_FLASH_NODE(inst), write_block_size), \ + .params = &mcux_c40_params_##inst, \ + IF_ENABLED(CONFIG_SOC_FLASH_MCUX_C40_APPLY_PROTECTION, ( \ + .prot_tbl = mcux_c40_prot_##inst, \ + .prot_cnt = mcux_c40_prot_cnt_##inst, \ + )) \ + }; \ + static struct mcux_c40_data mcux_c40_data_##inst; \ + DEVICE_DT_DEFINE(C40_FLASH_NODE(inst), flash_mcux_c40_init, NULL, &mcux_c40_data_##inst,\ + &mcux_c40_cfg_##inst, POST_KERNEL, \ + CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &mcux_c40_api); \ + DEVICE_DT_INST_DEFINE(inst, NULL, NULL, NULL, NULL, POST_KERNEL, \ + CONFIG_KERNEL_INIT_PRIORITY_DEVICE, NULL); + +DT_INST_FOREACH_STATUS_OKAY(C40_INIT) diff --git a/modules/hal_nxp/mcux/mcux-sdk-ng/drivers/drivers.cmake b/modules/hal_nxp/mcux/mcux-sdk-ng/drivers/drivers.cmake index 27fcd925cf4ff..c376984e7c4c8 100644 --- a/modules/hal_nxp/mcux/mcux-sdk-ng/drivers/drivers.cmake +++ b/modules/hal_nxp/mcux/mcux-sdk-ng/drivers/drivers.cmake @@ -241,6 +241,10 @@ if(CONFIG_SOC_MCXW716C OR CONFIG_SOC_MCXW727C) endif() endif() +if(CONFIG_SOC_S32K344) + set_variable_ifdef(CONFIG_SOC_FLASH_MCUX_C40 CONFIG_MCUX_COMPONENT_driver.flash_c40) +endif() + if(CONFIG_SOC_SERIES_LPC51U68 OR CONFIG_SOC_SERIES_LPC54XXX) set_variable_ifdef(CONFIG_SOC_FLASH_MCUX CONFIG_MCUX_COMPONENT_driver.iap) endif() From d868bc79bf2c44393748a4c7d096be0c7ceabc46 Mon Sep 17 00:00:00 2001 From: Sumit Batra Date: Wed, 19 Nov 2025 20:23:06 +0530 Subject: [PATCH 3/6] dts: nxp: Add binding for C40 flash and flash controller MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce DT bindings for on-chip C40 flash and its controller and describe their corresponding nodes in nxp_s32k344_m7.dtsi. - Binding: dts/bindings/mtd/nxp,c40-flash.yaml Erase/write block sizes. - Binding: dts/bindings/flash_controller/nxp,c40-flash-controller.yaml Describe flash device (child) ranges - SoC nodes: With the new compatible and geometry properties. Keep status = "disabled" at the SoC level so boards opt-in. This prepares the platform for using Zephyr’s flash API / FLASH_MAP / MCUboot with internal code flash. Signed-off-by: Sumit Batra --- dts/arm/nxp/nxp_s32k344_m7.dtsi | 27 ++++++++++++------- .../nxp,c40-flash-controller.yaml | 19 +++++++++++++ dts/bindings/mtd/nxp,c40-flash.yaml | 19 +++++++++++++ 3 files changed, 55 insertions(+), 10 deletions(-) create mode 100644 dts/bindings/flash_controller/nxp,c40-flash-controller.yaml create mode 100644 dts/bindings/mtd/nxp,c40-flash.yaml diff --git a/dts/arm/nxp/nxp_s32k344_m7.dtsi b/dts/arm/nxp/nxp_s32k344_m7.dtsi index 21553748ba66f..1b120f37d5a4f 100644 --- a/dts/arm/nxp/nxp_s32k344_m7.dtsi +++ b/dts/arm/nxp/nxp_s32k344_m7.dtsi @@ -62,16 +62,23 @@ reg = <0x20400000 DT_SIZE_K(320)>; }; - /* - * Last 48Kb is reserved by Secure BAF, application core cannot access it. - * - * Do not assign the compatible for this now, when Flash API is implemented, - * need to check if "soc-nv-flash" can be used or a new binding need to be - * created, based on it. - */ - flash0: flash@400000 { - reg = <0x00400000 DT_SIZE_K(4048)>; - status = "disabled"; + c40fc: flash-controller@40268000 { + compatible = "nxp,c40-flash-controller"; + reg = <0x40268000 0x1000>; + #address-cells = <1>; + #size-cells = <1>; + + /* Map child address 0x0..size onto CPU 0x0040_0000.. */ + /* Last 48Kb is reserved by Secure BAF, app core cannot access it.*/ + ranges = <0x0 0x00400000 DT_SIZE_K(4048)>; /* 4048 KiB Flash window */ + + flash0: flash@0 { + compatible = "nxp,c40-flash"; + reg = <0x0 DT_SIZE_K(4048)>; + erase-block-size = ; /* 8 KiB sectors */ + write-block-size = <8>; /* 8-byte min program unit */ + status = "disabled"; + }; }; clock: clock-controller@402c8000 { diff --git a/dts/bindings/flash_controller/nxp,c40-flash-controller.yaml b/dts/bindings/flash_controller/nxp,c40-flash-controller.yaml new file mode 100644 index 0000000000000..eec3a82f6ba3d --- /dev/null +++ b/dts/bindings/flash_controller/nxp,c40-flash-controller.yaml @@ -0,0 +1,19 @@ +# Copyright 2025 NXP +# SPDX-License-Identifier: Apache-2.0 +title: NXP C40 Flash Controller + +description: | + Controller for the on-chip NXP C40 flash array. + +compatible: "nxp,c40-flash-controller" + +include: base.yaml + +properties: + "#address-cells": + const: 1 + description: Number of address cells for child flash nodes. + + "#size-cells": + const: 1 + description: Number of size cells for child flash nodes. diff --git a/dts/bindings/mtd/nxp,c40-flash.yaml b/dts/bindings/mtd/nxp,c40-flash.yaml new file mode 100644 index 0000000000000..3c9f9f55e4be5 --- /dev/null +++ b/dts/bindings/mtd/nxp,c40-flash.yaml @@ -0,0 +1,19 @@ +# Copyright 2025 NXP +# SPDX-License-Identifier: Apache-2.0 +title: NXP C40 Internal Flash + +description: | + On-chip C40 flash array used with NXP C40 flash controller. + +compatible: "nxp,c40-flash" + +include: soc-nv-flash.yaml + +properties: + erase-block-size: + const: 8192 + description: Minimum erase size for C40 is 8 KiB. + + write-block-size: + const: 8 + description: Smallest programmable unit is 8 bytes. From c0cd9a521207acf138a9ce5d0e159f4cd8c32814 Mon Sep 17 00:00:00 2001 From: Sumit Batra Date: Wed, 19 Nov 2025 21:18:26 +0530 Subject: [PATCH 4/6] soc: nxp s32k3: derive sys clock from devicetree Use devicetree to provide the system clock frequency for S32K3 instead of hardcoding it in board defconfigs. - Add clock-frequency to /cpus/cpu@0 in nxp_s32k344_m7.dtsi using DT_FREQ_M(160). - Define DT_SYSCLK_PATH and derive SYS_CLOCK_HW_CYCLES_PER_SEC from the sysclk node via dt_node_int_prop_int() when CORTEX_M_SYSTICK. - Remove CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC from mr_canhubk3 This keeps the clock configuration in a single SoC-level place, aligns S32K3 with other NXP Cortex-M SoCs, and ensures both the MCUboot and application builds share the same SYS_CLOCK_HW_CYCLES_PER_SEC. Signed-off-by: Sumit Batra --- boards/nxp/mr_canhubk3/mr_canhubk3_defconfig | 3 --- dts/arm/nxp/nxp_s32k344_m7.dtsi | 1 + soc/nxp/s32/s32k3/Kconfig.defconfig | 4 ++-- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/boards/nxp/mr_canhubk3/mr_canhubk3_defconfig b/boards/nxp/mr_canhubk3/mr_canhubk3_defconfig index 42dd17cc51621..d86e1b6d8480f 100644 --- a/boards/nxp/mr_canhubk3/mr_canhubk3_defconfig +++ b/boards/nxp/mr_canhubk3/mr_canhubk3_defconfig @@ -3,9 +3,6 @@ CONFIG_BUILD_OUTPUT_HEX=y -# Use Systick as system clock -CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=160000000 - # Run from internal Flash CONFIG_XIP=y diff --git a/dts/arm/nxp/nxp_s32k344_m7.dtsi b/dts/arm/nxp/nxp_s32k344_m7.dtsi index 1b120f37d5a4f..edc0b953b276b 100644 --- a/dts/arm/nxp/nxp_s32k344_m7.dtsi +++ b/dts/arm/nxp/nxp_s32k344_m7.dtsi @@ -20,6 +20,7 @@ device_type = "cpu"; compatible = "arm,cortex-m7"; reg = <0>; + clock-frequency = ; }; cpu@1 { diff --git a/soc/nxp/s32/s32k3/Kconfig.defconfig b/soc/nxp/s32/s32k3/Kconfig.defconfig index 768a3b16c7f53..ba037d79d8452 100644 --- a/soc/nxp/s32/s32k3/Kconfig.defconfig +++ b/soc/nxp/s32/s32k3/Kconfig.defconfig @@ -1,12 +1,12 @@ # NXP S32K3XX MCU series -# Copyright 2023-2024 NXP +# Copyright 2023-2025 NXP # SPDX-License-Identifier: Apache-2.0 if SOC_SERIES_S32K3 config SYS_CLOCK_HW_CYCLES_PER_SEC - default 2000000 + default $(dt_node_int_prop_int,/cpus/cpu@0,clock-frequency) if CORTEX_M_SYSTICK config NUM_IRQS # must be >= the highest interrupt number used From aa720b087c5e992c3347f434120a082922c729f0 Mon Sep 17 00:00:00 2001 From: Sumit Batra Date: Wed, 19 Nov 2025 21:21:26 +0530 Subject: [PATCH 5/6] soc: nxp: s32k3: gate IVT emission when chain-loaded by MCUboot Emit the IVT section and IVT header only when XIP and the image is either a standalone XIP app or MCUboot itself. Do not emit the IVT when the Zephyr image is chain-loaded by MCUboot (BOOTLOADER_MCUBOOT=y). - linker.ld/sections.ld: place .ivt_header at IVT_HEADER only under XIP && (!BOOTLOADER_MCUBOOT || MCUBOOT). Provide __ivt_region_start/end symbols. - soc.c: guard IVT struct under the same condition and mark it 'used' so the linker keeps it when needed. - Kconfig.defconfig - Make the bootloader and the sign tool compatible with the vector table. This avoids populating 0x400000 IVT from the app image while retaining it for MCUboot or standalone XIP use-cases. Files: - soc/nxp/s32/s32k3/linker.ld - soc/nxp/s32/s32k3/sections.ld - soc/nxp/s32/s32k3/soc.c - soc/nxp/s32/s32k3/Kconfig.defconfig Signed-off-by: Sumit Batra --- soc/nxp/s32/s32k3/Kconfig.defconfig | 5 +++++ soc/nxp/s32/s32k3/linker.ld | 12 ++++++++++-- soc/nxp/s32/s32k3/sections.ld | 10 +++++++--- soc/nxp/s32/s32k3/soc.c | 10 +++++++++- 4 files changed, 31 insertions(+), 6 deletions(-) diff --git a/soc/nxp/s32/s32k3/Kconfig.defconfig b/soc/nxp/s32/s32k3/Kconfig.defconfig index ba037d79d8452..c5bdbc3eda8bc 100644 --- a/soc/nxp/s32/s32k3/Kconfig.defconfig +++ b/soc/nxp/s32/s32k3/Kconfig.defconfig @@ -28,4 +28,9 @@ endif # ETH_DRIVER && NET_L2_ETHERNET config CACHE_MANAGEMENT default y +# S32K3 places the vector table at +0x400 +# This makes the bootloader and the sign tool compatible with that. +config ROM_START_OFFSET + default 0x400 if BOOTLOADER_MCUBOOT + endif # SOC_SERIES_S32K3 diff --git a/soc/nxp/s32/s32k3/linker.ld b/soc/nxp/s32/s32k3/linker.ld index 8681f1cd3f380..e821362e43347 100644 --- a/soc/nxp/s32/s32k3/linker.ld +++ b/soc/nxp/s32/s32k3/linker.ld @@ -4,12 +4,20 @@ * SPDX-License-Identifier: Apache-2.0 */ -#ifdef CONFIG_XIP +/* Emit IVT section only when XIP and (standalone app OR MCUboot itself) */ +#if defined(CONFIG_XIP) && (!defined(CONFIG_BOOTLOADER_MCUBOOT) || defined(CONFIG_MCUBOOT)) + MEMORY { - IVT_HEADER (r) : ORIGIN = CONFIG_FLASH_BASE_ADDRESS + CONFIG_IVT_HEADER_OFFSET, + IVT_HEADER (r) : ORIGIN = (CONFIG_FLASH_BASE_ADDRESS + CONFIG_IVT_HEADER_OFFSET), LENGTH = CONFIG_IVT_HEADER_SIZE } + +/* Symbols for IVT */ +PROVIDE(__ivt_region_start = ORIGIN(IVT_HEADER)); +PROVIDE(__ivt_region_end = ORIGIN(IVT_HEADER) + LENGTH(IVT_HEADER)); + #endif +/* Include standard Zephyr ARM script */ #include diff --git a/soc/nxp/s32/s32k3/sections.ld b/soc/nxp/s32/s32k3/sections.ld index ed9634431a522..ace72c10c2f99 100644 --- a/soc/nxp/s32/s32k3/sections.ld +++ b/soc/nxp/s32/s32k3/sections.ld @@ -4,10 +4,14 @@ * SPDX-License-Identifier: Apache-2.0 */ -#ifdef CONFIG_XIP +/* Emit IVT section only when XIP and (standalone app OR MCUboot itself) */ +#if defined(CONFIG_XIP) && (!defined(CONFIG_BOOTLOADER_MCUBOOT) || defined(CONFIG_MCUBOOT)) -.ivt_header : { - KEEP(*(.ivt_header)); +/* IVT at flash base */ +.ivt_header ORIGIN(IVT_HEADER) : ALIGN(4) +{ + /* Using a wildcard makes it more robust */ + KEEP(*(.ivt_header*)); } > IVT_HEADER #else diff --git a/soc/nxp/s32/s32k3/soc.c b/soc/nxp/s32/s32k3/soc.c index e2ecba3c6fbfd..c4ed93677d404 100644 --- a/soc/nxp/s32/s32k3/soc.c +++ b/soc/nxp/s32/s32k3/soc.c @@ -13,6 +13,11 @@ #include #ifdef CONFIG_XIP +/* + * Emit IVT only for standalone XIP or MCUboot itself + * But not for the cases where Zephyr Image is loaded by MCUboot + */ +#if !defined(CONFIG_BOOTLOADER_MCUBOOT) || defined(CONFIG_MCUBOOT) /* Image Vector Table structure definition for S32K3XX */ struct ivt { uint32_t header; @@ -33,13 +38,15 @@ struct ivt { extern char _vector_start[]; /* + * Attribute 'used' forces the compiler to emit ivt_header + * even if nothing references it. * IVT for SoC S32K344, the minimal boot configuration is: * - Watchdog (SWT0) is disabled (default value). * - Non-Secure Boot is used (default value). * - Ungate clock for Cortex-M7_0 after boot. * - Application start address of Cortex-M7_0 is application's vector table. */ -const struct ivt ivt_header __attribute__((section(".ivt_header"))) = { +const struct ivt ivt_header __attribute__((section(".ivt_header"), used)) = { .header = IVT_MAGIC_MARKER, .boot_configure = 1, .cm7_0_start_address = (const void *)_vector_start, @@ -47,6 +54,7 @@ const struct ivt ivt_header __attribute__((section(".ivt_header"))) = { .cm7_2_start_address = NULL, .lc_configure = NULL, }; +#endif #endif /* CONFIG_XIP */ void soc_early_init_hook(void) From 52e46f97af3906742def1f2f718dae38300bf824 Mon Sep 17 00:00:00 2001 From: Sumit Batra Date: Wed, 19 Nov 2025 21:24:35 +0530 Subject: [PATCH 6/6] boards: nxp: mr_canhubk3: add mcuboot variant and document sysbuild MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add an mcuboot board variant under the S32K344 SoC in board.yml. New target is - mr_canhubk3/s32k344/mcuboot. This enables a single sysbuild invocation to build MCUboot and the application. Also make a common dtsi for all mr_canhubk3 board variants. Extend the board documentation with an “MCUboot (sysbuild)” section that: Shows one-command sysbuild to produce both MCUboot and app Documents signing via sysbuild (SB_CONFIG_BOOT_SIGNATURE_*), and where the signed artifacts are generated. Provides simple flashing instructions and a troubleshooting note about using a 1 KiB (0x400) image header and not emitting an IVT for chain-loaded apps. Signed-off-by: Sumit Batra --- boards/nxp/mr_canhubk3/Kconfig.sysbuild | 20 + boards/nxp/mr_canhubk3/board.yml | 2 + boards/nxp/mr_canhubk3/doc/index.rst | 31 + boards/nxp/mr_canhubk3/mr_canhubk3.dts | 614 +---------------- .../nxp/mr_canhubk3/mr_canhubk3_common.dtsi | 619 ++++++++++++++++++ .../mr_canhubk3_s32k344_mcuboot.dts | 61 ++ .../mr_canhubk3_s32k344_mcuboot.yaml | 27 + .../mr_canhubk3_s32k344_mcuboot_defconfig | 17 + 8 files changed, 784 insertions(+), 607 deletions(-) create mode 100644 boards/nxp/mr_canhubk3/Kconfig.sysbuild create mode 100644 boards/nxp/mr_canhubk3/mr_canhubk3_common.dtsi create mode 100644 boards/nxp/mr_canhubk3/mr_canhubk3_s32k344_mcuboot.dts create mode 100644 boards/nxp/mr_canhubk3/mr_canhubk3_s32k344_mcuboot.yaml create mode 100644 boards/nxp/mr_canhubk3/mr_canhubk3_s32k344_mcuboot_defconfig diff --git a/boards/nxp/mr_canhubk3/Kconfig.sysbuild b/boards/nxp/mr_canhubk3/Kconfig.sysbuild new file mode 100644 index 0000000000000..f25fedd92beaf --- /dev/null +++ b/boards/nxp/mr_canhubk3/Kconfig.sysbuild @@ -0,0 +1,20 @@ +# Copyright 2025 NXP +# SPDX-License-Identifier: Apache-2.0 + + +if BOARD_MR_CANHUBK3_S32K344_MCUBOOT + +choice BOOTLOADER + default BOOTLOADER_MCUBOOT +endchoice + +# Use direct-XIP mode (dual-slot) on S32K3 +choice MCUBOOT_MODE + default MCUBOOT_MODE_DIRECT_XIP +endchoice + +choice BOOT_SIGNATURE_TYPE + default BOOT_SIGNATURE_TYPE_RSA +endchoice + +endif # BOARD_MR_CANHUBK3_S32K344_MCUBOOT diff --git a/boards/nxp/mr_canhubk3/board.yml b/boards/nxp/mr_canhubk3/board.yml index fcf396d2c45e6..43aaaf2bc4691 100644 --- a/boards/nxp/mr_canhubk3/board.yml +++ b/boards/nxp/mr_canhubk3/board.yml @@ -4,3 +4,5 @@ board: vendor: nxp socs: - name: s32k344 + variants: + - name: mcuboot diff --git a/boards/nxp/mr_canhubk3/doc/index.rst b/boards/nxp/mr_canhubk3/doc/index.rst index 905eba1d1d383..570a2157c6308 100644 --- a/boards/nxp/mr_canhubk3/doc/index.rst +++ b/boards/nxp/mr_canhubk3/doc/index.rst @@ -296,6 +296,37 @@ For example, to erase and verify flash content: west flash -r trace32 --startup-args elfFile=build/zephyr/zephyr.elf loadTo=flash eraseFlash=yes verifyFlash=yes +MCUboot +======= + +This board supports app chain-loading using MCUboot. + +Build & Flash +------------- + +To build MCUboot and the ``flash_shell`` sample application together and +generate HEX files suitable for flashing, run: + +.. code-block:: console + + west build -p -b mr_canhubk3/s32k344/mcuboot samples/drivers/flash_shell --sysbuild + west flash + +The resulting artifacts are: + +* MCUboot: ``build/mcuboot/zephyr/zephyr.hex`` +* App (unsigned): ``build/flash_shell/zephyr/zephyr.hex`` + +Troubleshooting +--------------- + + If MCUboot prints “Image in the primary slot is not valid” or stalls after + “Jumping to the first image slot”, the app was likely signed with a 512-byte header. + Re-sign with --header-size 0x400 and re-flash. + + Do not add an IVT to MCUboot-chainloaded applications; + it’s only emitted for standalone/XIP images or MCUboot itself. + Debugging ========= diff --git a/boards/nxp/mr_canhubk3/mr_canhubk3.dts b/boards/nxp/mr_canhubk3/mr_canhubk3.dts index 19ca4fb0aa9ae..35e06fc89bc6d 100644 --- a/boards/nxp/mr_canhubk3/mr_canhubk3.dts +++ b/boards/nxp/mr_canhubk3/mr_canhubk3.dts @@ -1,221 +1,26 @@ /* - * Copyright 2023-2024 NXP + * Copyright 2023-2025 NXP * * SPDX-License-Identifier: Apache-2.0 */ /dts-v1/; -#include -#include -#include -#include -#include -#include "mr_canhubk3-pinctrl.dtsi" -#include +#include "mr_canhubk3_common.dtsi" / { - model = "NXP MR-CANHUBK3"; - compatible = "nxp,mr_canhubk3"; - chosen { - zephyr,sram = &sram0_1; - zephyr,flash = &flash0; - zephyr,itcm = &itcm; - zephyr,dtcm = &dtcm; zephyr,code-partition = &code_partition; - zephyr,console = &lpuart2; - zephyr,shell-uart = &lpuart2; - zephyr,flash-controller = &mx25l6433f; - zephyr,canbus = &flexcan0; - zephyr,display = &ssd1306; - }; - - aliases { - dma0 = &edma0; - led0 = &user_led1_red; - led1 = &user_led1_green; - led2 = &user_led1_blue; - sw0 = &user_button_1; - sw1 = &user_button_2; - watchdog0 = &swt0; - /* For pwm test suites */ - pwm-0 = &emios0_pwm; - pwm-1 = &flexio0_pwm; - red-pwm-led = &user_led1_red_pwm; - green-pwm-led = &user_led1_green_pwm; - blue-pwm-led = &user_led1_blue_pwm; - pwm-led0 = &user_led1_blue_pwm; - qdec0 = &qdec0; - }; - - leds { - compatible = "gpio-leds"; - - user_led1_green: user_led1_green { - gpios = <&gpioa_h 11 GPIO_ACTIVE_LOW>; - label = "User RGB LED1 GREEN"; - }; - - user_led1_blue: user_led1_blue { - gpios = <&gpioe_l 12 GPIO_ACTIVE_LOW>; - label = "User RGB LED1 BLUE"; - }; - - user_led1_red: user_led1_red { - gpios = <&gpioe_l 14 GPIO_ACTIVE_LOW>; - label = "User RGB LED1 RED"; - }; - - can_led0: can_led0 { - gpios = <&gpioc_h 2 GPIO_ACTIVE_LOW>; - label = "CAN LED0"; - }; - - can_led1: can_led1 { - gpios = <&gpioe_l 5 GPIO_ACTIVE_LOW>; - label = "CAN LED1"; - }; - - can_led2: can_led2 { - gpios = <&gpiod_h 4 GPIO_ACTIVE_LOW>; - label = "CAN LED2"; - }; - - can_led3: can_led3 { - gpios = <&gpiob_h 8 GPIO_ACTIVE_LOW>; - label = "CAN LED3"; - }; - - can_led4: can_led4 { - gpios = <&gpiob_h 10 GPIO_ACTIVE_LOW>; - label = "CAN LED4"; - }; - - can_led5: can_led5 { - gpios = <&gpiod_h 15 GPIO_ACTIVE_LOW>; - label = "CAN LED5"; - }; - }; - - /* gpio-leds and pwm-leds are the same RGB LED and cannot be used at the same time. */ - pwmleds { - compatible = "pwm-leds"; - - user_led1_blue_pwm: user_led1_blue { - pwms = <&emios1_pwm 5 PWM_MSEC(20) PWM_POLARITY_INVERTED>; - }; - - user_led1_green_pwm: user_led1_green { - pwms = <&emios1_pwm 10 PWM_MSEC(20) PWM_POLARITY_INVERTED>; - }; - - user_led1_red_pwm: user_led1_red { - pwms = <&emios0_pwm 19 PWM_MSEC(20) PWM_POLARITY_INVERTED>; - }; - }; - - qdec0: qdec0 { - compatible = "nxp,qdec-s32"; - pinctrl-0 = <&qdec_s32>; - pinctrl-names = "default"; - micro-ticks-per-rev = <685440000>; - status = "okay"; - trgmux = <&trgmux>; - trgmux-io-config = <0 TRGMUX_IP_OUTPUT_EMIOS0_CH5_9_IPP_IND_CH6 - TRGMUX_IP_INPUT_LCU1_LC0_OUT_I2>, - <1 TRGMUX_IP_OUTPUT_EMIOS0_CH5_9_IPP_IND_CH7 - TRGMUX_IP_INPUT_LCU1_LC0_OUT_I3>, - <2 TRGMUX_IP_OUTPUT_LCU1_0_INP_I0 TRGMUX_IP_INPUT_SIUL2_IN2>, - <3 TRGMUX_IP_OUTPUT_LCU1_0_INP_I1 TRGMUX_IP_INPUT_SIUL2_IN3>; - lcu = <&lcu1>; - lcu-input-idx = ; - lcu-mux-sel = ; - lcu-output-filter-config = - /* LCU Out HW ID, Rise Filter, Fall Filter */ - <0 5 5>, /* LCU O0 */ - <1 5 5>, /* LCU O1 */ - <2 2 2>, /* LCU O2 */ - <3 2 2>; /* LCU O3 */ - emios = <&emios0>; - /* - * eMios channel numbers for qdec should be beyond the channel numbers - * used by the emios pwm - */ - emios-channels = <6 7>; - }; - - gpio_keys { - compatible = "gpio-keys"; - - user_button_1: button_0 { - label = "User SW1"; - gpios = <&gpiod_l 15 GPIO_ACTIVE_HIGH>; - zephyr,code = ; - }; - - user_button_2: button_1 { - label = "User SW2"; - gpios = <&gpioa_h 9 GPIO_ACTIVE_HIGH>; - zephyr,code = ; - }; - }; - - can_phy0: can-phy0 { - compatible = "nxp,tja1443", "can-transceiver-gpio"; - enable-gpios = <&gpioc_h 8 GPIO_ACTIVE_HIGH>; - standby-gpios = <&gpioc_h 5 GPIO_ACTIVE_LOW>; - max-bitrate = <5000000>; - #phy-cells = <0>; - }; - - can_phy1: can-phy1 { - compatible = "nxp,tja1443", "can-transceiver-gpio"; - enable-gpios = <&gpiod_l 2 GPIO_ACTIVE_HIGH>; - standby-gpios = <&gpiod_h 7 GPIO_ACTIVE_LOW>; - max-bitrate = <5000000>; - #phy-cells = <0>; - }; - - can_phy2: can-phy2 { - compatible = "nxp,tja1463", "can-transceiver-gpio"; - enable-gpios = <&gpiod_l 4 GPIO_ACTIVE_HIGH>; - standby-gpios = <&gpiod_h 6 GPIO_ACTIVE_LOW>; - max-bitrate = <8000000>; - #phy-cells = <0>; - }; - - can_phy3: can-phy3 { - compatible = "nxp,tja1463", "can-transceiver-gpio"; - enable-gpios = <&gpiob_l 0 GPIO_ACTIVE_HIGH>; - standby-gpios = <&gpiob_l 1 GPIO_ACTIVE_LOW>; - max-bitrate = <8000000>; - #phy-cells = <0>; - }; - - can_phy4: can-phy4 { - compatible = "nxp,tja1153", "can-transceiver-gpio"; - enable-gpios = <&gpioc_h 10 GPIO_ACTIVE_HIGH>; - standby-gpios = <&gpioc_h 9 GPIO_ACTIVE_LOW>; - max-bitrate = <2000000>; - #phy-cells = <0>; - }; - - can_phy5: can-phy5 { - compatible = "nxp,tja1153", "can-transceiver-gpio"; - enable-gpios = <&gpioe_h 1 GPIO_ACTIVE_HIGH>; - standby-gpios = <&gpiod_h 14 GPIO_ACTIVE_LOW>; - max-bitrate = <2000000>; - #phy-cells = <0>; + zephyr,flash = &flash0; }; }; -&pmc { - lm-reg; +&c40fc { + status = "okay"; }; &flash0 { + status = "okay"; + partitions { compatible = "fixed-partitions"; #address-cells = <1>; @@ -232,408 +37,3 @@ }; }; }; - -&gpioa_h { - status = "okay"; -}; - -&gpioe_l { - status = "okay"; -}; - -/* Enable gpio to control the CAN transceivers and LEDs */ - -&gpiob_h { - status = "okay"; -}; - -&gpioc_h { - status = "okay"; -}; - -&gpiod_l { - status = "okay"; -}; - -&gpiod_h { - status = "okay"; -}; - -&gpiob_l { - status = "okay"; -}; - -&gpioe_h { - status = "okay"; -}; - -&eirq0 { - pinctrl-0 = <&eirq0_default>; - pinctrl-names = "default"; - status = "okay"; -}; - -&lpuart0 { - pinctrl-0 = <&lpuart0_default>; - pinctrl-names = "default"; - dmas = <&edma0 0 37>, <&edma0 1 38>; - dma-names = "tx", "rx"; -}; - -&lpuart1 { - pinctrl-0 = <&lpuart1_default>; - pinctrl-names = "default"; - dmas = <&edma0 2 39>, <&edma0 3 40>; - dma-names = "tx", "rx"; -}; - -&lpuart2 { - pinctrl-0 = <&lpuart2_default>; - pinctrl-names = "default"; - current-speed = <115200>; - dmas = <&edma0 16 38>, <&edma0 17 39>; - dma-names = "tx", "rx"; - status = "okay"; -}; - -&lpuart9 { - pinctrl-0 = <&lpuart9_default>; - pinctrl-names = "default"; - /* - * LPUART 1 and 9 share the same DMA source for TX - * and RX, using UART async API for both instances - * should be careful. - */ - dmas = <&edma0 4 39>, <&edma0 5 40>; - dma-names = "tx", "rx"; -}; - -&lpuart10 { - pinctrl-0 = <&lpuart10_default>; - pinctrl-names = "default"; - /* - * LPUART 2 and 10 share the same DMA source for TX - * and RX, using UART async API for both instances - * should be careful. - */ - dmas = <&edma0 18 38>, <&edma0 19 39>; - dma-names = "tx", "rx"; -}; - -&lpuart13 { - pinctrl-0 = <&lpuart13_default>; - pinctrl-names = "default"; - dmas = <&edma0 20 44>, <&edma0 21 45>; - dma-names = "tx", "rx"; -}; - -&lpuart14 { - pinctrl-0 = <&lpuart14_default>; - pinctrl-names = "default"; - dmas = <&edma0 22 46>, <&edma0 23 47>; - dma-names = "tx", "rx"; -}; - -&qspi0 { - pinctrl-0 = <&qspi0_default>; - pinctrl-names = "default"; - data-rate = "SDR"; - a-rx-clock-source = "LOOPBACK"; - a-dll-mode = "BYPASSED"; - ahb-buffers-masters = <0 1 2 3>; - ahb-buffers-sizes = <0 0 0 256>; - ahb-buffers-all-masters; - status = "okay"; - - mx25l6433f: mx25l6433f@0 { - compatible = "nxp,s32-qspi-nor"; - reg = <0>; - size = ; - jedec-id = [c2 20 17]; - quad-enable-requirements = "S1B6"; - readoc = "1-4-4"; - writeoc = "1-4-4"; - has-32k-erase; - max-program-buffer-size = <256>; - write-block-size = <1>; - status = "okay"; - - partitions { - compatible = "fixed-partitions"; - #address-cells = <1>; - #size-cells = <1>; - - storage_partition: partition@0 { - label = "storage"; - reg = <0x0 0x100000>; - }; - }; - }; -}; - -&flexcan0 { - pinctrl-0 = <&flexcan0_default>; - pinctrl-names = "default"; - phys = <&can_phy0>; - status = "okay"; -}; - -&flexcan1 { - pinctrl-0 = <&flexcan1_default>; - pinctrl-names = "default"; - phys = <&can_phy1>; -}; - -&flexcan2 { - pinctrl-0 = <&flexcan2_default>; - pinctrl-names = "default"; - phys = <&can_phy2>; -}; - -&flexcan3 { - pinctrl-0 = <&flexcan3_default>; - pinctrl-names = "default"; - phys = <&can_phy3>; -}; - -&flexcan4 { - pinctrl-0 = <&flexcan4_default>; - pinctrl-names = "default"; - phys = <&can_phy4>; -}; - -&flexcan5 { - pinctrl-0 = <&flexcan5_default>; - pinctrl-names = "default"; - phys = <&can_phy5>; -}; - -&lpi2c0 { - pinctrl-0 = <&lpi2c0_default>; - pinctrl-names = "default"; - clock-frequency = ; - status = "okay"; - - ssd1306: ssd1306@3c { - compatible = "solomon,ssd1306fb"; - reg = <0x3c>; - width = <128>; - height = <32>; - segment-offset = <0>; - page-offset = <0>; - display-offset = <0>; - multiplex-ratio = <31>; - segment-remap; - com-invdir; - com-sequential; - prechargep = <0x22>; - }; -}; - -&lpi2c1 { - pinctrl-0 = <&lpi2c1_default>; - pinctrl-names = "default"; - clock-frequency = ; -}; - -&lpspi1 { - pinctrl-0 = <&lpspi1_default>; - pinctrl-names = "default"; - data-pin-config = "sdo-in,sdi-out"; -}; - -&lpspi2 { - pinctrl-0 = <&lpspi2_default>; - pinctrl-names = "default"; - data-pin-config = "sdo-in,sdi-out"; -}; - -&lpspi3 { - pinctrl-0 = <&lpspi3_default>; - pinctrl-names = "default"; - data-pin-config = "sdo-in,sdi-out"; - status = "okay"; - - fs26_wdt: watchdog@0 { - compatible = "nxp,fs26-wdog"; - reg = <0>; - spi-max-frequency = ; - type = "challenger"; - int-gpios = <&gpioa_h 2 GPIO_ACTIVE_LOW>; - status = "okay"; - }; -}; - -&lpspi4 { - pinctrl-0 = <&lpspi4_default>; - pinctrl-names = "default"; - data-pin-config = "sdo-in,sdi-out"; -}; - -&lpspi5 { - pinctrl-0 = <&lpspi5_default>; - pinctrl-names = "default"; - data-pin-config = "sdo-in,sdi-out"; -}; - -&emac0 { - pinctrl-0 = <&emac0_default>; - pinctrl-names = "default"; - phy-connection-type = "rmii"; - local-mac-address = [02 04 9f aa bb cc]; - phy-handle = <&phy>; - status = "okay"; -}; - -&mdio0 { - pinctrl-0 = <&mdio0_default>; - pinctrl-names = "default"; - status = "okay"; - - phy: ethernet-phy@12 { - compatible = "nxp,tja1103"; - status = "okay"; - reg = <0x12>; - int-gpios = <&gpiod_l 5 GPIO_ACTIVE_LOW>; - master-slave = "slave"; - }; -}; - -&emios0 { - clock-divider = <200>; - status = "okay"; - - master_bus { - /* - * Timebase for PWM led, setting clock 50KHz for internal counter, - * default period is 1000 cycles <-> 20ms. - */ - emios0_bus_a { - mode = "MCB_UP_COUNTER"; - prescaler = <16>; - status = "okay"; - }; - }; - - emios0_pwm: pwm { - pinctrl-0 = <&emios0_default>; - pinctrl-names = "default"; - status = "okay"; - - /* Default clock for internal counter for PWM channel 0-7 is 100Khz */ - pwm_0 { - channel = <0>; - pwm-mode = "OPWFMB"; - prescaler = <8>; - }; - - pwm_1 { - channel = <1>; - pwm-mode = "OPWFMB"; - prescaler = <8>; - }; - - pwm_2 { - channel = <2>; - pwm-mode = "OPWFMB"; - prescaler = <8>; - }; - - pwm_3 { - channel = <3>; - pwm-mode = "OPWFMB"; - prescaler = <8>; - }; - - pwm_4 { - channel = <4>; - pwm-mode = "OPWFMB"; - prescaler = <8>; - }; - - pwm_5 { - channel = <5>; - pwm-mode = "OPWFMB"; - prescaler = <8>; - }; - - rgb_red { - channel = <19>; - master-bus = <&emios0_bus_a>; - pwm-mode = "OPWMB"; - }; - }; -}; - -&emios1 { - clock-divider = <200>; - status = "okay"; - - master_bus { - /* - * Timebase for PWM led, setting clock 50KHz for internal counter, - * default period is 1000 cycles <-> 20ms. - */ - emios1_bus_a { - prescaler = <16>; - mode = "MCB_UP_COUNTER"; - status = "okay"; - }; - - emios1_bus_f { - prescaler = <16>; - mode = "MCB_UP_COUNTER"; - status = "okay"; - }; - }; - - emios1_pwm: pwm { - pinctrl-0 = <&emios1_default>; - pinctrl-names = "default"; - status = "okay"; - - rgb_green { - channel = <10>; - master-bus = <&emios1_bus_a>; - pwm-mode = "OPWMB"; - }; - - rgb_blue { - channel = <5>; - master-bus = <&emios1_bus_f>; - pwm-mode = "OPWMB"; - }; - }; -}; - -&flexio0 { - status = "okay"; - - flexio0_pwm: flexio0_pwm { - pinctrl-0 = <&flexio0_pwm_default>; - pinctrl-names = "default"; - status = "okay"; - - pwm_0 { - pin-id = <19>; - prescaler = <1>; - }; - - pwm_1 { - pin-id = <11>; - prescaler = <1>; - }; - }; -}; - -&lcu1 { - status = "okay"; -}; - -&trgmux { - status = "okay"; -}; - -&edma0 { - status = "okay"; -}; diff --git a/boards/nxp/mr_canhubk3/mr_canhubk3_common.dtsi b/boards/nxp/mr_canhubk3/mr_canhubk3_common.dtsi new file mode 100644 index 0000000000000..36a23e5b49b37 --- /dev/null +++ b/boards/nxp/mr_canhubk3/mr_canhubk3_common.dtsi @@ -0,0 +1,619 @@ +/* + * Copyright 2025 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include "mr_canhubk3-pinctrl.dtsi" +#include + +/ { + model = "NXP MR-CANHUBK3"; + compatible = "nxp,mr_canhubk3"; + + chosen { + zephyr,sram = &sram0_1; + zephyr,flash = &flash0; + zephyr,itcm = &itcm; + zephyr,dtcm = &dtcm; + zephyr,console = &lpuart2; + zephyr,shell-uart = &lpuart2; + zephyr,flash-controller = &c40fc; + zephyr,canbus = &flexcan0; + zephyr,display = &ssd1306; + }; + + aliases { + dma0 = &edma0; + led0 = &user_led1_red; + led1 = &user_led1_green; + led2 = &user_led1_blue; + sw0 = &user_button_1; + sw1 = &user_button_2; + watchdog0 = &swt0; + /* For pwm test suites */ + pwm-0 = &emios0_pwm; + pwm-1 = &flexio0_pwm; + red-pwm-led = &user_led1_red_pwm; + green-pwm-led = &user_led1_green_pwm; + blue-pwm-led = &user_led1_blue_pwm; + pwm-led0 = &user_led1_blue_pwm; + qdec0 = &qdec0; + }; + + leds { + compatible = "gpio-leds"; + + user_led1_green: user_led1_green { + gpios = <&gpioa_h 11 GPIO_ACTIVE_LOW>; + label = "User RGB LED1 GREEN"; + }; + + user_led1_blue: user_led1_blue { + gpios = <&gpioe_l 12 GPIO_ACTIVE_LOW>; + label = "User RGB LED1 BLUE"; + }; + + user_led1_red: user_led1_red { + gpios = <&gpioe_l 14 GPIO_ACTIVE_LOW>; + label = "User RGB LED1 RED"; + }; + + can_led0: can_led0 { + gpios = <&gpioc_h 2 GPIO_ACTIVE_LOW>; + label = "CAN LED0"; + }; + + can_led1: can_led1 { + gpios = <&gpioe_l 5 GPIO_ACTIVE_LOW>; + label = "CAN LED1"; + }; + + can_led2: can_led2 { + gpios = <&gpiod_h 4 GPIO_ACTIVE_LOW>; + label = "CAN LED2"; + }; + + can_led3: can_led3 { + gpios = <&gpiob_h 8 GPIO_ACTIVE_LOW>; + label = "CAN LED3"; + }; + + can_led4: can_led4 { + gpios = <&gpiob_h 10 GPIO_ACTIVE_LOW>; + label = "CAN LED4"; + }; + + can_led5: can_led5 { + gpios = <&gpiod_h 15 GPIO_ACTIVE_LOW>; + label = "CAN LED5"; + }; + }; + + /* gpio-leds and pwm-leds are the same RGB LED and cannot be used at the same time. */ + pwmleds { + compatible = "pwm-leds"; + + user_led1_blue_pwm: user_led1_blue { + pwms = <&emios1_pwm 5 PWM_MSEC(20) PWM_POLARITY_INVERTED>; + }; + + user_led1_green_pwm: user_led1_green { + pwms = <&emios1_pwm 10 PWM_MSEC(20) PWM_POLARITY_INVERTED>; + }; + + user_led1_red_pwm: user_led1_red { + pwms = <&emios0_pwm 19 PWM_MSEC(20) PWM_POLARITY_INVERTED>; + }; + }; + + qdec0: qdec0 { + compatible = "nxp,qdec-s32"; + pinctrl-0 = <&qdec_s32>; + pinctrl-names = "default"; + micro-ticks-per-rev = <685440000>; + status = "okay"; + trgmux = <&trgmux>; + trgmux-io-config = <0 TRGMUX_IP_OUTPUT_EMIOS0_CH5_9_IPP_IND_CH6 + TRGMUX_IP_INPUT_LCU1_LC0_OUT_I2>, + <1 TRGMUX_IP_OUTPUT_EMIOS0_CH5_9_IPP_IND_CH7 + TRGMUX_IP_INPUT_LCU1_LC0_OUT_I3>, + <2 TRGMUX_IP_OUTPUT_LCU1_0_INP_I0 TRGMUX_IP_INPUT_SIUL2_IN2>, + <3 TRGMUX_IP_OUTPUT_LCU1_0_INP_I1 TRGMUX_IP_INPUT_SIUL2_IN3>; + lcu = <&lcu1>; + lcu-input-idx = ; + lcu-mux-sel = ; + lcu-output-filter-config = + /* LCU Out HW ID, Rise Filter, Fall Filter */ + <0 5 5>, /* LCU O0 */ + <1 5 5>, /* LCU O1 */ + <2 2 2>, /* LCU O2 */ + <3 2 2>; /* LCU O3 */ + emios = <&emios0>; + /* + * eMios channel numbers for qdec should be beyond the channel numbers + * used by the emios pwm + */ + emios-channels = <6 7>; + }; + + gpio_keys { + compatible = "gpio-keys"; + + user_button_1: button_0 { + label = "User SW1"; + gpios = <&gpiod_l 15 GPIO_ACTIVE_HIGH>; + zephyr,code = ; + }; + + user_button_2: button_1 { + label = "User SW2"; + gpios = <&gpioa_h 9 GPIO_ACTIVE_HIGH>; + zephyr,code = ; + }; + }; + + can_phy0: can-phy0 { + compatible = "nxp,tja1443", "can-transceiver-gpio"; + enable-gpios = <&gpioc_h 8 GPIO_ACTIVE_HIGH>; + standby-gpios = <&gpioc_h 5 GPIO_ACTIVE_LOW>; + max-bitrate = <5000000>; + #phy-cells = <0>; + }; + + can_phy1: can-phy1 { + compatible = "nxp,tja1443", "can-transceiver-gpio"; + enable-gpios = <&gpiod_l 2 GPIO_ACTIVE_HIGH>; + standby-gpios = <&gpiod_h 7 GPIO_ACTIVE_LOW>; + max-bitrate = <5000000>; + #phy-cells = <0>; + }; + + can_phy2: can-phy2 { + compatible = "nxp,tja1463", "can-transceiver-gpio"; + enable-gpios = <&gpiod_l 4 GPIO_ACTIVE_HIGH>; + standby-gpios = <&gpiod_h 6 GPIO_ACTIVE_LOW>; + max-bitrate = <8000000>; + #phy-cells = <0>; + }; + + can_phy3: can-phy3 { + compatible = "nxp,tja1463", "can-transceiver-gpio"; + enable-gpios = <&gpiob_l 0 GPIO_ACTIVE_HIGH>; + standby-gpios = <&gpiob_l 1 GPIO_ACTIVE_LOW>; + max-bitrate = <8000000>; + #phy-cells = <0>; + }; + + can_phy4: can-phy4 { + compatible = "nxp,tja1153", "can-transceiver-gpio"; + enable-gpios = <&gpioc_h 10 GPIO_ACTIVE_HIGH>; + standby-gpios = <&gpioc_h 9 GPIO_ACTIVE_LOW>; + max-bitrate = <2000000>; + #phy-cells = <0>; + }; + + can_phy5: can-phy5 { + compatible = "nxp,tja1153", "can-transceiver-gpio"; + enable-gpios = <&gpioe_h 1 GPIO_ACTIVE_HIGH>; + standby-gpios = <&gpiod_h 14 GPIO_ACTIVE_LOW>; + max-bitrate = <2000000>; + #phy-cells = <0>; + }; +}; + +&pmc { + lm-reg; +}; + +&gpioa_h { + status = "okay"; +}; + +&gpioe_l { + status = "okay"; +}; + +/* Enable gpio to control the CAN transceivers and LEDs */ + +&gpiob_h { + status = "okay"; +}; + +&gpioc_h { + status = "okay"; +}; + +&gpiod_l { + status = "okay"; +}; + +&gpiod_h { + status = "okay"; +}; + +&gpiob_l { + status = "okay"; +}; + +&gpioe_h { + status = "okay"; +}; + +&eirq0 { + pinctrl-0 = <&eirq0_default>; + pinctrl-names = "default"; + status = "okay"; +}; + +&lpuart0 { + pinctrl-0 = <&lpuart0_default>; + pinctrl-names = "default"; + dmas = <&edma0 0 37>, <&edma0 1 38>; + dma-names = "tx", "rx"; +}; + +&lpuart1 { + pinctrl-0 = <&lpuart1_default>; + pinctrl-names = "default"; + dmas = <&edma0 2 39>, <&edma0 3 40>; + dma-names = "tx", "rx"; +}; + +&lpuart2 { + pinctrl-0 = <&lpuart2_default>; + pinctrl-names = "default"; + current-speed = <115200>; + dmas = <&edma0 16 38>, <&edma0 17 39>; + dma-names = "tx", "rx"; + status = "okay"; +}; + +&lpuart9 { + pinctrl-0 = <&lpuart9_default>; + pinctrl-names = "default"; + /* + * LPUART 1 and 9 share the same DMA source for TX + * and RX, using UART async API for both instances + * should be careful. + */ + dmas = <&edma0 4 39>, <&edma0 5 40>; + dma-names = "tx", "rx"; +}; + +&lpuart10 { + pinctrl-0 = <&lpuart10_default>; + pinctrl-names = "default"; + /* + * LPUART 2 and 10 share the same DMA source for TX + * and RX, using UART async API for both instances + * should be careful. + */ + dmas = <&edma0 18 38>, <&edma0 19 39>; + dma-names = "tx", "rx"; +}; + +&lpuart13 { + pinctrl-0 = <&lpuart13_default>; + pinctrl-names = "default"; + dmas = <&edma0 20 44>, <&edma0 21 45>; + dma-names = "tx", "rx"; +}; + +&lpuart14 { + pinctrl-0 = <&lpuart14_default>; + pinctrl-names = "default"; + dmas = <&edma0 22 46>, <&edma0 23 47>; + dma-names = "tx", "rx"; +}; + +&qspi0 { + pinctrl-0 = <&qspi0_default>; + pinctrl-names = "default"; + data-rate = "SDR"; + a-rx-clock-source = "LOOPBACK"; + a-dll-mode = "BYPASSED"; + ahb-buffers-masters = <0 1 2 3>; + ahb-buffers-sizes = <0 0 0 256>; + ahb-buffers-all-masters; + status = "okay"; + + mx25l6433f: mx25l6433f@0 { + compatible = "nxp,s32-qspi-nor"; + reg = <0>; + size = ; + jedec-id = [c2 20 17]; + quad-enable-requirements = "S1B6"; + readoc = "1-4-4"; + writeoc = "1-4-4"; + has-32k-erase; + max-program-buffer-size = <256>; + write-block-size = <1>; + status = "okay"; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + storage_partition: partition@0 { + label = "storage"; + reg = <0x0 0x100000>; + }; + }; + }; +}; + +&flexcan0 { + pinctrl-0 = <&flexcan0_default>; + pinctrl-names = "default"; + phys = <&can_phy0>; + status = "okay"; +}; + +&flexcan1 { + pinctrl-0 = <&flexcan1_default>; + pinctrl-names = "default"; + phys = <&can_phy1>; +}; + +&flexcan2 { + pinctrl-0 = <&flexcan2_default>; + pinctrl-names = "default"; + phys = <&can_phy2>; +}; + +&flexcan3 { + pinctrl-0 = <&flexcan3_default>; + pinctrl-names = "default"; + phys = <&can_phy3>; +}; + +&flexcan4 { + pinctrl-0 = <&flexcan4_default>; + pinctrl-names = "default"; + phys = <&can_phy4>; +}; + +&flexcan5 { + pinctrl-0 = <&flexcan5_default>; + pinctrl-names = "default"; + phys = <&can_phy5>; +}; + +&lpi2c0 { + pinctrl-0 = <&lpi2c0_default>; + pinctrl-names = "default"; + clock-frequency = ; + status = "okay"; + + ssd1306: ssd1306@3c { + compatible = "solomon,ssd1306fb"; + reg = <0x3c>; + width = <128>; + height = <32>; + segment-offset = <0>; + page-offset = <0>; + display-offset = <0>; + multiplex-ratio = <31>; + segment-remap; + com-invdir; + com-sequential; + prechargep = <0x22>; + }; +}; + +&lpi2c1 { + pinctrl-0 = <&lpi2c1_default>; + pinctrl-names = "default"; + clock-frequency = ; +}; + +&lpspi1 { + pinctrl-0 = <&lpspi1_default>; + pinctrl-names = "default"; + data-pin-config = "sdo-in,sdi-out"; +}; + +&lpspi2 { + pinctrl-0 = <&lpspi2_default>; + pinctrl-names = "default"; + data-pin-config = "sdo-in,sdi-out"; +}; + +&lpspi3 { + pinctrl-0 = <&lpspi3_default>; + pinctrl-names = "default"; + data-pin-config = "sdo-in,sdi-out"; + status = "okay"; + + fs26_wdt: watchdog@0 { + compatible = "nxp,fs26-wdog"; + reg = <0>; + spi-max-frequency = ; + type = "challenger"; + int-gpios = <&gpioa_h 2 GPIO_ACTIVE_LOW>; + status = "okay"; + }; +}; + +&lpspi4 { + pinctrl-0 = <&lpspi4_default>; + pinctrl-names = "default"; + data-pin-config = "sdo-in,sdi-out"; +}; + +&lpspi5 { + pinctrl-0 = <&lpspi5_default>; + pinctrl-names = "default"; + data-pin-config = "sdo-in,sdi-out"; +}; + +&emac0 { + pinctrl-0 = <&emac0_default>; + pinctrl-names = "default"; + phy-connection-type = "rmii"; + local-mac-address = [02 04 9f aa bb cc]; + phy-handle = <&phy>; + status = "okay"; +}; + +&mdio0 { + pinctrl-0 = <&mdio0_default>; + pinctrl-names = "default"; + status = "okay"; + + phy: ethernet-phy@12 { + compatible = "nxp,tja1103"; + status = "okay"; + reg = <0x12>; + int-gpios = <&gpiod_l 5 GPIO_ACTIVE_LOW>; + master-slave = "slave"; + }; +}; + +&emios0 { + clock-divider = <200>; + status = "okay"; + + master_bus { + /* + * Timebase for PWM led, setting clock 50KHz for internal counter, + * default period is 1000 cycles <-> 20ms. + */ + emios0_bus_a { + mode = "MCB_UP_COUNTER"; + prescaler = <16>; + status = "okay"; + }; + }; + + emios0_pwm: pwm { + pinctrl-0 = <&emios0_default>; + pinctrl-names = "default"; + status = "okay"; + + /* Default clock for internal counter for PWM channel 0-7 is 100Khz */ + pwm_0 { + channel = <0>; + pwm-mode = "OPWFMB"; + prescaler = <8>; + }; + + pwm_1 { + channel = <1>; + pwm-mode = "OPWFMB"; + prescaler = <8>; + }; + + pwm_2 { + channel = <2>; + pwm-mode = "OPWFMB"; + prescaler = <8>; + }; + + pwm_3 { + channel = <3>; + pwm-mode = "OPWFMB"; + prescaler = <8>; + }; + + pwm_4 { + channel = <4>; + pwm-mode = "OPWFMB"; + prescaler = <8>; + }; + + pwm_5 { + channel = <5>; + pwm-mode = "OPWFMB"; + prescaler = <8>; + }; + + rgb_red { + channel = <19>; + master-bus = <&emios0_bus_a>; + pwm-mode = "OPWMB"; + }; + }; +}; + +&emios1 { + clock-divider = <200>; + status = "okay"; + + master_bus { + /* + * Timebase for PWM led, setting clock 50KHz for internal counter, + * default period is 1000 cycles <-> 20ms. + */ + emios1_bus_a { + prescaler = <16>; + mode = "MCB_UP_COUNTER"; + status = "okay"; + }; + + emios1_bus_f { + prescaler = <16>; + mode = "MCB_UP_COUNTER"; + status = "okay"; + }; + }; + + emios1_pwm: pwm { + pinctrl-0 = <&emios1_default>; + pinctrl-names = "default"; + status = "okay"; + + rgb_green { + channel = <10>; + master-bus = <&emios1_bus_a>; + pwm-mode = "OPWMB"; + }; + + rgb_blue { + channel = <5>; + master-bus = <&emios1_bus_f>; + pwm-mode = "OPWMB"; + }; + }; +}; + +&flexio0 { + status = "okay"; + + flexio0_pwm: flexio0_pwm { + pinctrl-0 = <&flexio0_pwm_default>; + pinctrl-names = "default"; + status = "okay"; + + pwm_0 { + pin-id = <19>; + prescaler = <1>; + }; + + pwm_1 { + pin-id = <11>; + prescaler = <1>; + }; + }; +}; + +&lcu1 { + status = "okay"; +}; + +&trgmux { + status = "okay"; +}; + +&edma0 { + status = "okay"; +}; diff --git a/boards/nxp/mr_canhubk3/mr_canhubk3_s32k344_mcuboot.dts b/boards/nxp/mr_canhubk3/mr_canhubk3_s32k344_mcuboot.dts new file mode 100644 index 0000000000000..1904986807d0b --- /dev/null +++ b/boards/nxp/mr_canhubk3/mr_canhubk3_s32k344_mcuboot.dts @@ -0,0 +1,61 @@ +/* + * Copyright 2025 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; +#include "mr_canhubk3_common.dtsi" + +/ { + chosen { + zephyr,code-partition = &slot0_partition; + zephyr,flash = &flash0; + }; +}; + +&c40fc { + status = "okay"; +}; + +&flash0 { + status = "okay"; + + /* Replace any board-default partitions with the MCUboot layout */ + /delete-node/ partitions; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + ivt_header: partition@0 { + label = "ivt-header"; + reg = <0x00000000 256>; + }; + + /* pad up to the 8 KiB sector boundary at 0x2000 */ + ivt_pad: partition@100 { + label = "ivt_pad"; + reg = <0x00000100 (DT_SIZE_K(8) - 256)>; + }; + + /* MCUboot @ 0x2000 (128 KiB here; adjust if you use 64 KiB) */ + boot_partition: partition@2000 { + label = "mcuboot"; + reg = <0x00002000 DT_SIZE_K(128)>; + }; + + /* Primary image (slot 0) */ + slot0_partition: partition@22000 { + label = "image-0"; + reg = <0x00022000 DT_SIZE_K(1920)>; + }; + + /* Secondary image (slot 1) — start right after slot0 ends */ + slot1_partition: partition@202000 { + label = "image-1"; + reg = <0x00202000 DT_SIZE_K(1920)>; + }; + }; +}; diff --git a/boards/nxp/mr_canhubk3/mr_canhubk3_s32k344_mcuboot.yaml b/boards/nxp/mr_canhubk3/mr_canhubk3_s32k344_mcuboot.yaml new file mode 100644 index 0000000000000..53f19b7c2b6ec --- /dev/null +++ b/boards/nxp/mr_canhubk3/mr_canhubk3_s32k344_mcuboot.yaml @@ -0,0 +1,27 @@ +# Copyright 2025 NXP +# SPDX-License-Identifier: Apache-2.0 + +identifier: mr_canhubk3/s32k344/mcuboot +name: NXP MR-CANHUBK3 (S32K344, MCUboot) +type: mcu +arch: arm +toolchain: + - zephyr +ram: 320 +flash: 1919 +sysbuild: true +supported: + - adc + - can + - counter + - display + - dma + - flash + - gpio + - i2c + - netif:eth + - pwm + - spi + - uart + - watchdog +vendor: nxp diff --git a/boards/nxp/mr_canhubk3/mr_canhubk3_s32k344_mcuboot_defconfig b/boards/nxp/mr_canhubk3/mr_canhubk3_s32k344_mcuboot_defconfig new file mode 100644 index 0000000000000..a7f2aba81f7c8 --- /dev/null +++ b/boards/nxp/mr_canhubk3/mr_canhubk3_s32k344_mcuboot_defconfig @@ -0,0 +1,17 @@ +# Copyright 2023-2024 NXP +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_BUILD_OUTPUT_HEX=y + +# Enable MPU +CONFIG_ARM_MPU=y + +# Use no-cached memory for HAL +CONFIG_NOCACHE_MEMORY=y + +# Drivers +CONFIG_SERIAL=y +CONFIG_WATCHDOG=y + +# Serial console +CONFIG_CONSOLE=y