summaryrefslogtreecommitdiff
path: root/arch
diff options
context:
space:
mode:
authorTom Rini <[email protected]>2026-06-10 09:17:16 -0600
committerTom Rini <[email protected]>2026-06-10 09:17:16 -0600
commit45cfba58dba911685700d6574b01f39329dce99c (patch)
tree757f42198d98a688fbfd610d3039e4ee8316429d /arch
parent8ef5312bbaf7e85c5c2f710316aea819e12fbe7d (diff)
parentec217322301b306012e01796090c98af9d1f3812 (diff)
Merge tag 'fsl-qoriq-next-2026-06-09' of https://source.denx.de/u-boot/custodians/u-boot-fsl-qoriq into next
CI: https://source.denx.de/u-boot/custodians/u-boot-fsl-qoriq/-/pipelines/30397 - Add JEDEC JC_42.4 thermal driver - Add QorIQ/Layerscape TMU support - Misc dts fix for fsl-lx2160a - Misc i.MX9 SCMI updates
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/cpu/armv8/fsl-layerscape/cpu.c21
-rw-r--r--arch/arm/dts/fsl-lx2160a.dtsi60
-rw-r--r--arch/arm/dts/fsl-lx2162a-qds.dts99
-rw-r--r--arch/arm/include/asm/arch-fsl-layerscape/sys_proto.h30
-rw-r--r--arch/arm/include/asm/arch-imx9/sys_proto.h1
-rw-r--r--arch/arm/mach-imx/imx9/Kconfig4
-rw-r--r--arch/arm/mach-imx/imx9/scmi/Makefile2
-rw-r--r--arch/arm/mach-imx/imx9/scmi/fdt.c644
-rw-r--r--arch/arm/mach-imx/imx9/scmi/soc.c105
9 files changed, 844 insertions, 122 deletions
diff --git a/arch/arm/cpu/armv8/fsl-layerscape/cpu.c b/arch/arm/cpu/armv8/fsl-layerscape/cpu.c
index a047494b1fd..cbeac6d4383 100644
--- a/arch/arm/cpu/armv8/fsl-layerscape/cpu.c
+++ b/arch/arm/cpu/armv8/fsl-layerscape/cpu.c
@@ -986,6 +986,27 @@ uint get_svr(void)
}
#endif
+/*
+ * Layerscape mirror of the i.MX get_cpu_temp_grade(). i.MX reads the
+ * OCOTP "CPU temp grade" fuses; Layerscape has no such fuse, so the
+ * limits come from the data sheet instead. LX2160A Reference Manual
+ * Rev. 1 (10/2021) section 1.12.1 specifies the maximum operating
+ * junction temperature at 105 degC for commercial / embedded parts;
+ * the lower bound is the standard -40 degC commercial low.
+ *
+ * The TMU itself is documented as accurate within +/- 3 degC (RM
+ * section 28.1), which the thermal driver clears by setting its
+ * alert threshold 10 degC below critical.
+ */
+u32 get_cpu_temp_grade(int *minc, int *maxc)
+{
+ if (minc)
+ *minc = -40;
+ if (maxc)
+ *maxc = 105;
+ return 0; /* commercial */
+}
+
#ifdef CONFIG_DISPLAY_CPUINFO
int print_cpuinfo(void)
{
diff --git a/arch/arm/dts/fsl-lx2160a.dtsi b/arch/arm/dts/fsl-lx2160a.dtsi
index 4b4b1c100b8..61d78b74f19 100644
--- a/arch/arm/dts/fsl-lx2160a.dtsi
+++ b/arch/arm/dts/fsl-lx2160a.dtsi
@@ -292,7 +292,7 @@
#interrupt-cells = <2>;
};
- watchdog@23a0000 {
+ wdt0: watchdog@23a0000 {
compatible = "arm,sbsa-gwdt";
reg = <0x0 0x23a0000 0 0x1000>,
<0x0 0x2390000 0 0x1000>;
@@ -594,6 +594,64 @@
};
};
+ /* LX2160ARM Chapter 28 ("Thermal Monitoring Unit") */
+ tmu: tmu@1f80000 {
+ compatible = "fsl,qoriq-tmu";
+ reg = <0x0 0x1f80000 0x0 0x10000>;
+ interrupts = <GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH>;
+ fsl,tmu-range = <0x800000e6 0x8001017d>;
+ fsl,tmu-calibration = <0x00000000 0x00000035
+ 0x00000001 0x00000154>;
+ little-endian;
+ #thermal-sensor-cells = <1>;
+ label = "lx2160a-tmu"; /* explicit naming */
+ };
+
+ /* explicit thermal-zones names per LX2160ARM Table 323 */
+ thermal-zones {
+ cluster67-thermal {
+ polling-delay-passive = <1000>;
+ polling-delay = <5000>;
+ thermal-sensors = <&tmu 0>;
+ };
+
+ ddr1-cluster5-thermal {
+ polling-delay-passive = <1000>;
+ polling-delay = <5000>;
+ thermal-sensors = <&tmu 1>;
+ };
+
+ wriop-thermal {
+ polling-delay-passive = <1000>;
+ polling-delay = <5000>;
+ thermal-sensors = <&tmu 2>;
+ };
+
+ dce-qbman-hsio2-thermal {
+ polling-delay-passive = <1000>;
+ polling-delay = <5000>;
+ thermal-sensors = <&tmu 3>;
+ };
+
+ ccn-dpaa-tbu-thermal {
+ polling-delay-passive = <1000>;
+ polling-delay = <5000>;
+ thermal-sensors = <&tmu 4>;
+ };
+
+ cluster4-hsio3-thermal {
+ polling-delay-passive = <1000>;
+ polling-delay = <5000>;
+ thermal-sensors = <&tmu 5>;
+ };
+
+ cluster23-thermal {
+ polling-delay-passive = <1000>;
+ polling-delay = <5000>;
+ thermal-sensors = <&tmu 6>;
+ };
+ };
+
/* WRIOP0: 0x8b8_0000, E-MDIO1: 0x1_6000 */
emdio1: mdio@8b96000 {
compatible = "fsl,ls-mdio";
diff --git a/arch/arm/dts/fsl-lx2162a-qds.dts b/arch/arm/dts/fsl-lx2162a-qds.dts
index 4eaf982529d..35d80639958 100644
--- a/arch/arm/dts/fsl-lx2162a-qds.dts
+++ b/arch/arm/dts/fsl-lx2162a-qds.dts
@@ -37,105 +37,6 @@
status = "disabled";
};
-&dspi0 {
- bus-num = <0>;
- status = "okay";
-
- dflash0: n25q128a@0 {
- #address-cells = <1>;
- #size-cells = <1>;
- compatible = "jedec,spi-nor";
- spi-max-frequency = <3000000>;
- spi-cpol;
- spi-cpha;
- reg = <0>;
- };
- dflash1: sst25wf040b@1 {
- #address-cells = <1>;
- #size-cells = <1>;
- compatible = "jedec,spi-nor";
- spi-max-frequency = <3000000>;
- spi-cpol;
- spi-cpha;
- reg = <1>;
- };
- dflash2: en25s64@2 {
- #address-cells = <1>;
- #size-cells = <1>;
- compatible = "jedec,spi-nor";
- spi-max-frequency = <3000000>;
- spi-cpol;
- spi-cpha;
- reg = <2>;
- };
-};
-
-&dspi1 {
- bus-num = <0>;
- status = "okay";
-
- dflash3: n25q128a@0 {
- #address-cells = <1>;
- #size-cells = <1>;
- compatible = "jedec,spi-nor";
- spi-max-frequency = <3000000>;
- spi-cpol;
- spi-cpha;
- reg = <0>;
- };
- dflash4: sst25wf040b@1 {
- #address-cells = <1>;
- #size-cells = <1>;
- compatible = "jedec,spi-nor";
- spi-max-frequency = <3000000>;
- spi-cpol;
- spi-cpha;
- reg = <1>;
- };
- dflash5: en25s64@2 {
- #address-cells = <1>;
- #size-cells = <1>;
- compatible = "jedec,spi-nor";
- spi-max-frequency = <3000000>;
- spi-cpol;
- spi-cpha;
- reg = <2>;
- };
-};
-
-&dspi2 {
- bus-num = <0>;
- status = "okay";
-
- dflash6: n25q128a@0 {
- #address-cells = <1>;
- #size-cells = <1>;
- compatible = "jedec,spi-nor";
- spi-max-frequency = <3000000>;
- spi-cpol;
- spi-cpha;
- reg = <0>;
- };
- dflash7: sst25wf040b@1 {
- #address-cells = <1>;
- #size-cells = <1>;
- compatible = "jedec,spi-nor";
- spi-max-frequency = <3000000>;
- spi-cpol;
- spi-cpha;
- reg = <1>;
- };
- dflash8: en25s64@2 {
- #address-cells = <1>;
- #size-cells = <1>;
- compatible = "jedec,spi-nor";
- spi-max-frequency = <3000000>;
- spi-cpol;
- spi-cpha;
- reg = <2>;
- };
-};
-
&esdhc1 {
mmc-hs200-1_8v;
mmc-hs400-1_8v;
diff --git a/arch/arm/include/asm/arch-fsl-layerscape/sys_proto.h b/arch/arm/include/asm/arch-fsl-layerscape/sys_proto.h
new file mode 100644
index 00000000000..3b78e73c726
--- /dev/null
+++ b/arch/arm/include/asm/arch-fsl-layerscape/sys_proto.h
@@ -0,0 +1,30 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2026 Free Mobile - Vincent Jardin
+ *
+ * Layerscape mirror of the i.MX <asm/mach-imx/sys_proto.h>: declares
+ * the SoC-personality helpers consumed by generic drivers that work on
+ * both i.MX and QorIQ/Layerscape parts (e.g. drivers/thermal/imx_tmu.c
+ * for the QorIQ TMU variant).
+ */
+
+#ifndef _ASM_ARCH_FSL_LAYERSCAPE_SYS_PROTO_H
+#define _ASM_ARCH_FSL_LAYERSCAPE_SYS_PROTO_H
+
+#include <linux/types.h>
+
+/*
+ * Per LX2160A Reference Manual, Rev. 1 (10/2021):
+ * - section 1.12.1: "NXP specs max power at 105 degC junction" for
+ * commercial / embedded operating conditions.
+ * - section 28.1: TMU "Accuracy within +/- 3 degC".
+ *
+ * Layerscape SoCs do not expose an OCOTP-style "CPU temp grade" fuse,
+ * so the implementation returns the documented junction-temperature
+ * limit from the data sheet (-40 .. 105 degC commercial range). The
+ * thermal driver subtracts 10 degC for its alert threshold, which
+ * comfortably clears the +/- 3 degC TMU accuracy in both directions.
+ */
+u32 get_cpu_temp_grade(int *minc, int *maxc);
+
+#endif /* _ASM_ARCH_FSL_LAYERSCAPE_SYS_PROTO_H */
diff --git a/arch/arm/include/asm/arch-imx9/sys_proto.h b/arch/arm/include/asm/arch-imx9/sys_proto.h
index b5e7d7d6855..d43e54e72aa 100644
--- a/arch/arm/include/asm/arch-imx9/sys_proto.h
+++ b/arch/arm/include/asm/arch-imx9/sys_proto.h
@@ -22,6 +22,7 @@ int low_drive_freq_update(void *blob);
enum imx9_soc_voltage_mode soc_target_voltage_mode(void);
int get_reset_reason(bool sys, bool lm);
+int imx9_uboot_fixup_by_fuse(void *fdt);
int scmi_get_boot_device_offset(unsigned long *img_off);
int scmi_get_boot_stage(u8 *stage);
diff --git a/arch/arm/mach-imx/imx9/Kconfig b/arch/arm/mach-imx/imx9/Kconfig
index 7fa6d6369e8..4bb6a87ce26 100644
--- a/arch/arm/mach-imx/imx9/Kconfig
+++ b/arch/arm/mach-imx/imx9/Kconfig
@@ -150,6 +150,7 @@ config TARGET_PHYCORE_IMX93
config TARGET_IMX95_19X19_EVK
bool "imx95_19x19_evk"
+ select OF_BOARD_FIXUP
select IMX95
imply BOOTSTD_BOOTCOMMAND
imply BOOTSTD_FULL
@@ -157,6 +158,7 @@ config TARGET_IMX95_19X19_EVK
config TARGET_IMX95_15X15_EVK
bool "imx95_15x15_evk"
+ select OF_BOARD_FIXUP
select IMX95
imply BOOTSTD_BOOTCOMMAND
imply BOOTSTD_FULL
@@ -164,6 +166,7 @@ config TARGET_IMX95_15X15_EVK
config TARGET_IMX943_EVK
bool "imx943_evk"
+ select OF_BOARD_FIXUP
select IMX94
imply BOOTSTD_BOOTCOMMAND
imply BOOTSTD_FULL
@@ -180,6 +183,7 @@ config TARGET_VERDIN_IMX95
config TARGET_IMX952_EVK
bool "imx952_evk"
+ select OF_BOARD_FIXUP
select IMX_SM_CPU
select IMX_SM_LMM
select IMX952
diff --git a/arch/arm/mach-imx/imx9/scmi/Makefile b/arch/arm/mach-imx/imx9/scmi/Makefile
index b98744e1ecb..e83d27327cb 100644
--- a/arch/arm/mach-imx/imx9/scmi/Makefile
+++ b/arch/arm/mach-imx/imx9/scmi/Makefile
@@ -5,5 +5,5 @@
# Add include path for NXP device tree header files from Linux.
ccflags-y += -I$(srctree)/dts/upstream/src/arm64/freescale/
-obj-y += soc.o
+obj-y += soc.o fdt.o
obj-y += clock_scmi.o clock.o
diff --git a/arch/arm/mach-imx/imx9/scmi/fdt.c b/arch/arm/mach-imx/imx9/scmi/fdt.c
new file mode 100644
index 00000000000..a1d9afbf69a
--- /dev/null
+++ b/arch/arm/mach-imx/imx9/scmi/fdt.c
@@ -0,0 +1,644 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2026 NXP
+ *
+ */
+
+#include <asm/arch/sys_proto.h>
+#include <linux/bitfield.h>
+#include <fuse.h>
+#include <fdt_support.h>
+#include <fdtdec.h>
+
+struct periph_fuse_info {
+ u32 bit_mask;
+ u32 soc_type; /* 0 means for all */
+ bool of_board_fix;
+ int (*disable_func)(void *blob, u32 fuse_val);
+};
+
+int num_a55_cores_disabled;
+int gpu_disabled;
+
+static int delete_fdt_nodes(void *blob, const char *const nodes_path[], int size_array)
+{
+ int i = 0;
+ int rc;
+ int nodeoff;
+
+ for (i = 0; i < size_array; i++) {
+ nodeoff = fdt_path_offset(blob, nodes_path[i]);
+ if (nodeoff < 0)
+ continue; /* Not found, skip it */
+
+ debug("Found %s node\n", nodes_path[i]);
+
+ rc = fdt_del_node(blob, nodeoff);
+ if (rc < 0) {
+ printf("Unable to delete node %s, err=%s\n",
+ nodes_path[i], fdt_strerror(rc));
+ } else {
+ printf("Delete node %s\n", nodes_path[i]);
+ }
+ }
+
+ return 0;
+}
+
+static int disable_fdt_nodes(void *blob, const char *const nodes_path[],
+ int size_array, const char *prop, const char *value)
+{
+ int i = 0;
+ int rc;
+ int nodeoff;
+ const char *status = "disabled";
+ const char *prop_str;
+
+ for (i = 0; i < size_array; i++) {
+ nodeoff = fdt_path_offset(blob, nodes_path[i]);
+ if (nodeoff < 0)
+ continue; /* Not found, skip it */
+
+ debug("Found %s node\n", nodes_path[i]);
+
+ if (prop && value) {
+ prop_str = fdt_stringlist_get(blob, nodeoff, prop, 0, NULL);
+
+ if (!prop_str || strcmp(prop_str, value))
+ continue;
+ }
+
+add_status:
+ rc = fdt_setprop(blob, nodeoff, "status", status, strlen(status) + 1);
+ if (rc) {
+ if (rc == -FDT_ERR_NOSPACE) {
+ rc = fdt_increase_size(blob, 512);
+ if (!rc)
+ goto add_status;
+ }
+ printf("Unable to update property %s:%s, err=%s\n",
+ nodes_path[i], "status", fdt_strerror(rc));
+ } else {
+ debug("Modify %s:%s disabled\n", nodes_path[i], "status");
+ }
+ }
+
+ return 0;
+}
+
+static int get_cooling_device_list(void *blob, u32 nodeoff,
+ const char *const path, u32 *cooling_dev, int max_cnt)
+{
+ int cnt, j;
+
+ cnt = fdtdec_get_int_array_count(blob, nodeoff, "cooling-device",
+ cooling_dev, max_cnt);
+ if (cnt < 0) {
+ printf("cnt incorrect, path %s, cnt = %d\n", path, cnt);
+ return cnt;
+ }
+ if (cnt != max_cnt)
+ printf("Warning: %s, cooling-device count %d\n", path, cnt);
+
+ for (j = 0; j < cnt; j++)
+ cooling_dev[j] = cpu_to_fdt32(cooling_dev[j]);
+
+ return cnt;
+}
+
+static void disable_thermal_vpu_node(void *blob, u32 disabled_cores, u32 gpu_disabled)
+{
+ static const char * const thermal_path[] = {
+ "/thermal-zones/ana/cooling-maps/map0",
+ "/thermal-zones/ana-thermal/cooling-maps/map0",
+ };
+ int num_cpus = (is_imx94() || is_imx952()) ? 4 : 6;
+ u32 array_cnt = (num_cpus + 2) * 3 - (disabled_cores * 3) - (gpu_disabled * 3);
+ u32 cooling_dev[array_cnt];
+
+ int nodeoff, ret, i, cnt;
+
+ for (i = 0; i < ARRAY_SIZE(thermal_path); i++) {
+ nodeoff = fdt_path_offset(blob, thermal_path[i]);
+ if (nodeoff < 0) {
+ printf("path not found %s\n", thermal_path[i]);
+ continue; /* Not found, skip it */
+ }
+
+ cnt = get_cooling_device_list(blob, nodeoff,
+ thermal_path[i], cooling_dev, array_cnt);
+ /* VPU map does not exist in cooling dev*/
+ if (cnt <= ((num_cpus - disabled_cores) * 3 + (gpu_disabled ? 0 : 3)))
+ continue;
+
+ /* Remove VPU it the last two nodes in the fdt ana blob */
+ ret = fdt_setprop(blob, nodeoff, "cooling-device", &cooling_dev,
+ sizeof(u32) * (array_cnt - 3));
+
+ if (ret < 0) {
+ printf("Warning: %s, cooling-device setprop failed %d\n",
+ thermal_path[i], ret);
+ continue;
+ }
+
+ printf("Update node %s, cooling-device prop\n", thermal_path[i]);
+ }
+}
+
+static void disable_thermal_gpu_node(void *blob, u32 disabled_cores)
+{
+ static const char * const thermal_path[] = {
+ "/thermal-zones/ana/cooling-maps/map0",
+ "/thermal-zones/ana-thermal/cooling-maps/map0",
+ };
+ int num_cpus = (is_imx94() || is_imx952()) ? 4 : 6;
+ u32 array_cnt = (num_cpus + 2) * 3 - (disabled_cores * 3);
+ u32 cooling_dev[array_cnt];
+ int nodeoff, ret, i, cnt;
+
+ for (i = 0; i < ARRAY_SIZE(thermal_path); i++) {
+ nodeoff = fdt_path_offset(blob, thermal_path[i]);
+ if (nodeoff < 0) {
+ printf("path not found %s\n", thermal_path[i]);
+ continue; /* Not found, skip it */
+ }
+
+ cnt = get_cooling_device_list(blob, nodeoff, thermal_path[i],
+ cooling_dev, array_cnt);
+ if (cnt <= (num_cpus - disabled_cores) * 3)
+ continue; /* GPU map does not exist in cooling dev*/
+
+ /* Remove GPU and VPU as these are the last two nodes in the fdt ana blob */
+ ret = fdt_setprop(blob, nodeoff, "cooling-device", &cooling_dev,
+ sizeof(u32) * (array_cnt - 6));
+ if (ret < 0) {
+ printf("Warning: %s, cooling-device setprop failed %d\n",
+ thermal_path[i], ret);
+ continue;
+ }
+
+ if (cnt == array_cnt) {
+ /* Add VPU node back to ana thermal-zone. */
+ ret = fdt_appendprop(blob, nodeoff, "cooling-device",
+ &cooling_dev[array_cnt - 3], sizeof(u32) * 3);
+ if (ret < 0) {
+ printf("Warning: %s, cooling-device appendprop failed %d\n",
+ thermal_path[i], ret);
+ continue;
+ }
+ }
+
+ printf("Update node %s, cooling-device prop\n", thermal_path[i]);
+ }
+}
+
+static void disable_thermal_cpu_nodes(void *blob, u32 disabled_cores)
+{
+ static const char * const thermal_path[] = {
+ "/thermal-zones/pf53_arm/cooling-maps/map0",
+ "/thermal-zones/ana/cooling-maps/map0",
+ "/thermal-zones/a55/cooling-maps/map0",
+ "/thermal-zones/a55-thermal/cooling-maps/map0",
+ "/thermal-zones/ana-thermal/cooling-maps/map0",
+ };
+ u32 cooling_dev[24];
+ int nodeoff, ret, i, cnt;
+ int prop_size = 3 * ((is_imx94() || is_imx952()) ? 4 : 6);
+
+ for (i = 0; i < ARRAY_SIZE(thermal_path); i++) {
+ nodeoff = fdt_path_offset(blob, thermal_path[i]);
+ if (nodeoff < 0) {
+ printf("path not found %s\n", thermal_path[i]);
+ continue; /* Not found, skip it */
+ }
+ cnt = get_cooling_device_list(blob, nodeoff, thermal_path[i], cooling_dev, 24);
+
+ ret = fdt_setprop(blob, nodeoff, "cooling-device", &cooling_dev,
+ sizeof(u32) * (prop_size - disabled_cores * 3));
+
+ if (ret < 0) {
+ printf("Warning: %s, cooling-device setprop failed %d\n",
+ thermal_path[i], ret);
+ continue;
+ }
+
+ /* Add GPU and VPU nodes back to ana thermal-zone. */
+ if (cnt > prop_size) {
+ ret = fdt_appendprop(blob, nodeoff, "cooling-device",
+ &cooling_dev[prop_size],
+ sizeof(u32) * (cnt - prop_size));
+ if (ret < 0) {
+ printf("Warning: %s, cooling-device appendprop failed %d\n",
+ thermal_path[i], ret);
+ continue;
+ }
+ }
+
+ printf("Update node %s, cooling-device prop\n", thermal_path[i]);
+ }
+}
+
+static int disable_ld_node(void *blob, u32 fuse_val)
+{
+ static const char * const nodes_path_ld[] = {
+ "/remoteproc",
+ "/disp-mu",
+ "/soc/syscon@4b070000",
+ "/soc/mailbox@4b080000",
+ "/soc/mailbox@4b090000",
+ };
+
+ return delete_fdt_nodes(blob, nodes_path_ld, ARRAY_SIZE(nodes_path_ld));
+}
+
+static int disable_npu_node(void *blob, u32 fuse_val)
+{
+ static const char * const nodes_path_npu[] = {
+ "/soc/imx95-neutron-remoteproc@4ab00000",
+ "/soc/imx95-neutron@4ab00004",
+ "/soc/neutron-remoteproc@4ab00000",
+ "/soc/neutron@4ab00004",
+ };
+
+ return delete_fdt_nodes(blob, nodes_path_npu, ARRAY_SIZE(nodes_path_npu));
+}
+
+static int disable_arm_cpu_nodes(void *blob, u32 fuse_val)
+{
+ u32 i = 0;
+ int rc;
+ int nodeoff;
+ char nodes_path[32];
+ int num_cpus = (is_imx94() || is_imx952()) ? 4 : 6;
+
+ num_a55_cores_disabled = 0;
+
+ if (fuse_val & BIT(2)) /* A55C2 */
+ num_a55_cores_disabled++;
+
+ if (fuse_val & BIT(3)) /* A55C2 */
+ num_a55_cores_disabled++;
+
+ if (fuse_val & BIT(4)) /* A55C3 */
+ num_a55_cores_disabled++;
+
+ if (fuse_val & BIT(5)) /* A55C4 */
+ num_a55_cores_disabled++;
+
+ if (fuse_val & BIT(6)) /* A55C5 */
+ num_a55_cores_disabled++;
+
+ for (i = num_cpus; i > (num_cpus - num_a55_cores_disabled); i--) {
+ sprintf(nodes_path, "/cpus/cpu@%u00", i - 1);
+
+ nodeoff = fdt_path_offset(blob, nodes_path);
+ if (nodeoff < 0)
+ continue; /* Not found, skip it */
+
+ debug("Found %s node\n", nodes_path);
+
+ rc = fdt_del_node(blob, nodeoff);
+ if (rc < 0) {
+ printf("Unable to delete node %s, err=%s\n",
+ nodes_path, fdt_strerror(rc));
+ } else {
+ printf("Delete node %s\n", nodes_path);
+
+ /* Remove node from cpu-map/cluster0 */
+ sprintf(nodes_path, "/cpus/cpu-map/cluster0/core%u", i - 1);
+ nodeoff = fdt_path_offset(blob, nodes_path);
+ if (nodeoff < 0)
+ continue; /* Not found, skip it */
+
+ rc = fdt_del_node(blob, nodeoff);
+ if (rc < 0)
+ printf("Unable to delete node %s, err=%s\n",
+ nodes_path, fdt_strerror(rc));
+ }
+ }
+
+ disable_thermal_cpu_nodes(blob, num_a55_cores_disabled);
+
+ return 0;
+}
+
+static int disable_jpegdec_node(void *blob, u32 fuse_val)
+{
+ static const char * const nodes_path_jpegdec[] = {
+ "/soc/jpegdec@4c500000",
+ };
+
+ return delete_fdt_nodes(blob, nodes_path_jpegdec, ARRAY_SIZE(nodes_path_jpegdec));
+}
+
+static int disable_jpegenc_node(void *blob, u32 fuse_val)
+{
+ static const char * const nodes_path_jpegenc[] = {
+ "/soc/jpegenc@4c550000",
+ };
+
+ return delete_fdt_nodes(blob, nodes_path_jpegenc, ARRAY_SIZE(nodes_path_jpegenc));
+}
+
+static int disable_mipicsi0_node(void *blob, u32 fuse_val)
+{
+ static const char * const nodes_path_mipicsi0[] = {
+ "/soc/csi@4ad30000",
+ };
+
+ return delete_fdt_nodes(blob, nodes_path_mipicsi0, ARRAY_SIZE(nodes_path_mipicsi0));
+}
+
+static int disable_mipicsi1_node(void *blob, u32 fuse_val)
+{
+ static const char * const nodes_path_mipicsi1[] = {
+ "/soc/csi@4ad40000",
+ };
+
+ return delete_fdt_nodes(blob, nodes_path_mipicsi1, ARRAY_SIZE(nodes_path_mipicsi1));
+}
+
+static int disable_isp_node(void *blob, u32 fuse_val)
+{
+ static const char * const nodes_path_isp[] = {
+ "/soc@0/isp@4ae00000",
+ "/soc/isp@4ae00000",
+ };
+
+ return delete_fdt_nodes(blob, nodes_path_isp, ARRAY_SIZE(nodes_path_isp));
+}
+
+static int disable_vpu_node(void *blob, u32 fuse_val)
+{
+ int ret = 0;
+
+ static const char * const nodes_path_vpu[] = {
+ "/soc/vpu-ctrl@4c4c0000",
+ "/soc/vpu-ctrl@4c4f0000",
+ "/soc/vpu@4c480000",
+ "/soc/vpu@4c490000",
+ "/soc/vpu@4c4a0000",
+ "/soc/vpu@4c4b0000",
+ "/soc/vpu@4c4c0000",
+ "/soc/vpu@4c4d0000",
+ "/soc/vpu@4c4e0000",
+ "/soc/jpegdec@4c500000",
+ "/soc/jpegenc@4c550000",
+ "/soc/vpuenc@4c460000",
+ "/soc/syscon@4c410000"
+ };
+
+ ret = delete_fdt_nodes(blob, nodes_path_vpu, ARRAY_SIZE(nodes_path_vpu));
+ if (!ret)
+ disable_thermal_vpu_node(blob, num_a55_cores_disabled, gpu_disabled);
+
+ return ret;
+}
+
+static int disable_vpuenc_node(void *blob, u32 fuse_val)
+{
+ static const char * const nodes_path_vpuenc[] = {
+ "/soc/vpuenc@4c460000",
+ };
+
+ return delete_fdt_nodes(blob, nodes_path_vpuenc, ARRAY_SIZE(nodes_path_vpuenc));
+}
+
+static int disable_vpuwave511_node(void *blob, u32 fuse_val)
+{
+ static const char * const nodes_path_vpu511[] = {
+ "/soc/vpu-ctrl@4c4f0000",
+ "/soc/vpu@4c4b0000",
+ "/soc/vpu@4c4c0000",
+ "/soc/vpu@4c4d0000",
+ "/soc/vpu@4c4e0000",
+ };
+
+ return delete_fdt_nodes(blob, nodes_path_vpu511, ARRAY_SIZE(nodes_path_vpu511));
+}
+
+static int disable_gpu_node(void *blob, u32 fuse_val)
+{
+ int ret = 0;
+
+ static const char * const nodes_path_gpu[] = {
+ "/soc/gpu@4d900000",
+ "/thermal-zones@1/ana/cooling-maps/map1/cooling-device/gpu@4d900000",
+ "/thermal-zones/ana/cooling-maps/map1/cooling-device/gpu@4d900000",
+ "/thermal-zones@1/ana/cooling-maps/map1/cooling-device",
+ "/thermal-zones/ana/cooling-maps/map1/cooling-device",
+ "/thermal-zones@1/ana/cooling-maps/map1",
+ "/thermal-zones/ana/cooling-maps/map1",
+ };
+
+ ret = delete_fdt_nodes(blob, nodes_path_gpu, ARRAY_SIZE(nodes_path_gpu));
+ if (!ret) {
+ disable_thermal_gpu_node(blob, num_a55_cores_disabled);
+ gpu_disabled = 1;
+ }
+ return ret;
+}
+
+static int disable_pciea_node(void *blob, u32 fuse_val)
+{
+ static const char * const nodes_path_pciea[] = {
+ "/soc/pcie@4c300000",
+ "/soc/pcie-ep@4c300000"
+ };
+
+ return delete_fdt_nodes(blob, nodes_path_pciea, ARRAY_SIZE(nodes_path_pciea));
+}
+
+static int disable_pcieb_node(void *blob, u32 fuse_val)
+{
+ static const char * const nodes_path_pcieb[] = {
+ "/soc/pcie@4c380000",
+ "/soc/pcie-ep@4c380000"
+ };
+
+ return delete_fdt_nodes(blob, nodes_path_pcieb, ARRAY_SIZE(nodes_path_pcieb));
+}
+
+int disable_enet10g_node(void *blob, u32 fuse_val)
+{
+ static const char * const nodes_path_enet10g[] = {
+ "/pcie@4ca00000/ethernet@10,0",
+ "/soc/pcie@4ca00000/ethernet@10,0",
+ "/soc/syscon@4ca00000/ethernet@10,0",
+ "/soc/netc-blk-ctrl@4cde0000/pcie@4ca00000/ethernet@10,0",
+ };
+
+ return disable_fdt_nodes(blob, nodes_path_enet10g, ARRAY_SIZE(nodes_path_enet10g),
+ NULL, NULL);
+}
+
+int disable_enet25g_node(void *blob, u32 fuse_val)
+{
+ static const char * const nodes_path_enet25g[] = {
+ "/soc/system-controller@4ceb0000/pcie@4ca00000/ethernet-switch@0,2/ports/port@0",
+ "/soc/system-controller@4ceb0000/pcie@4ca00000/ethernet-switch@0,2/ports/port@1",
+ };
+
+ return disable_fdt_nodes(blob, nodes_path_enet25g, ARRAY_SIZE(nodes_path_enet25g),
+ "phy-mode", "sgmii");
+}
+
+int disable_mipidsi_node(void *blob, u32 fuse_val)
+{
+ static const char * const nodes_path_mipidsi[] = {
+ "/soc/dsi@4acf0000",
+ "/soc/syscon@4acf0000",
+ "/soc/dsi@4b060000",
+ "/soc/phy@4b110000",
+ };
+
+ return delete_fdt_nodes(blob, nodes_path_mipidsi, ARRAY_SIZE(nodes_path_mipidsi));
+}
+
+int disable_dpu_node(void *blob, u32 fuse_val)
+{
+ static const char * const nodes_path_dpu[] = {
+ "/soc/bridge@4b0d0000/channel@0/port@0/endpoint",
+ "/soc/bridge@4b0d0000/channel@0/port@1/endpoint",
+ "/soc/bridge@4b0d0000/channel@1/port@0/endpoint",
+ "/soc/bridge@4b0d0000/channel@1/port@1/endpoint",
+ "/soc/display-controller@4b400000/ports/port@0/endpoint",
+ "/soc/display-controller@4b400000/ports/port@1/endpoint",
+ "/soc/display-controller@4b400000",
+ "/soc/syscon@4b010000/bridge@8/ports/port@0/endpoint",
+ "/soc/syscon@4b010000/bridge@8/ports/port@1/endpoint",
+ "/soc/syscon@4b010000/bridge@8/ports/port@2/endpoint@0",
+ "/soc/syscon@4b010000/bridge@8/ports/port@2/endpoint@1",
+ "/soc/syscon@4b010000/bridge@8/ports/port@3/endpoint@0",
+ "/soc/syscon@4b010000/bridge@8/ports/port@3/endpoint@1",
+ "/soc/syscon@4b010000/bridge@8",
+ "/soc/syscon@4b010000",
+ "/soc/syscon@4b0a0000",
+ "/soc/interrupt-controller@4b0b0000",
+ "/soc/bridge@4b0d0000"
+ };
+
+ return delete_fdt_nodes(blob, nodes_path_dpu, ARRAY_SIZE(nodes_path_dpu));
+}
+
+int disable_lvds_node(void *blob, u32 fuse_val)
+{
+ static const char * const nodes_path_lvds[] = {
+ "/soc/syscon@4b0c0000/ldb@4/channel@0",
+ "/soc/syscon@4b0c0000/phy@8",
+ "/soc/syscon@4b0c0000/ldb@4/channel@1",
+ "/soc/syscon@4b0c0000/phy@c",
+ "/soc/syscon@4b0c0000"
+ };
+
+ return delete_fdt_nodes(blob, nodes_path_lvds, ARRAY_SIZE(nodes_path_lvds));
+}
+
+int disable_cm70_node(void *blob, u32 fuse_val)
+{
+ static const char * const nodes_path_cm70[] = {
+ "/reserved-memory/vdev0vring0@82000000",
+ "/reserved-memory/vdev0vring1@82008000",
+ "/reserved-memory/vdev1vring0@82010000",
+ "/reserved-memory/vdev1vring1@82018000",
+ "/reserved-memory/rsc-table@82220000",
+ "/reserved-memory/vdevbuffer@82020000",
+ "/imx943-cm70",
+ };
+
+ return delete_fdt_nodes(blob, nodes_path_cm70, ARRAY_SIZE(nodes_path_cm70));
+}
+
+int disable_cm71_node(void *blob, u32 fuse_val)
+{
+ static const char * const nodes_path_cm71[] = {
+ "/reserved-memory/vdev0vring0@84000000",
+ "/reserved-memory/vdev0vring1@84008000",
+ "/reserved-memory/vdev1vring0@84010000",
+ "/reserved-memory/vdev1vring1@84018000",
+ "/reserved-memory/rsc-table@84220000",
+ "/reserved-memory/vdevbuffer@84020000",
+ "/imx943-cm71",
+ };
+
+ return delete_fdt_nodes(blob, nodes_path_cm71, ARRAY_SIZE(nodes_path_cm71));
+}
+
+/* There is order dependency between cpu->gpu->vpu */
+struct periph_fuse_info f17_grp[] = {
+ { BIT(30), MXC_CPU_IMX952, false, disable_ld_node },
+};
+
+struct periph_fuse_info f18_grp[] = {
+ { BIT(0), 0, false, disable_npu_node },
+ { GENMASK(6, 2), 0, false, disable_arm_cpu_nodes },
+ { BIT(9), 0, true, disable_cm70_node },
+ { BIT(17), MXC_CPU_IMX94, true, disable_cm71_node },
+ { BIT(22), 0, true, disable_dpu_node },
+ { BIT(27), 0, true, disable_lvds_node },
+ { BIT(29), 0, false, disable_isp_node },
+};
+
+struct periph_fuse_info f19_grp[] = {
+ { BIT(6), 0, true, disable_pciea_node },
+ { BIT(7), 0, true, disable_pcieb_node },
+ { BIT(17), 0, false, disable_gpu_node },
+ { BIT(18), 0, false, disable_vpu_node },
+ { BIT(19), 0, false, disable_jpegenc_node },
+ { BIT(20), 0, false, disable_jpegdec_node },
+ { BIT(22), 0, false, disable_mipicsi0_node },
+ { BIT(23), 0, false, disable_mipicsi1_node },
+ { BIT(24), 0, true, disable_mipidsi_node },
+ { BIT(26), 0, false, disable_vpuenc_node },
+ { BIT(27), 0, false, disable_vpuwave511_node },
+};
+
+struct periph_fuse_info f20_grp[] = {
+ { BIT(12), MXC_CPU_IMX95, true, disable_enet10g_node },
+ { BIT(12), MXC_CPU_IMX94, true, disable_enet25g_node },
+};
+
+static void ft_disable_periph(void *blob, u32 fuse_bank, u32 fuse_word,
+ struct periph_fuse_info *info, u32 info_num,
+ bool board_fix_fdt)
+{
+ int i, ret;
+ u32 val = 0;
+
+ ret = fuse_read(fuse_bank, fuse_word, &val);
+ if (ret)
+ return;
+
+ for (i = 0; i < info_num; i++) {
+ if (val & info[i].bit_mask) {
+ if (board_fix_fdt && !info[i].of_board_fix)
+ continue;
+
+ if (!info[i].soc_type || is_cpu_type(info[i].soc_type))
+ info[i].disable_func(blob, val);
+ }
+ }
+}
+
+int ft_system_setup(void *blob, struct bd_info *bd)
+{
+ /* Common peripheral disable fuse process */
+ ft_disable_periph(blob, 2, 1, f17_grp, ARRAY_SIZE(f17_grp), false);
+ ft_disable_periph(blob, 2, 2, f18_grp, ARRAY_SIZE(f18_grp), false);
+ ft_disable_periph(blob, 2, 3, f19_grp, ARRAY_SIZE(f19_grp), false);
+ ft_disable_periph(blob, 2, 4, f20_grp, ARRAY_SIZE(f20_grp), false);
+
+ return 0;
+}
+
+/* Fix uboot dtb based on fuses. */
+#if IS_ENABLED(CONFIG_OF_BOARD_FIXUP) && !IS_ENABLED(CONFIG_XPL_BUILD)
+int imx9_uboot_fixup_by_fuse(void *fdt)
+{
+ ft_disable_periph(fdt, 2, 2, f18_grp, ARRAY_SIZE(f18_grp), true);
+ ft_disable_periph(fdt, 2, 3, f19_grp, ARRAY_SIZE(f19_grp), true);
+ ft_disable_periph(fdt, 2, 4, f20_grp, ARRAY_SIZE(f20_grp), true);
+
+ return 0;
+}
+#endif
diff --git a/arch/arm/mach-imx/imx9/scmi/soc.c b/arch/arm/mach-imx/imx9/scmi/soc.c
index 8a295baf5a2..123c1d51a4d 100644
--- a/arch/arm/mach-imx/imx9/scmi/soc.c
+++ b/arch/arm/mach-imx/imx9/scmi/soc.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0+
/*
- * Copyright 2025 NXP
+ * Copyright 2025-2026 NXP
*
* Peng Fan <[email protected]>
*/
@@ -186,8 +186,9 @@ u32 get_cpu_temp_grade(int *minc, int *maxc)
*minc = -40;
*maxc = 105;
} else if (val == TEMP_EXTCOMMERCIAL) {
- *minc = -20;
- *maxc = 105;
+ /* Map to Ext industrial */
+ *minc = -40;
+ *maxc = 125;
} else {
*minc = 0;
*maxc = 95;
@@ -715,14 +716,88 @@ int get_reset_reason(bool sys, bool lm)
return 0;
}
-const char *get_imx_type(u32 imxtype)
+const char *get_cpu_variant_type_name(u32 type)
{
- switch (imxtype) {
- case SCMI_CPU:
- return IMX_PLAT_STR;
- default:
- return "??";
+ u32 val, core_num, part_num;
+ int ret;
+
+ ret = fuse_read(2, 1, &val);
+ if (ret)
+ return NULL;
+
+ /* Get part num */
+ part_num = (val >> 4) & 0xff;
+ if (!part_num)
+ return NULL;
+
+ if (type == MXC_CPU_IMX95 || type == MXC_CPU_IMX952) {
+ u32 segment;
+ static char name[8] = "95294";
+ char pn[2];
+
+ core_num = part_num & 0x3;
+ segment = (part_num >> 2) & 0xf;
+
+ switch (segment) {
+ case 0xa:
+ pn[0] = 'T';
+ break;
+ case 0xb:
+ pn[0] = 'V';
+ break;
+ case 0xc:
+ pn[0] = 'C';
+ break;
+ case 0xd:
+ pn[0] = 'G';
+ break;
+ case 0xe:
+ pn[0] = 'I';
+ break;
+ case 0xf:
+ pn[0] = 'N';
+ break;
+ default:
+ pn[0] = segment + '0';
+ break;
+ }
+
+ pn[1] = core_num * 2 + '0';
+
+ if (type == MXC_CPU_IMX95)
+ sprintf(name, "95%c%c", pn[0], pn[1]);
+ else
+ sprintf(name, "952%c%c", pn[0], pn[1]);
+
+ return name;
+ } else if (type == MXC_CPU_IMX94) {
+ static char *name = "94398";
+
+ core_num = 8;
+
+ ret = fuse_read(2, 2, &val);
+ if (ret)
+ return NULL;
+
+ if (part_num > 30) { /* 943 */
+ /* A55 2 & 3 disabled */
+ if ((val & 0x18) == 0x18)
+ core_num = 6;
+ } else if (part_num > 20) { /* 942 */
+ core_num = 5;
+
+ /* m7_0 disabled */
+ if ((val & 0x200) == 0x200)
+ core_num = 4;
+ } else if (part_num > 10) { /* 941 */
+ core_num = 5;
+ }
+ sprintf(name, "94%u%u", part_num, core_num);
+
+ return name;
}
+
+ return NULL;
}
void build_info(void)
@@ -798,18 +873,6 @@ int arch_misc_init(void)
return 0;
}
-#if defined(CONFIG_OF_BOARD_FIXUP) && !defined(CONFIG_SPL_BUILD)
-int board_fix_fdt(void *fdt)
-{
- return 0;
-}
-#endif
-
-int ft_system_setup(void *blob, struct bd_info *bd)
-{
- return 0;
-}
-
#if IS_ENABLED(CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG)
void get_board_serial(struct tag_serialnr *serialnr)
{