summaryrefslogtreecommitdiff
path: root/arch
diff options
context:
space:
mode:
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/dts/imx95-19x19-evk-u-boot.dtsi62
-rw-r--r--arch/arm/dts/imx95-u-boot.dtsi188
-rw-r--r--arch/arm/include/asm/arch-imx/cpu.h2
-rw-r--r--arch/arm/include/asm/arch-imx9/clock.h10
-rw-r--r--arch/arm/include/asm/arch-imx9/imx-regs.h6
-rw-r--r--arch/arm/include/asm/arch-imx9/sys_proto.h1
-rw-r--r--arch/arm/include/asm/mach-imx/sys_proto.h39
-rw-r--r--arch/arm/mach-imx/Kconfig2
-rw-r--r--arch/arm/mach-imx/image-container.c119
-rw-r--r--arch/arm/mach-imx/imx9/Kconfig15
-rw-r--r--arch/arm/mach-imx/imx9/Makefile9
-rw-r--r--arch/arm/mach-imx/imx9/scmi/Makefile6
-rw-r--r--arch/arm/mach-imx/imx9/scmi/clock.c70
-rw-r--r--arch/arm/mach-imx/imx9/scmi/clock_scmi.c133
-rw-r--r--arch/arm/mach-imx/imx9/scmi/container.cfg10
-rw-r--r--arch/arm/mach-imx/imx9/scmi/imximage.cfg15
-rw-r--r--arch/arm/mach-imx/imx9/scmi/soc.c749
-rw-r--r--arch/sandbox/include/asm/scmi_test.h4
18 files changed, 1412 insertions, 28 deletions
diff --git a/arch/arm/dts/imx95-19x19-evk-u-boot.dtsi b/arch/arm/dts/imx95-19x19-evk-u-boot.dtsi
new file mode 100644
index 00000000000..2d1f02baa5f
--- /dev/null
+++ b/arch/arm/dts/imx95-19x19-evk-u-boot.dtsi
@@ -0,0 +1,62 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2025 NXP
+ */
+
+#include "imx95-u-boot.dtsi"
+
+&lpuart1 {
+ bootph-pre-ram;
+};
+
+&reg_usdhc2_vmmc {
+ bootph-pre-ram;
+};
+
+&usdhc1 {
+ bootph-pre-ram;
+};
+
+&usdhc2 {
+ bootph-pre-ram;
+};
+
+&wdog3 {
+ status = "disabled";
+};
+
+&pinctrl_uart1 {
+ bootph-pre-ram;
+};
+
+&pinctrl_usdhc1 {
+ bootph-pre-ram;
+};
+
+&pinctrl_usdhc1_100mhz {
+ bootph-pre-ram;
+};
+
+&pinctrl_usdhc1_200mhz {
+ bootph-pre-ram;
+};
+
+&pinctrl_usdhc2 {
+ bootph-pre-ram;
+};
+
+&pinctrl_usdhc2_100mhz {
+ bootph-pre-ram;
+};
+
+&pinctrl_usdhc2_200mhz {
+ bootph-pre-ram;
+};
+
+&pinctrl_usdhc2_gpio {
+ bootph-pre-ram;
+};
+
+&pinctrl_reg_usdhc2_vmmc {
+ bootph-pre-ram;
+};
diff --git a/arch/arm/dts/imx95-u-boot.dtsi b/arch/arm/dts/imx95-u-boot.dtsi
new file mode 100644
index 00000000000..5ec3b1c51d6
--- /dev/null
+++ b/arch/arm/dts/imx95-u-boot.dtsi
@@ -0,0 +1,188 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2025 NXP
+ */
+
+/ {
+ binman {
+ multiple-images;
+
+ m33-oei-ddrfw {
+ pad-byte = <0x00>;
+ align-size = <0x8>;
+ filename = "m33-oei-ddrfw.bin";
+
+ oei-m33-ddr {
+ align-size = <0x4>;
+ filename = "oei-m33-ddr.bin";
+ type = "blob-ext";
+ };
+
+ imx-lpddr {
+ type = "nxp-header-ddrfw";
+
+ imx-lpddr-imem {
+ filename = "lpddr5_imem_v202311.bin";
+ type = "blob-ext";
+ };
+
+ imx-lpddr-dmem {
+ filename = "lpddr5_dmem_v202311.bin";
+ type = "blob-ext";
+ };
+ };
+
+ imx-lpddr-qb {
+ type = "nxp-header-ddrfw";
+
+ imx-lpddr-imem-qb {
+ filename = "lpddr5_imem_qb_v202311.bin";
+ type = "blob-ext";
+ };
+
+ imx-lpddr-dmem-qb {
+ filename = "lpddr5_dmem_qb_v202311.bin";
+ type = "blob-ext";
+ };
+ };
+ };
+
+ imx-boot {
+ filename = "flash.bin";
+ pad-byte = <0x00>;
+
+ spl {
+ align = <0x400>;
+ align-size = <0x400>;
+ type = "mkimage";
+ args = "-n spl/u-boot-spl.cfgout -T imx8image";
+ };
+
+ u-boot {
+ type = "mkimage";
+ args = "-n u-boot-container.cfgout -T imx8image";
+ };
+ };
+ };
+};
+
+&A55_0 {
+ clocks = <&scmi_clk IMX95_CLK_ARMPLL_PFD0>;
+ /delete-property/ power-domains;
+};
+
+&A55_1 {
+ clocks = <&scmi_clk IMX95_CLK_ARMPLL_PFD0>;
+ /delete-property/ power-domains;
+};
+
+&A55_2 {
+ clocks = <&scmi_clk IMX95_CLK_ARMPLL_PFD0>;
+ /delete-property/ power-domains;
+};
+
+&A55_3 {
+ clocks = <&scmi_clk IMX95_CLK_ARMPLL_PFD0>;
+ /delete-property/ power-domains;
+};
+
+&A55_4 {
+ clocks = <&scmi_clk IMX95_CLK_ARMPLL_PFD0>;
+ /delete-property/ power-domains;
+};
+
+&A55_5 {
+ clocks = <&scmi_clk IMX95_CLK_ARMPLL_PFD0>;
+ /delete-property/ power-domains;
+};
+
+&aips1 {
+ bootph-all;
+};
+
+&aips2 {
+ bootph-all;
+};
+
+&aips3 {
+ bootph-pre-ram;
+};
+
+&clk_ext1 {
+ bootph-all;
+};
+
+&elemu1 {
+ bootph-all;
+ status = "okay";
+};
+
+&elemu3 {
+ bootph-all;
+ status = "okay";
+};
+
+&{/firmware} {
+ bootph-all;
+};
+
+&{/firmware/scmi} {
+ bootph-all;
+};
+
+&{/firmware/scmi/protocol@11} {
+ bootph-all;
+};
+
+&{/firmware/scmi/protocol@13} {
+ bootph-all;
+};
+
+&{/firmware/scmi/protocol@14} {
+ bootph-all;
+};
+
+&{/firmware/scmi/protocol@19} {
+ bootph-all;
+};
+
+&gpio2 {
+ bootph-pre-ram;
+};
+
+&gpio3 {
+ bootph-pre-ram;
+};
+
+&gpio4 {
+ bootph-pre-ram;
+};
+
+&gpio5 {
+ bootph-pre-ram;
+};
+
+&mu2 {
+ bootph-all;
+};
+
+&osc_24m {
+ bootph-all;
+};
+
+&{/soc} {
+ bootph-all;
+};
+
+&sram0 {
+ bootph-all;
+};
+
+&scmi_buf0 {
+ reg = <0x0 0x400>;
+ bootph-all;
+};
+
+&scmi_buf1 {
+ bootph-all;
+};
diff --git a/arch/arm/include/asm/arch-imx/cpu.h b/arch/arm/include/asm/arch-imx/cpu.h
index 0d7a5734616..1f669c72d00 100644
--- a/arch/arm/include/asm/arch-imx/cpu.h
+++ b/arch/arm/include/asm/arch-imx/cpu.h
@@ -76,6 +76,8 @@
#define MXC_CPU_IMX9111 0xCD /* dummy ID */
#define MXC_CPU_IMX9101 0xCE /* dummy ID */
+#define MXC_CPU_IMX95 0x1C1 /* dummy ID */
+
#define MXC_SOC_MX6 0x60
#define MXC_SOC_MX7 0x70
#define MXC_SOC_IMX8M 0x80
diff --git a/arch/arm/include/asm/arch-imx9/clock.h b/arch/arm/include/asm/arch-imx9/clock.h
index 60d48b13b11..ffaf6b5f7d8 100644
--- a/arch/arm/include/asm/arch-imx9/clock.h
+++ b/arch/arm/include/asm/arch-imx9/clock.h
@@ -255,5 +255,15 @@ int ccm_shared_gpr_tz_access(u32 gpr, bool non_secure, bool user_mode, bool lock
void enable_usboh3_clk(unsigned char enable);
int set_clk_enet(enum enet_freq type);
int set_clk_eqos(enum enet_freq type);
+
+int imx_clk_scmi_enable(u32 clock_id, bool enable);
+ulong imx_clk_scmi_set_rate(u32 clock_id, ulong rate);
+ulong imx_clk_scmi_get_rate(u32 clock_id);
+int imx_clk_scmi_set_parent(u32 clock_id, u32 parent_id);
void set_arm_clk(ulong freq);
+
+int imx_clk_scmi_enable(u32 clock_id, bool enable);
+ulong imx_clk_scmi_set_rate(u32 clock_id, ulong rate);
+ulong imx_clk_scmi_get_rate(u32 clock_id);
+int imx_clk_scmi_set_parent(u32 clock_id, u32 parent_id);
#endif
diff --git a/arch/arm/include/asm/arch-imx9/imx-regs.h b/arch/arm/include/asm/arch-imx9/imx-regs.h
index ef9538bd42e..5127fe8f286 100644
--- a/arch/arm/include/asm/arch-imx9/imx-regs.h
+++ b/arch/arm/include/asm/arch-imx9/imx-regs.h
@@ -13,6 +13,7 @@
#define CCM_BASE_ADDR 0x44450000UL
#define CCM_CCGR_BASE_ADDR 0x44458000UL
#define SYSCNT_CTRL_BASE_ADDR 0x44290000
+#define SYSCNT_CMP_BASE_ADDR (SYSCNT_CTRL_BASE_ADDR + 0x10000)
#define ANATOP_BASE_ADDR 0x44480000UL
@@ -20,6 +21,11 @@
#define WDG4_BASE_ADDR 0x424a0000UL
#define WDG5_BASE_ADDR 0x424b0000UL
+#define GPIO2_BASE_ADDR 0x43810000UL
+#define GPIO3_BASE_ADDR 0x43820000UL
+#define GPIO4_BASE_ADDR 0x43840000UL
+#define GPIO5_BASE_ADDR 0x43850000UL
+
#define FSB_BASE_ADDR 0x47510000UL
#define ANATOP_BASE_ADDR 0x44480000UL
diff --git a/arch/arm/include/asm/arch-imx9/sys_proto.h b/arch/arm/include/asm/arch-imx9/sys_proto.h
index e4bf6a63424..df2148a53c7 100644
--- a/arch/arm/include/asm/arch-imx9/sys_proto.h
+++ b/arch/arm/include/asm/arch-imx9/sys_proto.h
@@ -12,6 +12,7 @@ enum imx9_soc_voltage_mode {
VOLT_LOW_DRIVE = 0,
VOLT_NOMINAL_DRIVE,
VOLT_OVER_DRIVE,
+ VOLT_SUPER_OVER_DRIVE,
};
void soc_power_init(void);
diff --git a/arch/arm/include/asm/mach-imx/sys_proto.h b/arch/arm/include/asm/mach-imx/sys_proto.h
index 109a806852a..0780f99b49a 100644
--- a/arch/arm/include/asm/mach-imx/sys_proto.h
+++ b/arch/arm/include/asm/mach-imx/sys_proto.h
@@ -97,6 +97,8 @@ struct bd_info;
#define is_imx9302() (is_cpu_type(MXC_CPU_IMX9302))
#define is_imx9301() (is_cpu_type(MXC_CPU_IMX9301))
+#define is_imx95() (is_cpu_type(MXC_CPU_IMX95))
+
#define is_imx9121() (is_cpu_type(MXC_CPU_IMX9121))
#define is_imx9111() (is_cpu_type(MXC_CPU_IMX9111))
#define is_imx9101() (is_cpu_type(MXC_CPU_IMX9101))
@@ -216,6 +218,43 @@ ulong spl_romapi_get_uboot_base(u32 image_offset, u32 rom_bt_dev);
u32 rom_api_download_image(u8 *dest, u32 offset, u32 size);
u32 rom_api_query_boot_infor(u32 info_type, u32 *info);
+#if IS_ENABLED(CONFIG_SCMI_FIRMWARE)
+typedef struct rom_passover {
+ u16 tag; // Tag
+ u8 len; // Fixed value of 0x80
+ u8 ver; // Version
+ u32 boot_mode; // Boot mode
+ u32 card_addr_mode; // SD card address mode
+ u32 bad_blks_of_img_set0; // NAND bad block count skipped 1
+ u32 ap_mu_id; // AP MU ID
+ u32 bad_blks_of_img_set1; // NAND bad block count skipped 1
+ u8 boot_stage; // Boot stage
+ u8 img_set_sel; // Image set booted from
+ u8 rsv0[2]; // Reserved
+ u32 img_set_end; // Offset of Image End
+ u32 rom_version; // ROM version
+ u8 boot_dev_state; // Boot device state
+ u8 boot_dev_inst; // Boot device type
+ u8 boot_dev_type; // Boot device instance
+ u8 rsv1; // Reserved
+ u32 dev_page_size; // Boot device page size
+ u32 cnt_header_ofs; // Container header offset
+ u32 img_ofs; // Image offset
+} __packed rom_passover_t;
+
+/**
+ * struct scmi_rom_passover_out - Response payload for ROM_PASSOVER_GET command
+ * @status: SCMI clock ID
+ * @attributes: Attributes of the targets clock state
+ */
+struct scmi_rom_passover_get_out {
+ u32 status;
+ u32 numPassover;
+ u32 passover[(sizeof(rom_passover_t) + 8) / 4];
+};
+
+#endif
+
/* For i.MX ULP */
#define BT0CFG_LPBOOT_MASK 0x1
#define BT0CFG_DUALBOOT_MASK 0x2
diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
index 134e42028c3..e4014226582 100644
--- a/arch/arm/mach-imx/Kconfig
+++ b/arch/arm/mach-imx/Kconfig
@@ -180,7 +180,7 @@ config DDRMC_VF610_CALIBRATION
config IMX8_ROMAPI
def_bool y
- depends on IMX8MN || IMX8MP || IMX8ULP || IMX9
+ depends on IMX8MN || IMX8MP || IMX8ULP || IMX91 || IMX93
config SPL_IMX_ROMAPI_LOADADDR
hex "Default load address to load image through ROM API"
diff --git a/arch/arm/mach-imx/image-container.c b/arch/arm/mach-imx/image-container.c
index 2afe9d38a06..f84e23f4b2a 100644
--- a/arch/arm/mach-imx/image-container.c
+++ b/arch/arm/mach-imx/image-container.c
@@ -41,6 +41,52 @@
#define FUSE_IMG_SET_OFF_WORD 720
#endif
+#define MAX_V2X_CTNR_IMG_NUM (4)
+#define MIN_V2X_CTNR_IMG_NUM (2)
+
+#define IMG_FLAGS_IMG_TYPE_SHIFT (0u)
+#define IMG_FLAGS_IMG_TYPE_MASK (0xfU)
+#define IMG_FLAGS_IMG_TYPE(x) (((x) & IMG_FLAGS_IMG_TYPE_MASK) >> \
+ IMG_FLAGS_IMG_TYPE_SHIFT)
+
+#define IMG_FLAGS_CORE_ID_SHIFT (4u)
+#define IMG_FLAGS_CORE_ID_MASK (0xf0U)
+#define IMG_FLAGS_CORE_ID(x) (((x) & IMG_FLAGS_CORE_ID_MASK) >> \
+ IMG_FLAGS_CORE_ID_SHIFT)
+
+#define IMG_TYPE_V2X_PRI_FW (0x0Bu) /* Primary V2X FW */
+#define IMG_TYPE_V2X_SND_FW (0x0Cu) /* Secondary V2X FW */
+
+#define CORE_V2X_PRI 9
+#define CORE_V2X_SND 10
+
+static bool is_v2x_fw_container(ulong addr)
+{
+ struct container_hdr *phdr;
+ struct boot_img_t *img_entry;
+
+ phdr = (struct container_hdr *)addr;
+ if (phdr->tag != 0x87 || phdr->version != 0x0) {
+ debug("Wrong container header\n");
+ return false;
+ }
+
+ if (phdr->num_images >= MIN_V2X_CTNR_IMG_NUM && phdr->num_images <= MAX_V2X_CTNR_IMG_NUM) {
+ img_entry = (struct boot_img_t *)(addr + sizeof(struct container_hdr));
+
+ if (IMG_FLAGS_IMG_TYPE(img_entry->hab_flags) == IMG_TYPE_V2X_PRI_FW &&
+ IMG_FLAGS_CORE_ID(img_entry->hab_flags) == CORE_V2X_PRI) {
+ img_entry++;
+
+ if (IMG_FLAGS_IMG_TYPE(img_entry->hab_flags) == IMG_TYPE_V2X_SND_FW &&
+ IMG_FLAGS_CORE_ID(img_entry->hab_flags) == CORE_V2X_SND)
+ return true;
+ }
+ }
+
+ return false;
+}
+
int get_container_size(ulong addr, u16 *header_length)
{
struct container_hdr *phdr;
@@ -83,7 +129,7 @@ int get_container_size(ulong addr, u16 *header_length)
return max_offset;
}
-static int get_dev_container_size(void *dev, int dev_type, unsigned long offset, u16 *header_length)
+static int get_dev_container_size(void *dev, int dev_type, unsigned long offset, u16 *header_length, bool *v2x_cntr)
{
u8 *buf = malloc(CONTAINER_HDR_ALIGNMENT);
int ret = 0;
@@ -150,6 +196,9 @@ static int get_dev_container_size(void *dev, int dev_type, unsigned long offset,
ret = get_container_size((ulong)buf, header_length);
+ if (v2x_cntr)
+ *v2x_cntr = is_v2x_fw_container((ulong)buf);
+
free(buf);
return ret;
@@ -231,45 +280,67 @@ static unsigned long get_boot_device_offset(void *dev, int dev_type)
return offset;
}
-static int get_imageset_end(void *dev, int dev_type)
+static ulong get_imageset_end(void *dev, int dev_type)
{
- unsigned long offset1 = 0, offset2 = 0;
- int value_container[2];
+ unsigned long offset[3] = {};
+ int value_container[3] = {};
u16 hdr_length;
+ bool v2x_fw = false;
- offset1 = get_boot_device_offset(dev, dev_type);
- offset2 = CONTAINER_HDR_ALIGNMENT + offset1;
+ offset[0] = get_boot_device_offset(dev, dev_type);
- value_container[0] = get_dev_container_size(dev, dev_type, offset1, &hdr_length);
+ value_container[0] = get_dev_container_size(dev, dev_type, offset[0], &hdr_length, NULL);
if (value_container[0] < 0) {
printf("Parse seco container failed %d\n", value_container[0]);
- return value_container[0];
+ return 0;
}
debug("seco container size 0x%x\n", value_container[0]);
- value_container[1] = get_dev_container_size(dev, dev_type, offset2, &hdr_length);
- if (value_container[1] < 0) {
- debug("Parse scu container failed %d, only seco container\n",
- value_container[1]);
- /* return seco container total size */
- return value_container[0] + offset1;
+ if (is_imx95()) {
+ offset[1] = ALIGN(hdr_length, CONTAINER_HDR_ALIGNMENT) + offset[0];
+
+ value_container[1] = get_dev_container_size(dev, dev_type, offset[1], &hdr_length, &v2x_fw);
+ if (value_container[1] < 0) {
+ printf("Parse v2x container failed %d\n", value_container[1]);
+ return value_container[0] + offset[0]; /* return seco container total size */
+ }
+
+ if (v2x_fw) {
+ debug("v2x container size 0x%x\n", value_container[1]);
+ offset[2] = ALIGN(hdr_length, CONTAINER_HDR_ALIGNMENT) + offset[1];
+ } else {
+ printf("no v2x container included\n");
+ offset[2] = offset[1];
+ }
+ } else {
+ /* Skip offset[1] */
+ offset[2] = ALIGN(hdr_length, CONTAINER_HDR_ALIGNMENT) + offset[0];
+ }
+
+ value_container[2] = get_dev_container_size(dev, dev_type, offset[2], &hdr_length, NULL);
+ if (value_container[2] < 0) {
+ debug("Parse scu container image failed %d, only seco container\n", value_container[2]);
+ if (is_imx95())
+ return value_container[1] + offset[1]; /* return seco + v2x container total size */
+ else
+ return value_container[0] + offset[0]; /* return seco container total size */
}
- debug("scu container size 0x%x\n", value_container[1]);
+ debug("scu container size 0x%x\n", value_container[2]);
- return value_container[1] + offset2;
+ return value_container[2] + offset[2];
}
#ifdef CONFIG_SPL_SPI_LOAD
unsigned int spl_spi_get_uboot_offs(struct spi_flash *flash)
{
- int end;
+ ulong end;
end = get_imageset_end(flash, QSPI_DEV);
end = ROUND(end, SZ_1K);
- printf("Load image from QSPI 0x%x\n", end);
+ printf("Load image from QSPI 0x%lx\n", end);
return end;
}
@@ -279,12 +350,12 @@ unsigned int spl_spi_get_uboot_offs(struct spi_flash *flash)
unsigned long arch_spl_mmc_get_uboot_raw_sector(struct mmc *mmc,
unsigned long raw_sect)
{
- int end;
+ ulong end;
end = get_imageset_end(mmc, MMC_DEV);
end = ROUND(end, SZ_1K);
- printf("Load image from MMC/SD 0x%x\n", end);
+ printf("Load image from MMC/SD 0x%lx\n", end);
return end / mmc->read_bl_len;
}
@@ -312,12 +383,12 @@ int spl_mmc_emmc_boot_partition(struct mmc *mmc)
#ifdef CONFIG_SPL_NAND_SUPPORT
uint32_t spl_nand_get_uboot_raw_page(void)
{
- int end;
+ ulong end;
end = get_imageset_end((void *)NULL, NAND_DEV);
end = ROUND(end, SZ_16K);
- printf("Load image from NAND 0x%x\n", end);
+ printf("Load image from NAND 0x%lx\n", end);
return end;
}
@@ -326,7 +397,7 @@ uint32_t spl_nand_get_uboot_raw_page(void)
#ifdef CONFIG_SPL_NOR_SUPPORT
unsigned long spl_nor_get_uboot_base(void)
{
- int end;
+ ulong end;
/* Calculate the image set end,
* if it is less than CFG_SYS_UBOOT_BASE(0x8281000),
@@ -339,7 +410,7 @@ unsigned long spl_nor_get_uboot_base(void)
else
end = ROUND(end, SZ_1K);
- printf("Load image from NOR 0x%x\n", end);
+ printf("Load image from NOR 0x%lx\n", end);
return end;
}
diff --git a/arch/arm/mach-imx/imx9/Kconfig b/arch/arm/mach-imx/imx9/Kconfig
index 1ccdb1cf64f..0fd82dc0811 100644
--- a/arch/arm/mach-imx/imx9/Kconfig
+++ b/arch/arm/mach-imx/imx9/Kconfig
@@ -24,6 +24,13 @@ config IMX91
select IMX9
select ARMV8_SPL_EXCEPTION_VECTORS
+config IMX95
+ bool
+ select ARMV8_SPL_EXCEPTION_VECTORS
+ select IMX9
+ select DM_MAILBOX
+ select SCMI_FIRMWARE
+ select SPL_IMX_CONTAINER_USE_TRAMPOLINE
config SYS_SOC
default "imx9"
@@ -69,6 +76,13 @@ config TARGET_PHYCORE_IMX93
select OF_BOARD_FIXUP
select OF_BOARD_SETUP
+config TARGET_IMX95_19X19_EVK
+ bool "imx95_19x19_evk"
+ select IMX95
+ imply BOOTSTD_BOOTCOMMAND
+ imply BOOTSTD_FULL
+ imply OF_UPSTREAM
+
endchoice
source "board/freescale/imx91_evk/Kconfig"
@@ -76,6 +90,7 @@ source "board/freescale/imx93_evk/Kconfig"
source "board/freescale/imx93_qsb/Kconfig"
source "board/phytec/phycore_imx93/Kconfig"
source "board/variscite/imx93_var_som/Kconfig"
+source "board/freescale/imx95_evk/Kconfig"
endif
diff --git a/arch/arm/mach-imx/imx9/Makefile b/arch/arm/mach-imx/imx9/Makefile
index 45a9105a75a..53cc97c6b47 100644
--- a/arch/arm/mach-imx/imx9/Makefile
+++ b/arch/arm/mach-imx/imx9/Makefile
@@ -3,8 +3,13 @@
# Copyright 2022 NXP
obj-y += lowlevel_init.o
+
+ifeq ($(CONFIG_SCMI_FIRMWARE),y)
+obj-y += scmi/
+else
obj-y += soc.o clock.o clock_root.o trdc.o
+endif
-#ifndef CONFIG_XPL_BUILD
+ifneq ($(CONFIG_SPL_BUILD),y)
obj-y += imx_bootaux.o
-#endif
+endif \ No newline at end of file
diff --git a/arch/arm/mach-imx/imx9/scmi/Makefile b/arch/arm/mach-imx/imx9/scmi/Makefile
new file mode 100644
index 00000000000..4534db08d28
--- /dev/null
+++ b/arch/arm/mach-imx/imx9/scmi/Makefile
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright 2025 NXP
+
+obj-y += soc.o
+obj-y += clock_scmi.o clock.o
diff --git a/arch/arm/mach-imx/imx9/scmi/clock.c b/arch/arm/mach-imx/imx9/scmi/clock.c
new file mode 100644
index 00000000000..6e6541eaa31
--- /dev/null
+++ b/arch/arm/mach-imx/imx9/scmi/clock.c
@@ -0,0 +1,70 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2025 NXP
+ */
+
+#include <asm/arch/clock.h>
+#include <dm/uclass.h>
+#include <scmi_agent.h>
+#include "../../../../../dts/upstream/src/arm64/freescale/imx95-clock.h"
+
+u32 get_arm_core_clk(void)
+{
+ u32 val;
+
+ val = imx_clk_scmi_get_rate(IMX95_CLK_SEL_A55C0);
+ if (val)
+ return val;
+ return imx_clk_scmi_get_rate(IMX95_CLK_A55);
+}
+
+void init_uart_clk(u32 index)
+{
+ u32 clock_id;
+
+ switch (index) {
+ case 0:
+ clock_id = IMX95_CLK_LPUART1;
+ break;
+ case 1:
+ clock_id = IMX95_CLK_LPUART2;
+ break;
+ case 2:
+ clock_id = IMX95_CLK_LPUART3;
+ break;
+ default:
+ return;
+ }
+
+ /* 24MHz */
+ imx_clk_scmi_enable(clock_id, false);
+ imx_clk_scmi_set_parent(clock_id, IMX95_CLK_24M);
+ imx_clk_scmi_set_rate(clock_id, 24000000);
+ imx_clk_scmi_enable(clock_id, true);
+}
+
+unsigned int mxc_get_clock(enum mxc_clock clk)
+{
+ switch (clk) {
+ case MXC_ARM_CLK:
+ return get_arm_core_clk();
+ case MXC_IPG_CLK:
+ return imx_clk_scmi_get_rate(IMX95_CLK_BUSWAKEUP);
+ case MXC_CSPI_CLK:
+ return imx_clk_scmi_get_rate(IMX95_CLK_LPSPI1);
+ case MXC_ESDHC_CLK:
+ return imx_clk_scmi_get_rate(IMX95_CLK_USDHC1);
+ case MXC_ESDHC2_CLK:
+ return imx_clk_scmi_get_rate(IMX95_CLK_USDHC2);
+ case MXC_ESDHC3_CLK:
+ return imx_clk_scmi_get_rate(IMX95_CLK_USDHC3);
+ case MXC_UART_CLK:
+ return imx_clk_scmi_get_rate(IMX95_CLK_LPUART1);
+ case MXC_FLEXSPI_CLK:
+ return imx_clk_scmi_get_rate(IMX95_CLK_FLEXSPI1);
+ default:
+ return -1;
+ };
+
+ return -1;
+};
diff --git a/arch/arm/mach-imx/imx9/scmi/clock_scmi.c b/arch/arm/mach-imx/imx9/scmi/clock_scmi.c
new file mode 100644
index 00000000000..fa15b5f8df9
--- /dev/null
+++ b/arch/arm/mach-imx/imx9/scmi/clock_scmi.c
@@ -0,0 +1,133 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2025 NXP
+ *
+ * Peng Fan <peng.fan@nxp.com>
+ */
+
+#include <dm/uclass.h>
+#include <scmi_agent.h>
+
+int imx_clk_scmi_enable(u32 clock_id, bool enable)
+{
+ struct scmi_clk_state_in in = {
+ .clock_id = clock_id,
+ .attributes = (enable) ? 1 : 0,
+ };
+ struct scmi_clk_state_out out;
+ struct scmi_msg msg = SCMI_MSG_IN(SCMI_PROTOCOL_ID_CLOCK,
+ SCMI_CLOCK_CONFIG_SET,
+ in, out);
+ int ret;
+ struct udevice *dev;
+
+ ret = uclass_get_device_by_name(UCLASS_CLK, "protocol@14", &dev);
+ if (ret)
+ return ret;
+
+ ret = devm_scmi_process_msg(dev, &msg);
+ if (ret)
+ return ret;
+
+ return scmi_to_linux_errno(out.status);
+}
+
+ulong imx_clk_scmi_set_rate(u32 clock_id, ulong rate)
+{
+ struct scmi_clk_rate_set_in in = {
+ .clock_id = clock_id,
+ .flags = SCMI_CLK_RATE_ROUND_CLOSEST,
+ .rate_lsb = (u32)rate,
+ .rate_msb = (u32)((u64)rate >> 32),
+ };
+ struct scmi_clk_rate_set_out out;
+ struct scmi_msg msg = SCMI_MSG_IN(SCMI_PROTOCOL_ID_CLOCK,
+ SCMI_CLOCK_RATE_SET,
+ in, out);
+ int ret;
+ struct udevice *dev;
+
+ ret = uclass_get_device_by_name(UCLASS_CLK, "protocol@14", &dev);
+ if (ret)
+ return ret;
+
+ ret = devm_scmi_process_msg(dev, &msg);
+ if (ret < 0)
+ return ret;
+
+ ret = scmi_to_linux_errno(out.status);
+ if (ret < 0)
+ return ret;
+
+ struct scmi_clk_rate_get_in in_rate = {
+ .clock_id = clock_id,
+ };
+ struct scmi_clk_rate_get_out out_rate;
+
+ msg = SCMI_MSG_IN(SCMI_PROTOCOL_ID_CLOCK, SCMI_CLOCK_RATE_GET, in_rate, out_rate);
+
+ ret = devm_scmi_process_msg(dev, &msg);
+ if (ret < 0)
+ return ret;
+
+ ret = scmi_to_linux_errno(out_rate.status);
+ if (ret < 0)
+ return ret;
+
+ return (ulong)(((u64)out_rate.rate_msb << 32) | out_rate.rate_lsb);
+}
+
+ulong imx_clk_scmi_get_rate(u32 clock_id)
+{
+ struct scmi_clk_rate_get_in in = {
+ .clock_id = clock_id,
+ };
+ struct scmi_clk_rate_get_out out;
+ struct scmi_msg msg = SCMI_MSG_IN(SCMI_PROTOCOL_ID_CLOCK,
+ SCMI_CLOCK_RATE_GET,
+ in, out);
+ int ret;
+ struct udevice *dev;
+
+ ret = uclass_get_device_by_name(UCLASS_CLK, "protocol@14", &dev);
+ if (ret)
+ return ret;
+
+ ret = devm_scmi_process_msg(dev, &msg);
+ if (ret < 0)
+ return ret;
+
+ ret = scmi_to_linux_errno(out.status);
+ if (ret < 0)
+ return ret;
+
+ return (ulong)(((u64)out.rate_msb << 32) | out.rate_lsb);
+}
+
+int imx_clk_scmi_set_parent(u32 clock_id, u32 parent_id)
+{
+ struct scmi_clk_parent_set_in in = {
+ .clock_id = clock_id,
+ .parent_clk = parent_id,
+ };
+ struct scmi_clk_parent_set_out out;
+ struct scmi_msg msg = SCMI_MSG_IN(SCMI_PROTOCOL_ID_CLOCK,
+ SCMI_CLOCK_PARENT_SET,
+ in, out);
+ int ret;
+ struct udevice *dev;
+
+ ret = uclass_get_device_by_name(UCLASS_CLK, "protocol@14", &dev);
+ if (ret)
+ return ret;
+
+ ret = devm_scmi_process_msg(dev, &msg);
+ if (ret < 0)
+ return ret;
+
+ ret = scmi_to_linux_errno(out.status);
+ if (ret < 0 && ret != -EACCES)
+ printf("%s: %d, clock_id %u\n", __func__, ret, clock_id);
+
+ return ret;
+}
diff --git a/arch/arm/mach-imx/imx9/scmi/container.cfg b/arch/arm/mach-imx/imx9/scmi/container.cfg
new file mode 100644
index 00000000000..441d9beedd1
--- /dev/null
+++ b/arch/arm/mach-imx/imx9/scmi/container.cfg
@@ -0,0 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2025 NXP
+ */
+
+BOOT_FROM SD
+SOC_TYPE IMX9
+CONTAINER
+IMAGE A55 bl31.bin 0x8a200000
+IMAGE A55 u-boot.bin CONFIG_TEXT_BASE
diff --git a/arch/arm/mach-imx/imx9/scmi/imximage.cfg b/arch/arm/mach-imx/imx9/scmi/imximage.cfg
new file mode 100644
index 00000000000..6af1c4ba628
--- /dev/null
+++ b/arch/arm/mach-imx/imx9/scmi/imximage.cfg
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2025 NXP
+ */
+
+BOOT_FROM SD
+SOC_TYPE IMX9
+APPEND mx95a0-ahab-container.img
+CONTAINER
+IMAGE OEI m33-oei-ddrfw.bin 0x1ffc0000
+HOLD 0x10000
+IMAGE OEI oei-m33-tcm.bin 0x1ffc0000
+IMAGE M33 m33_image.bin 0x1ffc0000
+IMAGE A55 spl/u-boot-spl.bin 0x20480000
+DUMMY_V2X 0x8b000000
diff --git a/arch/arm/mach-imx/imx9/scmi/soc.c b/arch/arm/mach-imx/imx9/scmi/soc.c
new file mode 100644
index 00000000000..d2b0455bff9
--- /dev/null
+++ b/arch/arm/mach-imx/imx9/scmi/soc.c
@@ -0,0 +1,749 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2025 NXP
+ *
+ * Peng Fan <peng.fan@nxp.com>
+ */
+
+#include <asm/arch/clock.h>
+#include <asm/arch/ddr.h>
+#include <asm/arch/sys_proto.h>
+#include <asm/armv8/mmu.h>
+#include <asm/mach-imx/boot_mode.h>
+#include <asm/mach-imx/ele_api.h>
+#include <asm/setup.h>
+#include <dm/uclass.h>
+#include <dm/device.h>
+#include <env_internal.h>
+#include <fuse.h>
+#include <imx_thermal.h>
+#include <linux/iopoll.h>
+#include <scmi_agent.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static rom_passover_t rom_passover_data = {0};
+
+uint32_t scmi_get_rom_data(rom_passover_t *rom_data)
+{
+ /* Read ROM passover data */
+ struct scmi_rom_passover_get_out out;
+ struct scmi_msg msg = {
+ .protocol_id = SCMI_PROTOCOL_ID_IMX_MISC,
+ .message_id = SCMI_MISC_ROM_PASSOVER_GET,
+ .in_msg = (u8 *)NULL,
+ .in_msg_sz = 0,
+ .out_msg = (u8 *)&out,
+ .out_msg_sz = sizeof(out),
+ };
+ int ret;
+ struct udevice *dev;
+
+ ret = uclass_get_device_by_name(UCLASS_CLK, "protocol@14", &dev);
+ if (ret)
+ return ret;
+
+ ret = devm_scmi_process_msg(dev, &msg);
+ if (ret == 0 && out.status == 0) {
+ memcpy(rom_data, (struct rom_passover_t *)out.passover, sizeof(rom_passover_t));
+ } else {
+ printf("Failed to get ROM passover data, scmi_err = %d, size_of(out) = %ld\n",
+ out.status, sizeof(out));
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+#if IS_ENABLED(CONFIG_ENV_IS_IN_MMC)
+__weak int board_mmc_get_env_dev(int devno)
+{
+ return devno;
+}
+
+int mmc_get_env_dev(void)
+{
+ int ret;
+ u16 boot_type;
+ u8 boot_instance;
+
+ volatile gd_t *pgd = gd;
+ rom_passover_t *rdata;
+
+#if IS_ENABLED(CONFIG_XPL_BUILD)
+ rdata = &rom_passover_data;
+#else
+ rom_passover_t rom_data = {0};
+
+ if (!pgd->reloc_off)
+ rdata = &rom_data;
+ else
+ rdata = &rom_passover_data;
+#endif
+ if (rdata->tag == 0) {
+ ret = scmi_get_rom_data(rdata);
+ if (ret != 0) {
+ puts("SCMI: failure at rom_boot_info\n");
+ return CONFIG_SYS_MMC_ENV_DEV;
+ }
+ }
+ boot_type = rdata->boot_dev_type;
+ boot_instance = rdata->boot_dev_inst;
+ set_gd(pgd);
+
+ debug("boot_type %d, instance %d\n", boot_type, boot_instance);
+
+ /* If not boot from sd/mmc, use default value */
+ if (boot_type != BOOT_TYPE_SD && boot_type != BOOT_TYPE_MMC)
+ return env_get_ulong("mmcdev", 10, CONFIG_SYS_MMC_ENV_DEV);
+
+ return board_mmc_get_env_dev(boot_instance);
+}
+#endif
+
+u32 get_cpu_speed_grade_hz(void)
+{
+ u32 speed, max_speed;
+ int ret;
+ u32 val, word, offset;
+
+ word = 17;
+ offset = 14;
+
+ ret = fuse_read(word / 8, word % 8, &val);
+ if (ret)
+ val = 0; /* If read fuse failed, return as blank fuse */
+
+ val >>= offset;
+ val &= 0xf;
+
+ max_speed = 2300000000;
+ speed = max_speed - val * 100000000;
+
+ if (is_imx95())
+ max_speed = 2000000000;
+
+ /* In case the fuse of speed grade not programmed */
+ if (speed > max_speed)
+ speed = max_speed;
+
+ return speed;
+}
+
+u32 get_cpu_temp_grade(int *minc, int *maxc)
+{
+ int ret;
+ u32 val, word, offset;
+
+ word = 17;
+ offset = 12;
+
+ ret = fuse_read(word / 8, word % 8, &val);
+ if (ret)
+ val = 0; /* If read fuse failed, return as blank fuse */
+
+ val >>= offset;
+ val &= 0x3;
+
+ if (minc && maxc) {
+ if (val == TEMP_AUTOMOTIVE) {
+ *minc = -40;
+ *maxc = 125;
+ } else if (val == TEMP_INDUSTRIAL) {
+ *minc = -40;
+ *maxc = 105;
+ } else if (val == TEMP_EXTCOMMERCIAL) {
+ *minc = -20;
+ *maxc = 105;
+ } else {
+ *minc = 0;
+ *maxc = 95;
+ }
+ }
+ return val;
+}
+
+static void set_cpu_info(struct ele_get_info_data *info)
+{
+ gd->arch.soc_rev = info->soc;
+ gd->arch.lifecycle = info->lc;
+ memcpy((void *)&gd->arch.uid, &info->uid, 4 * sizeof(u32));
+}
+
+u32 get_cpu_rev(void)
+{
+ u32 rev = (gd->arch.soc_rev >> 24) - 0xa0;
+
+ return (MXC_CPU_IMX95 << 12) | (CHIP_REV_1_0 + rev);
+}
+
+#define UNLOCK_WORD 0xD928C520
+#define REFRESH_WORD 0xB480A602
+
+static void disable_wdog(void __iomem *wdog_base)
+{
+ u32 val_cs = readl(wdog_base + 0x00);
+ int ret = 0;
+
+ if (!(val_cs & 0x80))
+ return;
+
+ /* default is 32bits cmd */
+ writel(REFRESH_WORD, (wdog_base + 0x04)); /* Refresh the CNT */
+
+ if (!(val_cs & 0x800)) {
+ writel(UNLOCK_WORD, (wdog_base + 0x04));
+ while (!(readl(wdog_base + 0x00) & 0x800))
+ ;
+ }
+ writel(0x0, (wdog_base + 0x0C)); /* Set WIN to 0 */
+ writel(0x400, (wdog_base + 0x08)); /* Set timeout to default 0x400 */
+ writel(0x2120, (wdog_base + 0x00)); /* Disable it and set update */
+
+ ret = readl_poll_timeout(wdog_base, val_cs, val_cs & 0x400, 100000);
+ if (ret < 0)
+ debug("%s timeout\n", __func__);
+}
+
+static struct mm_region imx9_mem_map[] = {
+ {
+ /* M7 TCM */
+ .virt = 0x203c0000UL,
+ .phys = 0x203c0000UL,
+ .size = 0x80000UL,
+ .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
+ PTE_BLOCK_NON_SHARE |
+ PTE_BLOCK_PXN | PTE_BLOCK_UXN
+ }, {
+ /* OCRAM */
+ .virt = 0x20480000UL,
+ .phys = 0x20480000UL,
+ .size = 0xA0000UL,
+ .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
+ PTE_BLOCK_OUTER_SHARE
+ }, {
+ /* AIPS */
+ .virt = 0x40000000UL,
+ .phys = 0x40000000UL,
+ .size = 0x40000000UL,
+ .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
+ PTE_BLOCK_NON_SHARE |
+ PTE_BLOCK_PXN | PTE_BLOCK_UXN
+ }, {
+ /* Flexible Serial Peripheral Interface */
+ .virt = 0x28000000UL,
+ .phys = 0x28000000UL,
+ .size = 0x8000000UL,
+ .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
+ PTE_BLOCK_NON_SHARE |
+ PTE_BLOCK_PXN | PTE_BLOCK_UXN
+ }, {
+ /* DRAM1 */
+ .virt = PHYS_SDRAM,
+ .phys = PHYS_SDRAM,
+ .size = PHYS_SDRAM_SIZE,
+ .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
+ PTE_BLOCK_OUTER_SHARE
+ }, {
+#ifdef PHYS_SDRAM_2_SIZE
+ /* DRAM2 */
+ .virt = 0x100000000UL,
+ .phys = 0x100000000UL,
+ .size = PHYS_SDRAM_2_SIZE,
+ .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
+ PTE_BLOCK_OUTER_SHARE
+ }, {
+#endif
+ /* empty entry to split table entry 5 if needed when TEEs are used */
+ 0,
+ }, {
+ /* List terminator */
+ 0,
+ }
+};
+
+struct mm_region *mem_map = imx9_mem_map;
+
+static unsigned int imx9_find_dram_entry_in_mem_map(void)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(imx9_mem_map); i++)
+ if (imx9_mem_map[i].phys == CFG_SYS_SDRAM_BASE)
+ return i;
+
+ hang(); /* Entry not found, this must never happen. */
+}
+
+void enable_caches(void)
+{
+ /* If OPTEE runs, remove OPTEE memory from MMU table to avoid speculative prefetch
+ * If OPTEE does not run, still update the MMU table according to dram banks structure
+ * to set correct dram size from board_phys_sdram_size
+ */
+ int i = 0;
+ /*
+ * please make sure that entry initial value matches
+ * imx9_mem_map for DRAM1
+ */
+ int entry = imx9_find_dram_entry_in_mem_map();
+ u64 attrs = imx9_mem_map[entry].attrs;
+
+ while (i < CONFIG_NR_DRAM_BANKS &&
+ entry < ARRAY_SIZE(imx9_mem_map)) {
+ if (gd->bd->bi_dram[i].start == 0)
+ break;
+ imx9_mem_map[entry].phys = gd->bd->bi_dram[i].start;
+ imx9_mem_map[entry].virt = gd->bd->bi_dram[i].start;
+ imx9_mem_map[entry].size = gd->bd->bi_dram[i].size;
+ imx9_mem_map[entry].attrs = attrs;
+ debug("Added memory mapping (%d): %llx %llx\n", entry,
+ imx9_mem_map[entry].phys, imx9_mem_map[entry].size);
+ i++; entry++;
+ }
+
+ icache_enable();
+ dcache_enable();
+}
+
+__weak int board_phys_sdram_size(phys_size_t *size)
+{
+ phys_size_t start, end;
+ phys_size_t val;
+
+ if (!size)
+ return -EINVAL;
+
+ val = readl(REG_DDR_CS0_BNDS);
+ start = (val >> 16) << 24;
+ end = (val & 0xFFFF);
+ end = end ? end + 1 : 0;
+ end = end << 24;
+ *size = end - start;
+
+ val = readl(REG_DDR_CS1_BNDS);
+ start = (val >> 16) << 24;
+ end = (val & 0xFFFF);
+ end = end ? end + 1 : 0;
+ end = end << 24;
+ *size += end - start;
+
+ return 0;
+}
+
+int dram_init(void)
+{
+ phys_size_t sdram_size;
+ int ret;
+
+ ret = board_phys_sdram_size(&sdram_size);
+ if (ret)
+ return ret;
+
+ /* rom_pointer[1] contains the size of TEE occupies */
+ if (rom_pointer[1] && PHYS_SDRAM < (phys_addr_t)rom_pointer[0])
+ gd->ram_size = sdram_size - rom_pointer[1];
+ else
+ gd->ram_size = sdram_size;
+
+ return 0;
+}
+
+int dram_init_banksize(void)
+{
+ int bank = 0;
+ int ret;
+ phys_size_t sdram_size;
+ phys_size_t sdram_b1_size, sdram_b2_size;
+
+ ret = board_phys_sdram_size(&sdram_size);
+ if (ret)
+ return ret;
+
+ /* Bank 1 can't cross over 4GB space */
+ if (sdram_size > 0x80000000) {
+ sdram_b1_size = 0x100000000UL - PHYS_SDRAM;
+ sdram_b2_size = sdram_size - sdram_b1_size;
+ } else {
+ sdram_b1_size = sdram_size;
+ sdram_b2_size = 0;
+ }
+
+ gd->bd->bi_dram[bank].start = PHYS_SDRAM;
+ if (rom_pointer[1] && PHYS_SDRAM < (phys_addr_t)rom_pointer[0]) {
+ phys_addr_t optee_start = (phys_addr_t)rom_pointer[0];
+ phys_size_t optee_size = (size_t)rom_pointer[1];
+
+ gd->bd->bi_dram[bank].size = optee_start - gd->bd->bi_dram[bank].start;
+ if ((optee_start + optee_size) < (PHYS_SDRAM + sdram_b1_size)) {
+ if (++bank >= CONFIG_NR_DRAM_BANKS) {
+ puts("CONFIG_NR_DRAM_BANKS is not enough\n");
+ return -1;
+ }
+
+ gd->bd->bi_dram[bank].start = optee_start + optee_size;
+ gd->bd->bi_dram[bank].size = PHYS_SDRAM +
+ sdram_b1_size - gd->bd->bi_dram[bank].start;
+ }
+ } else {
+ gd->bd->bi_dram[bank].size = sdram_b1_size;
+ }
+
+ if (sdram_b2_size) {
+ if (++bank >= CONFIG_NR_DRAM_BANKS) {
+ puts("CONFIG_NR_DRAM_BANKS is not enough for SDRAM_2\n");
+ return -1;
+ }
+ gd->bd->bi_dram[bank].start = 0x100000000UL;
+ gd->bd->bi_dram[bank].size = sdram_b2_size;
+ }
+
+ return 0;
+}
+
+phys_size_t get_effective_memsize(void)
+{
+ int ret;
+ phys_size_t sdram_size;
+ phys_size_t sdram_b1_size;
+
+ ret = board_phys_sdram_size(&sdram_size);
+ if (!ret) {
+ /* Bank 1 can't cross over 4GB space */
+ if (sdram_size > 0x80000000)
+ sdram_b1_size = 0x100000000UL - PHYS_SDRAM;
+ else
+ sdram_b1_size = sdram_size;
+
+ if (rom_pointer[1]) {
+ /* We will relocate u-boot to Top of dram1. Tee position has three cases:
+ * 1. At the top of dram1, Then return the size removed optee size.
+ * 2. In the middle of dram1, return the size of dram1.
+ * 3. Not in the scope of dram1, return the size of dram1.
+ */
+ if ((rom_pointer[0] + rom_pointer[1]) == (PHYS_SDRAM + sdram_b1_size))
+ return ((phys_addr_t)rom_pointer[0] - PHYS_SDRAM);
+ }
+
+ return sdram_b1_size;
+ } else {
+ return PHYS_SDRAM_SIZE;
+ }
+}
+
+void imx_get_mac_from_fuse(int dev_id, unsigned char *mac)
+{
+ u32 val[2] = {};
+ int ret, num_of_macs;
+
+ ret = fuse_read(40, 5, &val[0]);
+ if (ret)
+ goto err;
+
+ ret = fuse_read(40, 6, &val[1]);
+ if (ret)
+ goto err;
+
+ num_of_macs = (val[1] >> 24) & 0xff;
+ if (num_of_macs <= (dev_id * 3)) {
+ printf("WARNING: no MAC address assigned for MAC%d\n", dev_id);
+ goto err;
+ }
+
+ mac[0] = val[0] & 0xff;
+ mac[1] = (val[0] >> 8) & 0xff;
+ mac[2] = (val[0] >> 16) & 0xff;
+ mac[3] = (val[0] >> 24) & 0xff;
+ mac[4] = val[1] & 0xff;
+ mac[5] = (val[1] >> 8) & 0xff;
+ if (dev_id == 1)
+ mac[5] = mac[5] + 3;
+ if (dev_id == 2)
+ mac[5] = mac[5] + 6;
+
+ debug("%s: MAC%d: %pM\n", __func__, dev_id, mac);
+ return;
+err:
+ memset(mac, 0, 6);
+ printf("%s: fuse read err: %d\n", __func__, ret);
+}
+
+const char *get_imx_type(u32 imxtype)
+{
+ switch (imxtype) {
+ case MXC_CPU_IMX95:
+ return "95";/* iMX95 FULL */
+ default:
+ return "??";
+ }
+}
+
+void build_info(void)
+{
+ u32 fw_version, sha1, res = 0, status;
+ int ret;
+
+ printf("\nBuildInfo:\n");
+
+ ret = ele_get_fw_status(&status, &res);
+ if (ret) {
+ printf(" - ELE firmware status failed %d, 0x%x\n", ret, res);
+ } else if ((status & 0xff) == 1) {
+ ret = ele_get_fw_version(&fw_version, &sha1, &res);
+ if (ret) {
+ printf(" - ELE firmware version failed %d, 0x%x\n", ret, res);
+ } else {
+ printf(" - ELE firmware version %u.%u.%u-%x",
+ (fw_version & (0x00ff0000)) >> 16,
+ (fw_version & (0x0000fff0)) >> 4,
+ (fw_version & (0x0000000f)), sha1);
+ ((fw_version & (0x80000000)) >> 31) == 1 ? puts("-dirty\n") : puts("\n");
+ }
+ } else {
+ printf(" - ELE firmware not included\n");
+ }
+ puts("\n");
+}
+
+int arch_misc_init(void)
+{
+ build_info();
+ 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)
+{
+ printf("UID: %08x%08x%08x%08x\n", __be32_to_cpu(gd->arch.uid[0]),
+ __be32_to_cpu(gd->arch.uid[1]), __be32_to_cpu(gd->arch.uid[2]),
+ __be32_to_cpu(gd->arch.uid[3]));
+
+ serialnr->low = __be32_to_cpu(gd->arch.uid[1]);
+ serialnr->high = __be32_to_cpu(gd->arch.uid[0]);
+}
+#endif
+
+static void gpio_reset(ulong gpio_base)
+{
+ writel(0, gpio_base + 0x10);
+ writel(0, gpio_base + 0x14);
+ writel(0, gpio_base + 0x18);
+ writel(0, gpio_base + 0x1c);
+}
+
+int arch_cpu_init(void)
+{
+ if (IS_ENABLED(CONFIG_SPL_BUILD)) {
+ disable_wdog((void __iomem *)WDG3_BASE_ADDR);
+ disable_wdog((void __iomem *)WDG4_BASE_ADDR);
+
+ gpio_reset(GPIO2_BASE_ADDR);
+ gpio_reset(GPIO3_BASE_ADDR);
+ gpio_reset(GPIO4_BASE_ADDR);
+ gpio_reset(GPIO5_BASE_ADDR);
+ }
+
+ return 0;
+}
+
+int imx9_probe_mu(void)
+{
+ struct udevice *dev;
+ int ret;
+ u32 res;
+ struct ele_get_info_data info;
+
+ ret = uclass_get_device_by_driver(UCLASS_SCMI_AGENT, DM_DRIVER_GET(scmi_mbox), &dev);
+ if (ret)
+ return ret;
+
+ ret = uclass_get_device_by_name(UCLASS_CLK, "protocol@14", &dev);
+ if (ret)
+ return ret;
+
+ ret = devm_scmi_of_get_channel(dev);
+ if (ret)
+ return ret;
+
+ ret = uclass_get_device_by_name(UCLASS_PINCTRL, "protocol@19", &dev);
+ if (ret)
+ return ret;
+
+#if defined(CONFIG_SPL_BUILD)
+ ret = uclass_get_device_by_name(UCLASS_MISC, "mailbox@47530000", &dev);
+#else
+ ret = uclass_get_device_by_name(UCLASS_MISC, "mailbox@47550000", &dev);
+#endif
+ if (ret)
+ return ret;
+
+ if (gd->flags & GD_FLG_RELOC)
+ return 0;
+
+ ret = ele_get_info(&info, &res);
+ if (ret)
+ return ret;
+
+ set_cpu_info(&info);
+
+ return 0;
+}
+
+EVENT_SPY_SIMPLE(EVT_DM_POST_INIT_F, imx9_probe_mu);
+EVENT_SPY_SIMPLE(EVT_DM_POST_INIT_R, imx9_probe_mu);
+
+int timer_init(void)
+{
+ gd->arch.tbl = 0;
+ gd->arch.tbu = 0;
+
+ if (IS_ENABLED(CONFIG_SPL_BUILD)) {
+ unsigned long freq = 24000000;
+
+ asm volatile("msr cntfrq_el0, %0" : : "r" (freq) : "memory");
+
+ /* Clear the compare frame interrupt */
+ unsigned long sctr_cmpcr_addr = SYSCNT_CMP_BASE_ADDR + 0x2c;
+ unsigned long sctr_cmpcr = readl(sctr_cmpcr_addr);
+
+ sctr_cmpcr &= ~0x1;
+ writel(sctr_cmpcr, sctr_cmpcr_addr);
+ }
+
+ return 0;
+}
+
+enum env_location env_get_location(enum env_operation op, int prio)
+{
+ enum boot_device dev = get_boot_device();
+ enum env_location env_loc = ENVL_UNKNOWN;
+
+ if (prio)
+ return env_loc;
+
+ switch (dev) {
+ case QSPI_BOOT:
+ env_loc = ENVL_SPI_FLASH;
+ break;
+ case SD1_BOOT:
+ case SD2_BOOT:
+ case SD3_BOOT:
+ case MMC1_BOOT:
+ case MMC2_BOOT:
+ case MMC3_BOOT:
+ env_loc = ENVL_MMC;
+ break;
+ default:
+ env_loc = ENVL_NOWHERE;
+ break;
+ }
+
+ return env_loc;
+}
+
+enum imx9_soc_voltage_mode soc_target_voltage_mode(void)
+{
+ u32 speed = get_cpu_speed_grade_hz();
+ enum imx9_soc_voltage_mode voltage = VOLT_OVER_DRIVE;
+
+ if (is_imx95()) {
+ if (speed == 2000000000)
+ voltage = VOLT_SUPER_OVER_DRIVE;
+ else if (speed == 1800000000)
+ voltage = VOLT_OVER_DRIVE;
+ else if (speed == 1400000000)
+ voltage = VOLT_NOMINAL_DRIVE;
+ else /* boot not support low drive mode according to AS */
+ printf("Unexpected A55 freq %u, default to OD\n", speed);
+ }
+
+ return voltage;
+}
+
+#if IS_ENABLED(CONFIG_SCMI_FIRMWARE)
+enum boot_device get_boot_device(void)
+{
+ volatile gd_t *pgd = gd;
+ int ret;
+ u16 boot_type;
+ u8 boot_instance;
+ enum boot_device boot_dev = 0;
+ rom_passover_t *rdata;
+
+#if IS_ENABLED(CONFIG_SPL_BUILD)
+ rdata = &rom_passover_data;
+#else
+ rom_passover_t rom_data = {0};
+
+ if (pgd->reloc_off == 0)
+ rdata = &rom_data;
+ else
+ rdata = &rom_passover_data;
+#endif
+ if (rdata->tag == 0) {
+ ret = scmi_get_rom_data(rdata);
+ if (ret != 0) {
+ puts("SCMI: failure at rom_boot_info\n");
+ return -1;
+ }
+ }
+ boot_type = rdata->boot_dev_type;
+ boot_instance = rdata->boot_dev_inst;
+
+ set_gd(pgd);
+
+ switch (boot_type) {
+ case BT_DEV_TYPE_SD:
+ boot_dev = boot_instance + SD1_BOOT;
+ break;
+ case BT_DEV_TYPE_MMC:
+ boot_dev = boot_instance + MMC1_BOOT;
+ break;
+ case BT_DEV_TYPE_NAND:
+ boot_dev = NAND_BOOT;
+ break;
+ case BT_DEV_TYPE_FLEXSPINOR:
+ boot_dev = QSPI_BOOT;
+ break;
+ case BT_DEV_TYPE_USB:
+ boot_dev = boot_instance + USB_BOOT;
+ if (IS_ENABLED(CONFIG_IMX95))
+ boot_dev -= 3; //iMX95 usb instance start at 3
+ break;
+ default:
+ break;
+ }
+
+ return boot_dev;
+}
+#endif
+
+bool arch_check_dst_in_secure(void *start, ulong size)
+{
+ ulong ns_end = CFG_SYS_SDRAM_BASE + PHYS_SDRAM_SIZE;
+#ifdef PHYS_SDRAM_2_SIZE
+ ns_end += PHYS_SDRAM_2_SIZE;
+#endif
+
+ if ((ulong)start < CFG_SYS_SDRAM_BASE || (ulong)start + size > ns_end)
+ return true;
+
+ return false;
+}
+
+void *arch_get_container_trampoline(void)
+{
+ return (void *)((ulong)CFG_SYS_SDRAM_BASE + PHYS_SDRAM_SIZE - SZ_16M);
+}
diff --git a/arch/sandbox/include/asm/scmi_test.h b/arch/sandbox/include/asm/scmi_test.h
index 619f8f5098c..c9717118bcb 100644
--- a/arch/sandbox/include/asm/scmi_test.h
+++ b/arch/sandbox/include/asm/scmi_test.h
@@ -27,10 +27,12 @@ struct sandbox_scmi_pwd {
* @id: Identifier of the clock used in the SCMI protocol
* @enabled: Clock state: true if enabled, false if disabled
* @rate: Clock rate in Hertz
+ * @perm: Indicating state/parent/rate permission
*/
struct sandbox_scmi_clk {
bool enabled;
ulong rate;
+ u32 perm;
};
/**
@@ -108,7 +110,7 @@ struct sandbox_scmi_devices {
size_t regul_count;
};
-#ifdef CONFIG_SCMI_FIRMWARE
+#if IS_ENABLED(CONFIG_SCMI_FIRMWARE)
/**
* sandbox_scmi_channel_id - Get the channel id
* @dev: Reference to the SCMI protocol device