CI: https://source.denx.de/u-boot/custodians/u-boot-imx/-/pipelines/26064

- Add i.MX95 support.
- Enable BOOTAUX on the i.MX8M Beacon boards.
This commit is contained in:
Tom Rini
2025-05-04 08:51:43 -06:00
55 changed files with 2952 additions and 102 deletions
+2 -1
View File
@@ -2231,7 +2231,8 @@ CLEAN_FILES += include/autoconf.mk* include/bmp_logo.h include/bmp_logo_data.h \
itb.fit.fit itb.fit.itb itb.map spl.map mkimage-out.rom.mkimage \
mkimage.rom.mkimage mkimage-in-simple-bin* rom.map simple-bin* \
idbloader-spi.img lib/efi_loader/helloworld_efi.S *.itb \
Test* capsule*.*.efi-capsule capsule*.map
Test* capsule*.*.efi-capsule capsule*.map mkimage.imx-boot.spl \
mkimage.imx-boot.u-boot mkimage-out.imx-boot.spl mkimage-out.imx-boot.u-boot
# Directories & files removed with 'make mrproper'
MRPROPER_DIRS += include/config include/generated spl tpl vpl \
+62
View File
@@ -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;
};
+188
View File
@@ -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;
};
+2
View File
@@ -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
+10
View File
@@ -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
@@ -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
@@ -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);
+39
View File
@@ -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
+1 -1
View File
@@ -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"
+95 -24
View File
@@ -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];
}
debug("scu container size 0x%x\n", value_container[1]);
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 */
}
return value_container[1] + offset2;
debug("scu container size 0x%x\n", value_container[2]);
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;
}
+15
View File
@@ -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
+8 -3
View File
@@ -3,8 +3,13 @@
# Copyright 2022 NXP
obj-y += lowlevel_init.o
obj-y += soc.o clock.o clock_root.o trdc.o
#ifndef CONFIG_XPL_BUILD
ifeq ($(CONFIG_SCMI_FIRMWARE),y)
obj-y += scmi/
else
obj-y += soc.o clock.o clock_root.o trdc.o
endif
ifneq ($(CONFIG_SPL_BUILD),y)
obj-y += imx_bootaux.o
#endif
endif
+6
View File
@@ -0,0 +1,6 @@
# SPDX-License-Identifier: GPL-2.0+
#
# Copyright 2025 NXP
obj-y += soc.o
obj-y += clock_scmi.o clock.o
+70
View File
@@ -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;
};
+133
View File
@@ -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;
}
+10
View File
@@ -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
+15
View File
@@ -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
+749
View File
@@ -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);
}
+3 -1
View File
@@ -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
+12
View File
@@ -0,0 +1,12 @@
if TARGET_IMX95_19X19_EVK
config SYS_BOARD
default "imx95_evk"
config SYS_VENDOR
default "freescale"
config SYS_CONFIG_NAME
default "imx95_evk"
endif
+6
View File
@@ -0,0 +1,6 @@
i.MX95 EVK BOARD
M: Alice Guo <alice.guo@nxp.com>
S: Maintained
F: board/freescale/imx95_evk/
F: include/configs/imx95_evk.h
F: configs/imx95_19x19_evk_defconfig
+11
View File
@@ -0,0 +1,11 @@
#
# Copyright 2025 NXP
#
# SPDX-License-Identifier: GPL-2.0+
#
obj-y += imx95_evk.o
ifdef CONFIG_SPL_BUILD
obj-y += spl.o
endif
@@ -0,0 +1,91 @@
sec_boot=no
initrd_addr=0x93800000
emmc_dev=0
sd_dev=1
scriptaddr=0x93500000
kernel_addr_r=CONFIG_SYS_LOAD_ADDR
image=Image
splashimage=0xA0000000
console=ttyLP0,115200 earlycon
fdt_addr_r=0x93000000
fdt_addr=0x93000000
cntr_addr=0xA8000000
cntr_file=os_cntr_signed.bin
boot_fit=no
fdtfile=CONFIG_DEFAULT_FDT_FILE
bootm_size=0x10000000
mmcdev=CONFIG_SYS_MMC_ENV_DEV
mmcautodetect=yes
mmcargs=setenv bootargs console=${console} root=${mmcroot}
loadbootscript=fatload mmc ${mmcdev}:${mmcpart} ${loadaddr} ${script};
bootscript=echo Running bootscript from mmc ...; source
loadimage=fatload mmc ${mmcdev}:${mmcpart} ${loadaddr} ${image}
loadfdt=fatload mmc ${mmcdev}:${mmcpart} ${fdt_addr_r} ${fdtfile}
loadcntr=fatload mmc ${mmcdev}:${mmcpart} ${cntr_addr} ${cntr_file}
auth_os=auth_cntr ${cntr_addr}
boot_os=booti ${loadaddr} - ${fdt_addr_r};
mmcboot=echo Booting from mmc ...;
run mmcargs;
if test ${sec_boot} = yes; then
if run auth_os; then
run boot_os;
else
echo ERR: failed to authenticate;
fi;
else
if test ${boot_fit} = yes || test ${boot_fit} = try; then
bootm ${loadaddr};
else
if run loadfdt; then
run boot_os;
else
echo WARN: Cannot load the DT;
fi;
fi;
fi;
netargs=setenv bootargs console=${console} root=/dev/nfs
ip=dhcp nfsroot=${serverip}:${nfsroot},v3,tcp
netboot=echo Booting from net ...;
run netargs;
if test ${ip_dyn} = yes; then
setenv get_cmd dhcp;
else
setenv get_cmd tftp;
fi;
if test ${sec_boot} = yes; then
${get_cmd} ${cntr_addr} ${cntr_file};
if run auth_os; then
run boot_os;
else
echo ERR: failed to authenticate;
fi;
else
${get_cmd} ${loadaddr} ${image};
if test ${boot_fit} = yes || test ${boot_fit} = try; then
bootm ${loadaddr};
else
if ${get_cmd} ${fdt_addr_r} ${fdtfile}; then
run boot_os;
else
echo WARN: Cannot load the DT;
fi;
fi;
fi;
bsp_bootcmd=echo Running BSP bootcmd ...;
mmc dev ${mmcdev}; if mmc rescan; then
if run loadbootscript; then
run bootscript;
else
if test ${sec_boot} = yes; then
if run loadcntr; then
run mmcboot;
else run netboot;
fi;
else
if run loadimage; then
run mmcboot;
else run netboot;
fi;
fi;
fi;
fi;
+36
View File
@@ -0,0 +1,36 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright 2025 NXP
*/
#include <asm/arch/clock.h>
#include <asm/gpio.h>
#include <asm/mach-imx/sys_proto.h>
int board_early_init_f(void)
{
/* UART1: A55, UART2: M33, UART3: M7 */
init_uart_clk(0);
return 0;
}
int board_init(void)
{
return 0;
}
int board_late_init(void)
{
if (IS_ENABLED(CONFIG_ENV_IS_IN_MMC))
board_late_mmc_env_init();
return 0;
}
int board_phys_sdram_size(phys_size_t *size)
{
*size = PHYS_SDRAM_SIZE + PHYS_SDRAM_2_SIZE;
return 0;
}
+69
View File
@@ -0,0 +1,69 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright 2025 NXP
*/
#include <asm/arch/clock.h>
#include <asm/arch/mu.h>
#include <asm/mach-imx/boot_mode.h>
#include <asm/sections.h>
#include <hang.h>
#include <init.h>
#include <spl.h>
DECLARE_GLOBAL_DATA_PTR;
int spl_board_boot_device(enum boot_device boot_dev_spl)
{
switch (boot_dev_spl) {
case SD1_BOOT:
case MMC1_BOOT:
return BOOT_DEVICE_MMC1;
case SD2_BOOT:
case MMC2_BOOT:
return BOOT_DEVICE_MMC2;
case USB_BOOT:
return BOOT_DEVICE_BOARD;
default:
return BOOT_DEVICE_NONE;
}
}
void spl_board_init(void)
{
puts("Normal Boot\n");
}
void board_init_f(ulong dummy)
{
int ret;
/* Clear the BSS. */
memset(__bss_start, 0, __bss_end - __bss_start);
#ifdef CONFIG_SPL_RECOVER_DATA_SECTION
if (IS_ENABLED(CONFIG_SPL_BUILD))
spl_save_restore_data();
#endif
timer_init();
/* Need dm_init() to run before any SCMI calls can be made. */
spl_early_init();
/* Need enable SCMI drivers and ELE driver before enabling console */
ret = imx9_probe_mu();
if (ret)
hang(); /* if MU not probed, nothing can output, just hang here */
arch_cpu_init();
board_early_init_f();
preloader_console_init();
debug("SOC: 0x%x\n", gd->arch.soc_rev);
debug("LC: 0x%x\n", gd->arch.lifecycle);
board_init_r(NULL, 0);
}
+6
View File
@@ -363,6 +363,12 @@ config SPL_LOAD_IMX_CONTAINER
Support booting U-Boot from an i.MX8 container image. If you are not
using i.MX8, say 'n'.
config SPL_IMX_CONTAINER_USE_TRAMPOLINE
bool
depends on SPL
help
Enable SPL load reader to load data to a trampoline buffer.
config IMX_CONTAINER_CFG
string "i.MX8 Container config file"
depends on SPL && SPL_LOAD_IMX_CONTAINER
+32 -6
View File
@@ -14,6 +14,16 @@
#include <asm/mach-imx/ahab.h>
#endif
__weak bool arch_check_dst_in_secure(void *start, ulong size)
{
return false;
}
__weak void *arch_get_container_trampoline(void)
{
return NULL;
}
static struct boot_img_t *read_auth_image(struct spl_image_info *spl_image,
struct spl_load_info *info,
struct container_hdr *container,
@@ -22,6 +32,7 @@ static struct boot_img_t *read_auth_image(struct spl_image_info *spl_image,
{
struct boot_img_t *images;
ulong offset, overhead, size;
void *buf, *trampoline;
if (image_index > container->num_images) {
debug("Invalid image number\n");
@@ -42,12 +53,27 @@ static struct boot_img_t *read_auth_image(struct spl_image_info *spl_image,
debug("%s: container: %p offset: %lu size: %lu\n", __func__,
container, offset, size);
if (info->read(info, offset, size,
map_sysmem(images[image_index].dst - overhead,
images[image_index].size)) <
images[image_index].size) {
printf("%s wrong\n", __func__);
return NULL;
buf = map_sysmem(images[image_index].dst - overhead, images[image_index].size);
if (IS_ENABLED(CONFIG_SPL_IMX_CONTAINER_USE_TRAMPOLINE) &&
arch_check_dst_in_secure(buf, size)) {
trampoline = arch_get_container_trampoline();
if (!trampoline) {
printf("%s: trampoline size is zero\n", __func__);
return NULL;
}
if (info->read(info, offset, size, trampoline) < images[image_index].size) {
printf("%s: failed to load image to a trampoline buffer\n", __func__);
return NULL;
}
memcpy(buf, trampoline, images[image_index].size);
} else {
if (info->read(info, offset, size, buf) < images[image_index].size) {
printf("%s: failed to load image to a non-secure region\n", __func__);
return NULL;
}
}
#ifdef CONFIG_AHAB_BOOT
+1
View File
@@ -24,6 +24,7 @@ CONFIG_SPL_BSS_MAX_SIZE=0x2000
CONFIG_SYS_BOOTM_LEN=0x800000
CONFIG_SYS_LOAD_ADDR=0x40480000
CONFIG_SPL=y
CONFIG_IMX_BOOTAUX=y
CONFIG_FIT=y
CONFIG_FIT_EXTERNAL_OFFSET=0x3000
CONFIG_SPL_LOAD_FIT=y
+1
View File
@@ -29,6 +29,7 @@ CONFIG_SPL=y
CONFIG_SPL_IMX_ROMAPI_LOADADDR=0x48000000
CONFIG_SYS_MEMTEST_START=0x40000000
CONFIG_SYS_MEMTEST_END=0x44000000
CONFIG_IMX_BOOTAUX=y
CONFIG_REMAKE_ELF=y
CONFIG_FIT=y
CONFIG_FIT_EXTERNAL_OFFSET=0x3000
+1
View File
@@ -33,6 +33,7 @@ CONFIG_ARMV8_SET_SMPEN=y
CONFIG_ARMV8_EA_EL3_FIRST=y
CONFIG_SPL_IMX_ROMAPI_LOADADDR=0x48000000
CONFIG_PCI=y
CONFIG_IMX_BOOTAUX=y
# CONFIG_ANDROID_BOOT_IMAGE is not set
CONFIG_FIT=y
CONFIG_FIT_EXTERNAL_OFFSET=0x3000
+152
View File
@@ -0,0 +1,152 @@
CONFIG_ARM=y
CONFIG_ARCH_IMX9=y
CONFIG_TEXT_BASE=0x90200000
CONFIG_SYS_MALLOC_LEN=0x2000000
CONFIG_SYS_MALLOC_F_LEN=0x10000
CONFIG_SPL_GPIO=y
CONFIG_SPL_LIBCOMMON_SUPPORT=y
CONFIG_SPL_LIBGENERIC_SUPPORT=y
CONFIG_NR_DRAM_BANKS=3
CONFIG_ENV_SOURCE_FILE="imx95_19x19_evk"
CONFIG_SF_DEFAULT_SPEED=40000000
CONFIG_ENV_SIZE=0x4000
CONFIG_ENV_OFFSET=0x700000
CONFIG_IMX_CONFIG="arch/arm/mach-imx/imx9/scmi/imximage.cfg"
CONFIG_DM_GPIO=y
CONFIG_DEFAULT_DEVICE_TREE="freescale/imx95-19x19-evk"
CONFIG_TARGET_IMX95_19X19_EVK=y
CONFIG_OF_LIBFDT_OVERLAY=y
CONFIG_SYS_MONITOR_LEN=524288
CONFIG_SPL_MMC=y
CONFIG_SPL_SERIAL=y
CONFIG_SPL_DRIVERS_MISC=y
CONFIG_SPL_STACK=0x204d6000
CONFIG_SPL_TEXT_BASE=0x20480000
CONFIG_SPL_HAS_BSS_LINKER_SECTION=y
CONFIG_SPL_BSS_START_ADDR=0x204d6000
CONFIG_SPL_BSS_MAX_SIZE=0x2000
CONFIG_SYS_LOAD_ADDR=0x90400000
CONFIG_SPL=y
CONFIG_SPL_RECOVER_DATA_SECTION=y
CONFIG_PCI=y
CONFIG_SYS_MEMTEST_START=0x90000000
CONFIG_SYS_MEMTEST_END=0xA0000000
CONFIG_REMAKE_ELF=y
CONFIG_FIT=y
CONFIG_FIT_VERBOSE=y
CONFIG_OF_SYSTEM_SETUP=y
CONFIG_BOOTCOMMAND="bootflow scan -l; run bsp_bootcmd"
CONFIG_DEFAULT_FDT_FILE="imx95-19x19-evk.dtb"
CONFIG_SYS_CBSIZE=2048
CONFIG_SYS_PBSIZE=2074
CONFIG_ARCH_MISC_INIT=y
CONFIG_BOARD_EARLY_INIT_F=y
CONFIG_BOARD_LATE_INIT=y
CONFIG_SPL_MAX_SIZE=0x20000
CONFIG_SPL_BOARD_INIT=y
CONFIG_SPL_LOAD_IMX_CONTAINER=y
CONFIG_IMX_CONTAINER_CFG="arch/arm/mach-imx/imx9/scmi/container.cfg"
# CONFIG_SPL_SHARES_INIT_SP_ADDR is not set
CONFIG_SPL_SYS_MALLOC=y
CONFIG_SPL_HAS_CUSTOM_MALLOC_START=y
CONFIG_SPL_CUSTOM_SYS_MALLOC_ADDR=0x93200000
CONFIG_SPL_SYS_MALLOC_SIZE=0x80000
CONFIG_SPL_SYS_MMCSD_RAW_MODE=y
CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR=0x1040
CONFIG_SPL_I2C=y
CONFIG_SPL_DM_MAILBOX=y
CONFIG_SPL_POWER=y
CONFIG_SPL_WATCHDOG=y
CONFIG_SYS_PROMPT="u-boot=> "
CONFIG_CMD_ERASEENV=y
CONFIG_CMD_NVEDIT_EFI=y
CONFIG_CRC32_VERIFY=y
CONFIG_CMD_MEMTEST=y
CONFIG_CMD_CLK=y
CONFIG_CMD_DFU=y
CONFIG_CMD_FUSE=y
CONFIG_CMD_GPIO=y
CONFIG_CMD_GPT=y
CONFIG_CMD_I2C=y
CONFIG_CMD_MMC=y
CONFIG_CMD_PCI=y
CONFIG_CMD_POWEROFF=y
CONFIG_CMD_SNTP=y
CONFIG_CMD_CACHE=y
CONFIG_CMD_EFIDEBUG=y
CONFIG_CMD_RTC=y
CONFIG_CMD_TIME=y
CONFIG_CMD_GETTIME=y
CONFIG_CMD_TIMER=y
CONFIG_CMD_REGULATOR=y
CONFIG_CMD_HASH=y
CONFIG_CMD_EXT4_WRITE=y
CONFIG_OF_CONTROL=y
CONFIG_SPL_OF_CONTROL=y
CONFIG_ENV_OVERWRITE=y
CONFIG_ENV_IS_NOWHERE=y
CONFIG_ENV_IS_IN_MMC=y
CONFIG_SYS_RELOC_GD_ENV_ADDR=y
CONFIG_SYS_MMC_ENV_DEV=1
CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG=y
CONFIG_USE_ETHPRIME=y
CONFIG_ETHPRIME="eth0"
CONFIG_NET_RANDOM_ETHADDR=y
CONFIG_SYS_RX_ETH_BUFFER=8
CONFIG_SPL_DM=y
CONFIG_REGMAP=y
CONFIG_SYSCON=y
CONFIG_SPL_OF_TRANSLATE=y
CONFIG_CLK=y
CONFIG_SPL_CLK=y
CONFIG_SPL_CLK_CCF=y
CONFIG_CLK_CCF=y
CONFIG_CLK_SCMI=y
CONFIG_SPL_CLK_SCMI=y
CONFIG_DFU_MMC=y
CONFIG_DFU_RAM=y
CONFIG_SPL_FIRMWARE=y
# CONFIG_SCMI_AGENT_SMCCC is not set
CONFIG_IMX_RGPIO2P=y
CONFIG_DM_PCA953X=y
CONFIG_ADP5585_GPIO=y
CONFIG_DM_I2C=y
CONFIG_SYS_I2C_IMX_LPI2C=y
CONFIG_IMX_MU_MBOX=y
CONFIG_SUPPORT_EMMC_BOOT=y
CONFIG_MMC_IO_VOLTAGE=y
CONFIG_MMC_UHS_SUPPORT=y
CONFIG_MMC_HS400_ES_SUPPORT=y
CONFIG_MMC_HS400_SUPPORT=y
CONFIG_FSL_USDHC=y
CONFIG_MTD=y
CONFIG_DM_SPI_FLASH=y
CONFIG_SPI_FLASH_STMICRO=y
CONFIG_SPI_FLASH_MT35XU=y
CONFIG_PHYLIB=y
CONFIG_PHY_AQUANTIA=y
CONFIG_PHY_REALTEK=y
CONFIG_DM_MDIO=y
CONFIG_MII=y
CONFIG_FSL_ENETC=y
CONFIG_PCIE_ECAM_GENERIC=y
CONFIG_PHY=y
CONFIG_PINCTRL=y
CONFIG_SPL_PINCTRL=y
CONFIG_PINCTRL_IMX_SCMI=y
CONFIG_POWER_DOMAIN=y
CONFIG_SCMI_POWER_DOMAIN=y
CONFIG_DM_REGULATOR=y
CONFIG_SPL_DM_REGULATOR=y
CONFIG_DM_REGULATOR_FIXED=y
CONFIG_SPL_DM_REGULATOR_FIXED=y
CONFIG_DM_REGULATOR_GPIO=y
CONFIG_DM_RTC=y
CONFIG_DM_SERIAL=y
CONFIG_FSL_LPUART=y
CONFIG_SPI=y
CONFIG_DM_SPI=y
CONFIG_NXP_FSPI=y
CONFIG_ULP_WATCHDOG=y
CONFIG_LZO=y
CONFIG_BZIP2=y
+114
View File
@@ -0,0 +1,114 @@
.. SPDX-License-Identifier: GPL-2.0+
imx95_evk
=======================
U-Boot for the NXP i.MX95 19x19 EVK board
Quick Start
-----------
- Get ahab-container.img
- Get DDR PHY Firmware Images
- Get and Build OEI Images
- Get and Build System Manager Image
- Get and Build the ARM Trusted Firmware
- Build the Bootloader Image
- Boot
Get ahab-container.img
--------------------------------------
Note: srctree is U-Boot source directory
.. code-block:: bash
$ wget https://www.nxp.com/lgfiles/NMG/MAD/YOCTO/firmware-ele-imx-1.3.0-17945fc.bin
$ sh firmware-ele-imx-1.3.0-17945fc.bin --auto-accept
$ cp firmware-ele-imx-1.3.0-17945fc/mx95a0-ahab-container.img $(srctree)
Get DDR PHY Firmware Images
--------------------------------------
Note: srctree is U-Boot source directory
.. code-block:: bash
$ wget https://www.nxp.com/lgfiles/NMG/MAD/YOCTO/firmware-imx-8.26-d4c33ab.bin
$ sh firmware-imx-8.26-d4c33ab.bin --auto-accept
$ cp firmware-imx-8.26-d4c33ab/firmware/ddr/synopsys/lpddr5*v202311.bin $(srctree)
Get and Build OEI Images
--------------------------------------
Note: srctree is U-Boot source directory
Get OEI from: https://github.com/nxp-imx/imx-oei
branch: master
.. code-block:: bash
$ sudo apt -y install make gcc g++-multilib srecord
$ wget https://developer.arm.com/-/media/Files/downloads/gnu/13.3.rel1/binrel/arm-gnu-toolchain-13.3.rel1-x86_64-arm-none-eabi.tar.xz
$ tar xvf arm-gnu-toolchain-13.3.rel1-x86_64-arm-none-eabi.tar.xz
$ export TOOLS=$PWD
$ git clone -b master https://github.com/nxp-imx/imx-oei.git
$ cd imx-oei
$ make board=mx95lp5 oei=ddr DEBUG=1
$ cp build/mx95lp5/ddr/oei-m33-ddr.bin $(srctree)
$ make board=mx95lp5 oei=tcm DEBUG=1
$ cp build/mx95lp5/tcm/oei-m33-tcm.bin $(srctree)
Get and Build System Manager Image
--------------------------------------
Note: srctree is U-Boot source directory
Get System Manager from: https://github.com/nxp-imx/imx-sm
branch: master
.. code-block:: bash
$ sudo apt -y install make gcc g++-multilib srecord
$ wget https://developer.arm.com/-/media/Files/downloads/gnu/13.3.rel1/binrel/arm-gnu-toolchain-13.3.rel1-x86_64-arm-none-eabi.tar.xz
$ tar xvf arm-gnu-toolchain-13.3.rel1-x86_64-arm-none-eabi.tar.xz
$ export TOOLS=$PWD
$ git clone -b master https://github.com/nxp-imx/imx-sm.git
$ cd imx-sm
$ make config=mx95evk all
$ cp build/mx95evk/m33_image.bin $(srctree)
Get and Build the ARM Trusted Firmware
--------------------------------------
Note: srctree is U-Boot source directory
Get ATF from: https://github.com/nxp-imx/imx-atf/
branch: lf_v2.10
.. code-block:: bash
$ export CROSS_COMPILE=aarch64-poky-linux-
$ unset LDFLAGS
$ git clone -b lf_v2.10 https://github.com/nxp-imx/imx-atf.git
$ cd imx-atf
$ make PLAT=imx95 bl31
$ cp build/imx95/release/bl31.bin $(srctree)
Build the Bootloader Image
--------------------------
.. code-block:: bash
$ export CROSS_COMPILE=aarch64-poky-linux-
$ make imx95_19x19_evk_defconfig
$ make
Copy imx-boot-imx95.bin to the MicroSD card:
.. code-block:: bash
$ sudo dd if=flash.bin of=/dev/sd[x] bs=1k seek=32 conv=fsync
Boot
----
Set i.MX95 boot device to MicroSD card
+1
View File
@@ -15,6 +15,7 @@ NXP Semiconductors
imx91_11x11_evk
imx93_9x9_qsb
imx93_11x11_evk
imx95_evk
imxrt1020-evk
imxrt1050-evk
imxrt1170-evk
+136
View File
@@ -0,0 +1,136 @@
i.MX95 Image Container Format
-----------------------------
The image container set consists of some image containers, and image container
contains boot images. Each image container has its own container header which is
defined in Figure 1. All container headers are placed together in a continuous
8KB space at the beginning of the image container set - image container set header.
ROM code addresses image containers in image container set one by one based on
their headers order in image container set header.
If ELE container exists, its container header must be the 1st one in the image
container set header.
If V2X container exists, its container header must be the 2nd one in the image
container set header. V2X must be combined with ELE container.
The information of boot images are recorded in image container header. System
ROM code needs to retrieve the information from the image container header, like
the offset on boot source, the target address in RAM, the length of boot image.
The order of ROM code handling these boot images is based on the order of each
boot image information present in image container header.
Figure 1:
------------------- +--------------+--------------+--------------+--------------+
^ |Tag |Length |Length |Version |
| +--------------+--------------+--------------+--------------+
| | Flags |
| +--------------+--------------+--------------+--------------+
| |# of Images |Fuse version |SW version |
Image | +--------------+--------------+--------------+--------------+
Container | |Reserved |Signature Block Offset |
Header | ------- +--------------+--------------+--------------+--------------+
| ^ |Image0: Offset, Size, LoadAddr, EntryPoint, Flags, Hash, IV|
| | +--------------+--------------+--------------+--------------+
| Image | |Image1: Offset, Size, LoadAddr, EntryPoint, Flags, Hash, IV|
| Array | +--------------+--------------+--------------+--------------+
| | | ... |
| | +--------------+--------------+--------------+--------------+
v v |ImageN: Offset, Size, LoadAddr, EntryPoint, Flags, Hash, IV|
------------------- +--------------+--------------+--------------+--------------+
| ... |
----------- +--------------+--------------+--------------+--------------+ <-- SignOffset
^ |Tag |Length |Length |Version |
| +--------------+--------------+--------------+--------------+
| |SRK table offset |Certificate Offset |
| +--------------+--------------+--------------+--------------+
| |Blob Offset |Signature Offset |
| +--------------+--------------+--------------+--------------+
Signature | | SRK Table |
Block | +--------------+--------------+--------------+--------------+
| | Signature |
| +--------------+--------------+--------------+--------------+
| | Certificate (optional) |
| +--------------+--------------+--------------+--------------+
v | Blob (optional) |
----------- +--------------+--------------+--------------+--------------+
| ... |
+--------------+--------------+--------------+--------------+ <-- Image0Offset
| Image0 |
+--------------+--------------+--------------+--------------+
| ... |
+--------------+--------------+--------------+--------------+ <-- ImageNOffset
| ImageN |
+--------------+--------------+--------------+--------------+
| ... |
+--------------+--------------+--------------+--------------+
i.MX95 Low Power Boot Image Sets Layout
---------------------------------------
Image container sets are handled by M33 ROM.
--------------- +--------------+--------------+--------------+--------------+
^ | 1st Container Header |
| +--------------+--------------+--------------+--------------+
ELE + | | Padding for 1KB alignment |
OEM | +--------------+--------------+--------------+--------------+
Container | | 2nd Container Header |
Set | +--------------+--------------+--------------+--------------+
Header | | Padding for 1KB alignment |
| +--------------+--------------+--------------+--------------+
| | 3rd Container Header |
| +--------------+--------------+--------------+--------------+
v | Padding for 1KB alignment |
--------------- +--------------+--------------+--------------+--------------+
| ... |
+--------------+--------------+--------------+--------------+
| mx95a0-ahab-container.img |
+--------------+--------------+--------------+--------------+
| ... |
------------------- +--------------+--------------+--------------+--------------+
^ | oei-m33-ddr.bin |
| +--------------+--------------+--------------+--------------+
| | ddrfw-header.bin |
| +--------------+--------------+--------------+--------------+
| | lpddr5_imem_v202311.bin |
| +--------------+--------------+--------------+--------------+
m33-oei-ddrfw.bin | | lpddr5_dmem_v202311.bin |
| +--------------+--------------+--------------+--------------+
| | ddrfw-qb-header.bin |
| +--------------+--------------+--------------+--------------+
| | lpddr5_imem_qb_v202311.bin |
| +--------------+--------------+--------------+--------------+
v | lpddr5_dmem_qb_v202311.bin |
------------------- +--------------+--------------+--------------+--------------+
| ... |
+--------------+--------------+--------------+--------------+
| oei-m33-tcm.bin |
+--------------+--------------+--------------+--------------+
| ... |
+--------------+--------------+--------------+--------------+
| m33_image.bin |
+--------------+--------------+--------------+--------------+
| ... |
+--------------+--------------+--------------+--------------+
| u-boot-spl.bin |
+--------------+--------------+--------------+--------------+
| ... |
+--------------+--------------+--------------+--------------+
--------------- +--------------+--------------+--------------+--------------+
u-boot-atf ^ | 1st Container Header |
Container | +--------------+--------------+--------------+--------------+
Header v | Padding for 1KB alignment |
--------------- +--------------+--------------+--------------+--------------+
| ... |
+--------------+--------------+--------------+--------------+
| bl31.bin |
+--------------+--------------+--------------+--------------+
| ... |
+--------------+--------------+--------------+--------------+
| u-boot.bin |
+--------------+--------------+--------------+--------------+
| ... |
+--------------+--------------+--------------+--------------+
+193 -11
View File
@@ -8,10 +8,59 @@
#include <clk-uclass.h>
#include <dm.h>
#include <scmi_agent.h>
#include <scmi_agent-uclass.h>
#include <scmi_protocols.h>
#include <asm/types.h>
#include <linux/clk-provider.h>
struct clk_scmi {
struct clk clk;
u32 ctrl_flags;
};
struct scmi_clock_priv {
u32 version;
};
static int scmi_clk_get_permissions(struct udevice *dev, int clkid, u32 *perm)
{
struct scmi_clock_priv *priv = dev_get_priv(dev);
int ret;
struct scmi_clk_get_permissions_in in = {
.clock_id = clkid,
};
struct scmi_clk_get_permissions_out out;
struct scmi_msg msg = {
.protocol_id = SCMI_PROTOCOL_ID_CLOCK,
.message_id = SCMI_CLOCK_GET_PERMISSIONS,
.in_msg = (u8 *)&in,
.in_msg_sz = sizeof(in),
.out_msg = (u8 *)&out,
.out_msg_sz = sizeof(out),
};
if (priv->version < CLOCK_PROTOCOL_VERSION_3_0) {
log_debug("%s: SCMI clock management protocol version is less than 3.0.\n", __func__);
return -EINVAL;
}
ret = devm_scmi_process_msg(dev, &msg);
if (ret) {
log_debug("%s: get SCMI clock management protocol permissions failed\n", __func__);
return ret;
}
ret = scmi_to_linux_errno(out.status);
if (ret < 0) {
log_debug("%s: the status code of getting permissions: %d\n", __func__, ret);
return ret;
}
*perm = out.permissions;
return 0;
}
static int scmi_clk_get_num_clock(struct udevice *dev, size_t *num_clocks)
{
struct scmi_clk_protocol_attr_out out;
@@ -32,7 +81,8 @@ static int scmi_clk_get_num_clock(struct udevice *dev, size_t *num_clocks)
return 0;
}
static int scmi_clk_get_attibute(struct udevice *dev, int clkid, char **name)
static int scmi_clk_get_attibute(struct udevice *dev, int clkid, char **name,
u32 *attr)
{
struct scmi_clk_attribute_in in = {
.clock_id = clkid,
@@ -53,6 +103,7 @@ static int scmi_clk_get_attibute(struct udevice *dev, int clkid, char **name)
return ret;
*name = strdup(out.clock_name);
*attr = out.attributes;
return 0;
}
@@ -78,12 +129,48 @@ static int scmi_clk_gate(struct clk *clk, int enable)
static int scmi_clk_enable(struct clk *clk)
{
return scmi_clk_gate(clk, 1);
struct clk_scmi *clkscmi;
struct clk *c;
int ret;
if (!CONFIG_IS_ENABLED(CLK_CCF))
return scmi_clk_gate(clk, 1);
ret = clk_get_by_id(clk->id, &c);
if (ret)
return ret;
clkscmi = container_of(c, struct clk_scmi, clk);
if (clkscmi->ctrl_flags & SUPPORT_CLK_STAT_CONTROL)
return scmi_clk_gate(clk, 1);
/* Following Linux drivers/clk/clk-scmi.c, directly return 0 if agent has no permission. */
log_debug("%s: SCMI CLOCK: the clock cannot be enabled by the agent.\n", __func__);
return 0;
}
static int scmi_clk_disable(struct clk *clk)
{
return scmi_clk_gate(clk, 0);
struct clk_scmi *clkscmi;
struct clk *c;
int ret;
if (!CONFIG_IS_ENABLED(CLK_CCF))
return scmi_clk_gate(clk, 0);
ret = clk_get_by_id(clk->id, &c);
if (ret)
return ret;
clkscmi = container_of(c, struct clk_scmi, clk);
if (clkscmi->ctrl_flags & SUPPORT_CLK_STAT_CONTROL)
return scmi_clk_gate(clk, 0);
/* Following Linux drivers/clk/clk-scmi.c, directly return 0 if agent has no permission. */
log_debug("%s: SCMI CLOCK: the clock cannot be disabled by the agent.\n", __func__);
return 0;
}
static ulong scmi_clk_get_rate(struct clk *clk)
@@ -108,7 +195,7 @@ static ulong scmi_clk_get_rate(struct clk *clk)
return (ulong)(((u64)out.rate_msb << 32) | out.rate_lsb);
}
static ulong scmi_clk_set_rate(struct clk *clk, ulong rate)
static ulong __scmi_clk_set_rate(struct clk *clk, ulong rate)
{
struct scmi_clk_rate_set_in in = {
.clock_id = clk->id,
@@ -133,9 +220,33 @@ static ulong scmi_clk_set_rate(struct clk *clk, ulong rate)
return scmi_clk_get_rate(clk);
}
static ulong scmi_clk_set_rate(struct clk *clk, ulong rate)
{
struct clk_scmi *clkscmi;
struct clk *c;
int ret;
if (!CONFIG_IS_ENABLED(CLK_CCF))
return __scmi_clk_set_rate(clk, rate);
ret = clk_get_by_id(clk->id, &c);
if (ret)
return ret;
clkscmi = container_of(c, struct clk_scmi, clk);
if (clkscmi->ctrl_flags & SUPPORT_CLK_RATE_CONTROL)
return __scmi_clk_set_rate(clk, rate);
/* Following Linux drivers/clk/clk-scmi.c, directly return 0 if agent has no permission. */
log_debug("%s: SCMI CLOCK: the clock rate cannot be changed by the agent.\n", __func__);
return 0;
}
static int scmi_clk_probe(struct udevice *dev)
{
struct clk *clk;
struct clk_scmi *clk_scmi;
struct scmi_clock_priv *priv = dev_get_priv(dev);
size_t num_clocks, i;
int ret;
@@ -154,35 +265,98 @@ static int scmi_clk_probe(struct udevice *dev)
if (ret)
return ret;
ret = scmi_generic_protocol_version(dev, SCMI_PROTOCOL_ID_CLOCK, &priv->version);
if (ret) {
log_debug("%s: get SCMI clock management protocol version failed\n", __func__);
return ret;
}
for (i = 0; i < num_clocks; i++) {
char *clock_name;
u32 attributes;
if (!scmi_clk_get_attibute(dev, i, &clock_name)) {
clk = kzalloc(sizeof(*clk), GFP_KERNEL);
if (!clk || !clock_name)
if (!scmi_clk_get_attibute(dev, i, &clock_name, &attributes)) {
clk_scmi = kzalloc(sizeof(*clk_scmi), GFP_KERNEL);
if (!clk_scmi || !clock_name)
ret = -ENOMEM;
else
ret = clk_register(clk, dev->driver->name,
ret = clk_register(&clk_scmi->clk, dev->driver->name,
clock_name, dev->name);
if (ret) {
free(clk);
free(clk_scmi);
free(clock_name);
return ret;
}
clk_dm(i, clk);
clk_dm(i, &clk_scmi->clk);
if (CLK_HAS_RESTRICTIONS(attributes)) {
u32 perm;
ret = scmi_clk_get_permissions(dev, i, &perm);
if (ret < 0)
clk_scmi->ctrl_flags = 0;
else
clk_scmi->ctrl_flags = perm;
} else {
clk_scmi->ctrl_flags = SUPPORT_CLK_STAT_CONTROL | SUPPORT_CLK_PARENT_CONTROL |
SUPPORT_CLK_RATE_CONTROL;
}
}
}
return 0;
}
static int __scmi_clk_set_parent(struct clk *clk, struct clk *parent)
{
struct scmi_clk_parent_set_in in = {
.clock_id = clk->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;
ret = devm_scmi_process_msg(clk->dev, &msg);
if (ret < 0)
return ret;
return scmi_to_linux_errno(out.status);
}
static int scmi_clk_set_parent(struct clk *clk, struct clk *parent)
{
struct clk_scmi *clkscmi;
struct clk *c;
int ret;
if (!CONFIG_IS_ENABLED(CLK_CCF))
return -ENOTSUPP;
ret = clk_get_by_id(clk->id, &c);
if (ret)
return ret;
clkscmi = container_of(c, struct clk_scmi, clk);
if (clkscmi->ctrl_flags & SUPPORT_CLK_PARENT_CONTROL)
return __scmi_clk_set_parent(clk, parent);
/* Following Linux drivers/clk/clk-scmi.c, directly return 0 if agent has no permission. */
log_debug("%s: SCMI CLOCK: the clock's parent cannot be changed by the agent.\n", __func__);
return 0;
}
static const struct clk_ops scmi_clk_ops = {
.enable = scmi_clk_enable,
.disable = scmi_clk_disable,
.get_rate = scmi_clk_get_rate,
.set_rate = scmi_clk_set_rate,
.set_parent = scmi_clk_set_parent,
};
U_BOOT_DRIVER(scmi_clock) = {
@@ -190,4 +364,12 @@ U_BOOT_DRIVER(scmi_clock) = {
.id = UCLASS_CLK,
.ops = &scmi_clk_ops,
.probe = scmi_clk_probe,
.priv_auto = sizeof(struct scmi_clock_priv),
};
static struct scmi_proto_match match[] = {
{ .proto_id = SCMI_PROTOCOL_ID_CLOCK },
{ /* Sentinel */ }
};
U_BOOT_SCMI_PROTO_DRIVER(scmi_clock, match);
+2
View File
@@ -111,6 +111,8 @@ static const char *get_imx_type_str(u32 imxtype)
return "91(11)";/* iMX91 9x9 Reduced feature */
case MXC_CPU_IMX9101:
return "91(01)";/* iMX91 9x9 Specific feature */
case MXC_CPU_IMX95:
return "95";
default:
return "??";
}
+18 -8
View File
@@ -258,7 +258,7 @@ static int scmi_base_discover_impl_version_int(struct udevice *dev,
static int scmi_base_discover_list_protocols_int(struct udevice *dev,
u8 **protocols)
{
struct scmi_base_discover_list_protocols_out out;
struct scmi_base_discover_list_protocols_out *out;
int cur;
struct scmi_msg msg = {
.protocol_id = SCMI_PROTOCOL_ID_BASE,
@@ -268,7 +268,7 @@ static int scmi_base_discover_list_protocols_int(struct udevice *dev,
.out_msg = (u8 *)&out,
.out_msg_sz = sizeof(out),
};
u32 num_agents, num_protocols;
u32 num_agents, num_protocols, out_size;
u8 *buf;
int i, ret;
@@ -276,22 +276,31 @@ static int scmi_base_discover_list_protocols_int(struct udevice *dev,
if (ret)
return ret;
buf = calloc(sizeof(u8), num_protocols);
if (!buf)
out_size = sizeof(*out) + sizeof(u32) * (1 + num_protocols / 4);
out = calloc(1, out_size);
if (!out)
return -ENOMEM;
msg.out_msg = (u8 *)out;
msg.out_msg_sz = out_size;
buf = calloc(sizeof(u8), num_protocols);
if (!buf) {
free(out);
return -ENOMEM;
}
cur = 0;
do {
ret = devm_scmi_process_msg(dev, &msg);
if (ret)
goto err;
if (out.status) {
ret = scmi_to_linux_errno(out.status);
if (out->status) {
ret = scmi_to_linux_errno(out->status);
goto err;
}
for (i = 0; i < out.num_protocols; i++, cur++)
buf[cur] = out.protocols[i / 4] >> ((i % 4) * 8);
for (i = 0; i < out->num_protocols; i++, cur++)
buf[cur] = out->protocols[i / 4] >> ((i % 4) * 8);
} while (cur < num_protocols);
*protocols = buf;
@@ -299,6 +308,7 @@ static int scmi_base_discover_list_protocols_int(struct udevice *dev,
return num_protocols;
err:
free(buf);
free(out);
return ret;
}
+53 -3
View File
@@ -80,9 +80,9 @@ static struct sandbox_scmi_pwd scmi_pwdom[] = {
};
static struct sandbox_scmi_clk scmi_clk[] = {
{ .rate = 333 },
{ .rate = 200 },
{ .rate = 1000 },
{ .rate = 333, .perm = 0xE0000000 },
{ .rate = 200, .perm = 0xE0000000 },
{ .rate = 1000, .perm = 0xE0000000 },
};
static struct sandbox_scmi_reset scmi_reset[] = {
@@ -700,6 +700,21 @@ static int sandbox_scmi_pwd_name_get(struct udevice *dev, struct scmi_msg *msg)
/* Clock Protocol */
static int sandbox_scmi_clock_protocol_version(struct udevice *dev,
struct scmi_msg *msg)
{
struct scmi_protocol_version_out *out = NULL;
if (!msg->out_msg || msg->out_msg_sz < sizeof(*out))
return -EINVAL;
out = (struct scmi_protocol_version_out *)msg->out_msg;
out->version = 0x30000;
out->status = SCMI_SUCCESS;
return 0;
}
static int sandbox_scmi_clock_protocol_attribs(struct udevice *dev,
struct scmi_msg *msg)
{
@@ -740,6 +755,9 @@ static int sandbox_scmi_clock_attribs(struct udevice *dev, struct scmi_msg *msg)
if (clk_state->enabled)
out->attributes = 1;
/* Restricted clock */
out->attributes |= BIT(1);
ret = snprintf(out->clock_name, sizeof(out->clock_name),
"clk%u", in->clock_id);
assert(ret > 0 && ret < sizeof(out->clock_name));
@@ -837,6 +855,34 @@ static int sandbox_scmi_clock_gate(struct udevice *dev, struct scmi_msg *msg)
return 0;
}
static int sandbox_scmi_clock_permissions_get(struct udevice *dev,
struct scmi_msg *msg)
{
struct scmi_clk_get_permissions_in *in = NULL;
struct scmi_clk_get_permissions_out *out = NULL;
struct sandbox_scmi_clk *clk_state = NULL;
if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
!msg->out_msg || msg->out_msg_sz < sizeof(*out))
return -EINVAL;
in = (struct scmi_clk_get_permissions_in *)msg->in_msg;
out = (struct scmi_clk_get_permissions_out *)msg->out_msg;
clk_state = get_scmi_clk_state(in->clock_id);
if (!clk_state) {
dev_err(dev, "Unexpected clock ID %u\n", in->clock_id);
out->status = SCMI_NOT_FOUND;
} else {
out->permissions = clk_state->perm;
out->status = SCMI_SUCCESS;
}
return 0;
}
static int sandbox_scmi_rd_attribs(struct udevice *dev, struct scmi_msg *msg)
{
struct scmi_rd_attr_in *in = NULL;
@@ -1193,6 +1239,8 @@ static int sandbox_scmi_test_process_msg(struct udevice *dev,
return sandbox_proto_not_supported(msg);
switch (msg->message_id) {
case SCMI_PROTOCOL_VERSION:
return sandbox_scmi_clock_protocol_version(dev, msg);
case SCMI_PROTOCOL_ATTRIBUTES:
return sandbox_scmi_clock_protocol_attribs(dev, msg);
case SCMI_CLOCK_ATTRIBUTES:
@@ -1203,6 +1251,8 @@ static int sandbox_scmi_test_process_msg(struct udevice *dev,
return sandbox_scmi_clock_rate_get(dev, msg);
case SCMI_CLOCK_CONFIG_SET:
return sandbox_scmi_clock_gate(dev, msg);
case SCMI_CLOCK_GET_PERMISSIONS:
return sandbox_scmi_clock_permissions_get(dev, msg);
default:
break;
}
+26 -24
View File
@@ -97,6 +97,9 @@ struct udevice *scmi_get_protocol(struct udevice *dev,
case SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN:
proto = priv->voltagedom_dev;
break;
case SCMI_PROTOCOL_ID_PINCTRL:
proto = priv->pinctrl_dev;
break;
default:
dev_err(dev, "Protocol not supported\n");
proto = NULL;
@@ -147,6 +150,9 @@ static int scmi_add_protocol(struct udevice *dev,
case SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN:
priv->voltagedom_dev = proto;
break;
case SCMI_PROTOCOL_ID_PINCTRL:
priv->pinctrl_dev = proto;
break;
default:
dev_err(dev, "Protocol not supported\n");
return -EPROTO;
@@ -352,6 +358,22 @@ static int scmi_fill_base_info(struct udevice *agent, struct udevice *dev)
return 0;
}
static struct driver *scmi_proto_driver_get(unsigned int proto_id)
{
struct scmi_proto_driver *start, *entry;
int n_ents;
start = ll_entry_start(struct scmi_proto_driver, scmi_proto_driver);
n_ents = ll_entry_count(struct scmi_proto_driver, scmi_proto_driver);
for (entry = start; entry != start + n_ents; entry++) {
if (entry->match->proto_id == proto_id)
return entry->driver;
}
return NULL;
}
/*
* SCMI agent devices binds devices of various uclasses depending on
* the FDT description. scmi_bind_protocol() is a generic bind sequence
@@ -409,31 +431,11 @@ static int scmi_bind_protocols(struct udevice *dev)
drv = NULL;
name = ofnode_get_name(node);
switch (protocol_id) {
case SCMI_PROTOCOL_ID_POWER_DOMAIN:
if (CONFIG_IS_ENABLED(SCMI_POWER_DOMAIN) &&
scmi_protocol_is_supported(dev, protocol_id))
drv = DM_DRIVER_GET(scmi_power_domain);
break;
case SCMI_PROTOCOL_ID_CLOCK:
if (CONFIG_IS_ENABLED(CLK_SCMI) &&
scmi_protocol_is_supported(dev, protocol_id))
drv = DM_DRIVER_GET(scmi_clock);
break;
case SCMI_PROTOCOL_ID_RESET_DOMAIN:
if (IS_ENABLED(CONFIG_RESET_SCMI) &&
scmi_protocol_is_supported(dev, protocol_id))
drv = DM_DRIVER_GET(scmi_reset_domain);
break;
case SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN:
if (IS_ENABLED(CONFIG_DM_REGULATOR_SCMI) &&
scmi_protocol_is_supported(dev, protocol_id))
drv = DM_DRIVER_GET(scmi_voltage_domain);
break;
default:
break;
}
if (!scmi_protocol_is_supported(dev, protocol_id))
continue;
drv = scmi_proto_driver_get(protocol_id);
if (!drv) {
dev_dbg(dev, "Ignore unsupported SCMI protocol %#x\n",
protocol_id);
+13
View File
@@ -139,6 +139,19 @@ config PINCTRL_IMXRT
only parses the 'fsl,pins' property and configure related
registers.
config PINCTRL_IMX_SCMI
bool "IMX pinctrl SCMI driver"
depends on ARCH_IMX9 && PINCTRL_FULL
select PINCTRL_IMX
help
This provides a simple pinctrl driver for i.MX SoC which supports
SCMI. This feature depends on device tree configuration. This driver
is different from the linux one, this is a simple implementation,
only parses the 'fsl,pins' property and configure related
registers.
Say Y here to enable the imx pinctrl SCMI driver
config PINCTRL_VYBRID
bool "Vybrid (vf610) pinctrl driver"
depends on ARCH_VF610 && PINCTRL_FULL
+1
View File
@@ -11,3 +11,4 @@ obj-$(CONFIG_PINCTRL_IMX93) += pinctrl-imx93.o
obj-$(CONFIG_PINCTRL_MXS) += pinctrl-mxs.o
obj-$(CONFIG_PINCTRL_VYBRID) += pinctrl-vf610.o
obj-$(CONFIG_PINCTRL_IMXRT) += pinctrl-imxrt.o
obj-$(CONFIG_PINCTRL_IMX_SCMI) += pinctrl-imx-scmi.o
+165
View File
@@ -0,0 +1,165 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright 2025 NXP
*/
#include <asm/io.h>
#include <asm/mach-imx/sys_proto.h>
#include <dm.h>
#include <dm/device_compat.h>
#include <dm/devres.h>
#include <dm/pinctrl.h>
#include <scmi_agent.h>
#include <scmi_agent-uclass.h>
#include <scmi_protocols.h>
#include "pinctrl-imx.h"
#define DAISY_OFFSET_IMX95 0x408
/* SCMI pin control types */
#define PINCTRL_TYPE_MUX 192
#define PINCTRL_TYPE_CONFIG 193
#define PINCTRL_TYPE_DAISY_ID 194
#define PINCTRL_TYPE_DAISY_CFG 195
#define PINCTRL_NUM_CFGS_SHIFT 2
struct imx_scmi_pinctrl_priv {
u16 daisy_offset;
};
static int imx_pinconf_scmi_set(struct udevice *dev, u32 mux_ofs, u32 mux, u32 config_val,
u32 input_ofs, u32 input_val)
{
struct imx_scmi_pinctrl_priv *priv = dev_get_priv(dev);
int ret, num_cfgs = 0;
struct scmi_msg msg;
/* Call SCMI API to set the pin mux and configuration. */
struct scmi_pinctrl_config_set_out out;
struct scmi_pinctrl_config_set_in in = {
.identifier = mux_ofs / 4,
.function_id = 0xFFFFFFFF,
.attributes = 0,
};
if (mux_ofs) {
in.configs[num_cfgs].type = PINCTRL_TYPE_MUX;
in.configs[num_cfgs].val = mux;
num_cfgs++;
}
if (config_val) {
in.configs[num_cfgs].type = PINCTRL_TYPE_CONFIG;
in.configs[num_cfgs].val = config_val;
num_cfgs++;
}
if (input_ofs) {
in.configs[num_cfgs].type = PINCTRL_TYPE_DAISY_ID;
in.configs[num_cfgs].val = (input_ofs - priv->daisy_offset) / 4;
num_cfgs++;
in.configs[num_cfgs].type = PINCTRL_TYPE_DAISY_CFG;
in.configs[num_cfgs].val = input_val;
num_cfgs++;
}
/* Update the number of configs sent in this call. */
in.attributes = num_cfgs << PINCTRL_NUM_CFGS_SHIFT;
msg = SCMI_MSG_IN(SCMI_PROTOCOL_ID_PINCTRL,
SCMI_MSG_PINCTRL_CONFIG_SET, in, out);
ret = devm_scmi_process_msg(dev, &msg);
if (ret || out.status) {
dev_err(dev, "Failed to set PAD = %d, daisy = %d, scmi_err = %d, ret = %d\n",
mux_ofs / 4, input_ofs / 4, out.status, ret);
}
return ret;
}
static int imx_pinctrl_set_state_scmi(struct udevice *dev, struct udevice *config)
{
int mux_ofs, mux, config_val, input_reg, input_val;
u32 *pin_data;
int i, j = 0;
int npins;
int ret;
ret = imx_pinctrl_set_state_common(dev, config, FSL_PIN_SIZE,
&pin_data, &npins);
if (ret)
return ret;
/*
* Refer to linux documentation for details:
* Documentation/devicetree/bindings/pinctrl/fsl,imx-pinctrl.txt
*/
for (i = 0; i < npins; i++) {
mux_ofs = pin_data[j++];
/* Skip config_reg */
j++;
input_reg = pin_data[j++];
mux = pin_data[j++];
input_val = pin_data[j++];
config_val = pin_data[j++];
if (config_val & IMX_PAD_SION)
mux |= IOMUXC_CONFIG_SION;
config_val &= ~IMX_PAD_SION;
ret = imx_pinconf_scmi_set(dev, mux_ofs, mux, config_val, input_reg, input_val);
if (ret && ret != -EPERM) {
dev_err(dev, "Set pin %d, mux %d, val %d, error\n",
mux_ofs, mux, config_val);
}
}
devm_kfree(dev, pin_data);
return ret;
}
static const struct pinctrl_ops imx_scmi_pinctrl_ops = {
.set_state = imx_pinctrl_set_state_scmi,
};
static int imx_scmi_pinctrl_probe(struct udevice *dev)
{
struct imx_scmi_pinctrl_priv *priv = dev_get_priv(dev);
if (IS_ENABLED(CONFIG_IMX95))
priv->daisy_offset = DAISY_OFFSET_IMX95;
else
return -EINVAL;
return devm_scmi_of_get_channel(dev);
}
static int imx_scmi_pinctrl_bind(struct udevice *dev)
{
if (IS_ENABLED(CONFIG_IMX95))
return 0;
return -ENODEV;
}
U_BOOT_DRIVER(scmi_pinctrl_imx) = {
.name = "scmi_pinctrl_imx",
.id = UCLASS_PINCTRL,
.bind = imx_scmi_pinctrl_bind,
.probe = imx_scmi_pinctrl_probe,
.priv_auto = sizeof(struct imx_scmi_pinctrl_priv),
.ops = &imx_scmi_pinctrl_ops,
.flags = DM_FLAG_PRE_RELOC,
};
static struct scmi_proto_match match[] = {
{ .proto_id = SCMI_PROTOCOL_ID_PINCTRL },
{ /* Sentinel */ }
};
U_BOOT_SCMI_PROTO_DRIVER(scmi_pinctrl_imx, match);
+8
View File
@@ -11,6 +11,7 @@
#include <power-domain.h>
#include <power-domain-uclass.h>
#include <scmi_agent.h>
#include <scmi_agent-uclass.h>
#include <scmi_protocols.h>
#include <dm/device_compat.h>
@@ -190,3 +191,10 @@ U_BOOT_DRIVER(scmi_power_domain) = {
.probe = scmi_power_domain_probe,
.priv_auto = sizeof(struct scmi_power_domain_priv),
};
static struct scmi_proto_match match[] = {
{ .proto_id = SCMI_PROTOCOL_ID_POWER_DOMAIN },
{ /* Sentinel */ }
};
U_BOOT_SCMI_PROTO_DRIVER(scmi_power_domain, match);
+8
View File
@@ -8,6 +8,7 @@
#include <dm.h>
#include <errno.h>
#include <scmi_agent.h>
#include <scmi_agent-uclass.h>
#include <scmi_protocols.h>
#include <asm/types.h>
#include <dm/device.h>
@@ -202,3 +203,10 @@ U_BOOT_DRIVER(scmi_voltage_domain) = {
.id = UCLASS_NOP,
.bind = scmi_regulator_bind,
};
static struct scmi_proto_match match[] = {
{ .proto_id = SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN },
{ /* Sentinel */ }
};
U_BOOT_SCMI_PROTO_DRIVER(scmi_voltage_domain, match);
+8
View File
@@ -9,6 +9,7 @@
#include <errno.h>
#include <reset-uclass.h>
#include <scmi_agent.h>
#include <scmi_agent-uclass.h>
#include <scmi_protocols.h>
#include <asm/types.h>
@@ -81,3 +82,10 @@ U_BOOT_DRIVER(scmi_reset_domain) = {
.ops = &scmi_reset_domain_ops,
.probe = scmi_reset_probe,
};
static struct scmi_proto_match match[] = {
{ .proto_id = SCMI_PROTOCOL_ID_RESET_DOMAIN },
{ /* Sentinel */ }
};
U_BOOT_SCMI_PROTO_DRIVER(scmi_reset_domain, match);
+24
View File
@@ -0,0 +1,24 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright 2025 NXP
*/
#ifndef __IMX95_EVK_H
#define __IMX95_EVK_H
#include <linux/sizes.h>
#include <linux/stringify.h>
#include <asm/arch/imx-regs.h>
#define CFG_SYS_INIT_RAM_ADDR 0x90000000
#define CFG_SYS_INIT_RAM_SIZE 0x200000
#define CFG_SYS_SDRAM_BASE 0x90000000
#define PHYS_SDRAM 0x90000000
/* Totally 16GB */
#define PHYS_SDRAM_SIZE 0x70000000 /* 2GB - 256MB DDR */
#define PHYS_SDRAM_2_SIZE 0x380000000 /* 14GB */
#define WDOG_BASE_ADDR WDG3_BASE_ADDR
#endif
+16 -3
View File
@@ -157,7 +157,9 @@ enum imx8image_cmd {
CMD_SOC_TYPE,
CMD_CONTAINER,
CMD_IMAGE,
CMD_DATA
CMD_DATA,
CMD_DUMMY_V2X,
CMD_HOLD,
};
enum imx8image_core_type {
@@ -169,7 +171,9 @@ enum imx8image_core_type {
CFG_A35,
CFG_A55,
CFG_A53,
CFG_A72
CFG_A72,
CFG_M33,
CFG_OEI,
};
enum imx8image_fld_types {
@@ -208,7 +212,10 @@ typedef enum option_type {
FILEOFF,
MSG_BLOCK,
SENTINEL,
UPOWER
UPOWER,
OEI,
DUMMY_V2X,
HOLD,
} option_type_t;
typedef struct {
@@ -227,12 +234,16 @@ typedef struct {
#define CORE_CA35 4
#define CORE_CA72 5
#define CORE_SECO 6
#define CORE_M33 7
#define CORE_ULP_CM33 0x1
#define CORE_ULP_CA35 0x2
#define CORE_ULP_UPOWER 0x4
#define CORE_ULP_SENTINEL 0x6
#define CORE_IMX95_M33P 0
#define CORE_IMX95_A55C0 2
#define SC_R_OTP 357U
#define SC_R_DEBUG 354U
#define SC_R_ROM_0 236U
@@ -246,10 +257,12 @@ typedef struct {
#define IMG_TYPE_EXEC 0x03 /* Executable image type */
#define IMG_TYPE_DATA 0x04 /* Data image type */
#define IMG_TYPE_DCD_DDR 0x05 /* DCD/DDR image type */
#define IMG_TYPE_OEI 0x05 /* Optional Executable image type */
#define IMG_TYPE_SECO 0x06 /* SECO image type */
#define IMG_TYPE_SENTINEL 0x06 /* SENTINEL image type */
#define IMG_TYPE_PROV 0x07 /* Provisioning image type */
#define IMG_TYPE_DEK 0x08 /* DEK validation type */
#define IMG_TYPE_V2X_DUMMY 0x0E /* V2X Dummy image */
#define IMG_TYPE_SHIFT 0
#define IMG_TYPE_MASK 0x1f
+17
View File
@@ -27,6 +27,7 @@ struct scmi_channel;
* @clock_dev: SCMI clock protocol device
* @resetdom_dev: SCMI reset domain protocol device
* @voltagedom_dev: SCMI voltage domain protocol device
* @pinctrl_dev: SCMI pin control protocol device
*/
struct scmi_agent_priv {
u32 version;
@@ -43,6 +44,7 @@ struct scmi_agent_priv {
struct udevice *clock_dev;
struct udevice *resetdom_dev;
struct udevice *voltagedom_dev;
struct udevice *pinctrl_dev;
};
static inline u32 scmi_version(struct udevice *dev)
@@ -115,4 +117,19 @@ struct scmi_agent_ops {
struct scmi_msg *msg);
};
struct scmi_proto_match {
unsigned int proto_id;
};
struct scmi_proto_driver {
struct driver *driver;
const struct scmi_proto_match *match;
};
#define U_BOOT_SCMI_PROTO_DRIVER(__name, __match) \
ll_entry_declare(struct scmi_proto_driver, __name, scmi_proto_driver) = { \
.driver = llsym(struct driver, __name, driver), \
.match = __match, \
}
#endif /* _SCMI_TRANSPORT_UCLASS_H */
+103 -1
View File
@@ -24,6 +24,8 @@ enum scmi_std_protocol {
SCMI_PROTOCOL_ID_SENSOR = 0x15,
SCMI_PROTOCOL_ID_RESET_DOMAIN = 0x16,
SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN = 0x17,
SCMI_PROTOCOL_ID_PINCTRL = 0x19,
SCMI_PROTOCOL_ID_IMX_MISC = 0x84,
};
enum scmi_status_code {
@@ -49,6 +51,10 @@ enum scmi_discovery_id {
SCMI_PROTOCOL_MESSAGE_ATTRIBUTES = 0x2,
};
enum scmi_imx_misc_message_id {
SCMI_MISC_ROM_PASSOVER_GET = 0x7
};
/*
* SCMI Base Protocol
*/
@@ -139,7 +145,7 @@ struct scmi_base_discover_impl_version_out {
struct scmi_base_discover_list_protocols_out {
s32 status;
u32 num_protocols;
u32 protocols[3];
u32 protocols[];
};
/**
@@ -725,12 +731,15 @@ int scmi_pwd_name_get(struct udevice *dev, u32 domain_id, u8 **name);
/*
* SCMI Clock Protocol
*/
#define CLOCK_PROTOCOL_VERSION_3_0 0x30000
enum scmi_clock_message_id {
SCMI_CLOCK_ATTRIBUTES = 0x3,
SCMI_CLOCK_RATE_SET = 0x5,
SCMI_CLOCK_RATE_GET = 0x6,
SCMI_CLOCK_CONFIG_SET = 0x7,
SCMI_CLOCK_PARENT_SET = 0xD,
SCMI_CLOCK_GET_PERMISSIONS = 0xF,
};
#define SCMI_CLK_PROTO_ATTR_COUNT_MASK GENMASK(15, 0)
@@ -769,6 +778,7 @@ struct scmi_clk_attribute_in {
struct scmi_clk_attribute_out {
s32 status;
u32 attributes;
#define CLK_HAS_RESTRICTIONS(x) ((x) & BIT(1))
char clock_name[SCMI_CLOCK_NAME_LENGTH_MAX];
};
@@ -833,6 +843,45 @@ struct scmi_clk_rate_set_out {
s32 status;
};
/**
* struct scmi_clk_parent_state_in - Message payload for CLOCK_PARENT_SET command
* @clock_id: SCMI clock ID
* @parent_clk: SCMI clock ID
*/
struct scmi_clk_parent_set_in {
u32 clock_id;
u32 parent_clk;
};
/**
* struct scmi_clk_parent_set_out - Response payload for CLOCK_PARENT_SET command
* @status: SCMI command status
*/
struct scmi_clk_parent_set_out {
s32 status;
};
/**
* @clock_id: Identifier for the clock device.
*/
struct scmi_clk_get_permissions_in {
u32 clock_id;
};
/**
* @status: Negative 32-bit integers are used to return error status codes.
* @permissions: Bit[31] Clock state control, Bit[30] Clock parent control,
* Bit[29] Clock rate control, Bits[28:0] Reserved, must be zero.
*/
struct scmi_clk_get_permissions_out {
s32 status;
u32 permissions;
};
#define SUPPORT_CLK_STAT_CONTROL BIT(31)
#define SUPPORT_CLK_PARENT_CONTROL BIT(30)
#define SUPPORT_CLK_RATE_CONTROL BIT(29)
/*
* SCMI Reset Domain Protocol
*/
@@ -1005,4 +1054,57 @@ struct scmi_voltd_level_get_out {
s32 voltage_level;
};
/* SCMI Pinctrl Protocol */
enum scmi_pinctrl_message_id {
SCMI_MSG_PINCTRL_CONFIG_SET = 0x6
};
struct scmi_pin_config {
u32 type;
u32 val;
};
/**
* struct scmi_pad_config_set_in - Message payload for PAD_CONFIG_SET command
* @identifier: Identifier for the pin or group.
* @function_id: Identifier for the function selected to be enabled
* for the selected pin or group. This field is set to
* 0xFFFFFFFF if no function should be enabled by the
* pin or group.
* @attributes: Bits[31:11] Reserved, must be zero.
* Bit[10] Function valid.
* Bits[9:2] Number of configurations to set.
* Bits[1:0] Selector: Whether the identifier field
* refers to a pin or a group.
* @configs: Array of configurations.
*/
struct scmi_pinctrl_config_set_in {
u32 identifier;
u32 function_id;
u32 attributes;
struct scmi_pin_config configs[4];
};
struct scmi_pinctrl_config_set_out {
s32 status;
};
/* SCMI Perf Protocol */
enum scmi_perf_message_id {
SCMI_PERF_DOMAIN_ATTRIBUTES = 0x3,
SCMI_PERF_DESCRIBE_LEVELS = 0x4,
SCMI_PERF_LIMITS_SET = 0x5,
SCMI_PERF_LIMITS_GET = 0x6,
SCMI_PERF_LEVEL_SET = 0x7,
SCMI_PERF_LEVEL_GET = 0x8
};
struct scmi_perf_in {
u32 domain_id;
u32 perf_level;
};
struct scmi_perf_out {
s32 status;
};
#endif /* _SCMI_PROTOCOLS_H */
+10
View File
@@ -1663,6 +1663,16 @@ Properties / Entry arguments:
.. _etype_nxp_header_ddrfw:
Entry: nxp-header-ddrfw: add a header to DDR PHY firmware images
----------------------------------------------------------------
This entry is used to combine DDR PHY firmware images and their byte counts
together. See imx95_evk.rst for how to get DDR PHY Firmware Images.
.. _etype_opensbi:
Entry: opensbi: RISC-V OpenSBI fw_dynamic blob
+29
View File
@@ -0,0 +1,29 @@
# SPDX-License-Identifier: GPL-2.0+
#
# Copyright 2025 NXP
from binman.etype.section import Entry_section
class Entry_nxp_header_ddrfw(Entry_section):
"""Add a header to DDR PHY firmware images
This entry is used for i.MX95 to combine DDR PHY firmware images and their
byte counts together.
See imx95_evk.rst for how to get DDR PHY Firmware Images.
"""
def __init__(self, section, etype, node):
super().__init__(section, etype, node)
def BuildSectionData(self, required):
section_data = bytearray()
header_data = bytearray()
for entry in self._entries.values():
entry_data = entry.GetData(required)
section_data += entry_data
header_data += entry.contents_size.to_bytes(4, 'little')
return header_data + section_data
+11
View File
@@ -104,6 +104,8 @@ PRE_LOAD_VERSION = 0x11223344.to_bytes(4, 'big')
PRE_LOAD_HDR_SIZE = 0x00001000.to_bytes(4, 'big')
TI_BOARD_CONFIG_DATA = b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
TI_UNSECURE_DATA = b'unsecuredata'
IMX_LPDDR_IMEM_DATA = b'qwertyuiop1234567890'
IMX_LPDDR_DMEM_DATA = b'asdfghjklzxcvbnm'
# Subdirectory of the input dir to use to put test FDTs
TEST_FDT_SUBDIR = 'fdts'
@@ -202,6 +204,8 @@ class TestFunctional(unittest.TestCase):
TestFunctional._MakeInputFile('fsp_m.bin', FSP_M_DATA)
TestFunctional._MakeInputFile('fsp_s.bin', FSP_S_DATA)
TestFunctional._MakeInputFile('fsp_t.bin', FSP_T_DATA)
TestFunctional._MakeInputFile('lpddr5_imem.bin', IMX_LPDDR_IMEM_DATA)
TestFunctional._MakeInputFile('lpddr5_dmem.bin', IMX_LPDDR_DMEM_DATA)
cls._elf_testdir = os.path.join(cls._indir, 'elftest')
elf_test.BuildElfTestFiles(cls._elf_testdir)
@@ -7848,6 +7852,13 @@ fdt fdtmap Extract the devicetree blob from the fdtmap
"""Test that binman can produce an iMX8 image"""
self._DoTestFile('339_nxp_imx8.dts')
def testNxpHeaderDdrfw(self):
"""Test that binman can add a header to DDR PHY firmware images"""
data = self._DoReadFile('346_nxp_ddrfw_imx95.dts')
self.assertEqual(len(IMX_LPDDR_IMEM_DATA).to_bytes(4, 'little') +
len(IMX_LPDDR_DMEM_DATA).to_bytes(4, 'little') +
IMX_LPDDR_IMEM_DATA + IMX_LPDDR_DMEM_DATA, data)
def testFitSignSimple(self):
"""Test that image with FIT and signature nodes can be signed"""
if not elf.ELF_TOOLS:
+24
View File
@@ -0,0 +1,24 @@
// SPDX-License-Identifier: GPL-2.0+
/dts-v1/;
/ {
#address-cells = <1>;
#size-cells = <1>;
binman {
imx-lpddr {
type = "nxp-header-ddrfw";
imx-lpddr-imem {
filename = "lpddr5_imem.bin";
type = "blob-ext";
};
imx-lpddr-dmem {
filename = "lpddr5_dmem.bin";
type = "blob-ext";
};
};
};
};
+131 -16
View File
@@ -7,6 +7,7 @@
#include "imx8image.h"
#include <image.h>
#include <linux/sizes.h>
static int p_idx;
static int sector_size;
@@ -54,7 +55,9 @@ static table_entry_t imx8image_cmds[] = {
{CMD_CONTAINER, "CONTAINER", "new container", },
{CMD_IMAGE, "IMAGE", "new image", },
{CMD_DATA, "DATA", "new data", },
{-1, "", "", },
{CMD_DUMMY_V2X, "DUMMY_V2X", "v2x", },
{CMD_HOLD, "HOLD", "hold", },
{-1, "", "", }
};
static table_entry_t imx8image_core_entries[] = {
@@ -66,7 +69,9 @@ static table_entry_t imx8image_core_entries[] = {
{CFG_A55, "A55", "A55 core", },
{CFG_A53, "A53", "A53 core", },
{CFG_A72, "A72", "A72 core", },
{-1, "", "", },
{CFG_OEI, "OEI", "OEI", },
{CFG_M33, "M33", "M33 core", },
{-1, "", "", }
};
static table_entry_t imx8image_sector_size[] = {
@@ -144,6 +149,14 @@ static void parse_cfg_cmd(image_t *param_stack, int32_t cmd, char *token,
exit(EXIT_FAILURE);
}
break;
case CMD_DUMMY_V2X:
param_stack[p_idx].option = DUMMY_V2X;
param_stack[p_idx++].entry = (uint32_t)strtoll(token, NULL, 0);
break;
case CMD_HOLD:
param_stack[p_idx].option = HOLD;
param_stack[p_idx].entry = (uint32_t)strtoll(token, NULL, 0);
param_stack[p_idx++].filename = NULL;
default:
break;
}
@@ -221,6 +234,16 @@ static void parse_cfg_fld(image_t *param_stack, int32_t *cmd, char *token,
(*cmd == CMD_DATA) ? DATA : AP;
param_stack[p_idx].filename = token;
break;
case CFG_OEI:
param_stack[p_idx].option = OEI;
param_stack[p_idx].filename = token;
param_stack[p_idx].ext = CORE_CM4_0;
break;
case CFG_M33:
param_stack[p_idx].option = M40;
param_stack[p_idx].ext = 0;
param_stack[p_idx].filename = token;
break;
}
break;
case CFG_LOAD_ADDR:
@@ -238,9 +261,15 @@ static void parse_cfg_fld(image_t *param_stack, int32_t *cmd, char *token,
case CFG_A53:
case CFG_A55:
case CFG_A72:
case CFG_M33:
param_stack[p_idx++].entry =
(uint32_t)strtoll(token, NULL, 0);
break;
case CFG_OEI:
param_stack[p_idx].dst = (uint32_t)strtoll(token, NULL, 0);
param_stack[p_idx].entry = param_stack[p_idx].dst + 1;
p_idx++;
break;
}
default:
break;
@@ -549,6 +578,7 @@ static void set_image_array_entry(flash_header_v3_t *container,
char *tmp_filename, bool dcd_skip)
{
uint64_t entry = image_stack->entry;
uint64_t dst = image_stack->dst;
uint64_t core = image_stack->ext;
uint32_t meta;
char *tmp_name = "";
@@ -558,7 +588,9 @@ static void set_image_array_entry(flash_header_v3_t *container,
img->offset = offset; /* Is re-adjusted later */
img->size = size;
set_image_hash(img, tmp_filename, IMAGE_HASH_ALGO_DEFAULT);
if (type != DUMMY_V2X) {
set_image_hash(img, tmp_filename, IMAGE_HASH_ALGO_DEFAULT);
}
switch (type) {
case SECO:
@@ -580,6 +612,27 @@ static void set_image_array_entry(flash_header_v3_t *container,
img->dst = 0xe4000000; /* S400 IRAM base */
img->entry = 0xe4000000;
break;
case OEI:
if (soc != IMX9) {
fprintf(stderr, "Error: invalid core id: %" PRIi64 "\n", core);
exit(EXIT_FAILURE);
}
img->hab_flags |= IMG_TYPE_OEI;
if (core == CORE_CM4_0) {
img->hab_flags |= CORE_ULP_CM33 << BOOT_IMG_FLAGS_CORE_SHIFT;
meta = CORE_IMX95_M33P;
} else {
img->hab_flags |= CORE_ULP_CA35 << BOOT_IMG_FLAGS_CORE_SHIFT;
meta = CORE_IMX95_A55C0;
}
tmp_name = "OEI";
img->dst = (dst ? dst : entry);
img->entry = entry;
img->meta = meta;
custom_partition = 0;
break;
case AP:
if (soc == QX && core == CORE_CA35) {
meta = IMAGE_A35_DEFAULT_META(custom_partition);
@@ -587,8 +640,10 @@ static void set_image_array_entry(flash_header_v3_t *container,
meta = IMAGE_A53_DEFAULT_META(custom_partition);
} else if (soc == QM && core == CORE_CA72) {
meta = IMAGE_A72_DEFAULT_META(custom_partition);
} else if (((soc == ULP) || (soc == IMX9)) && core == CORE_CA35) {
} else if ((soc == ULP) && core == CORE_CA35) {
meta = 0;
} else if ((soc == IMX9) && core == CORE_CA35) {
meta = CORE_IMX95_A55C0;
} else {
fprintf(stderr,
"Error: invalid AP core id: %" PRIu64 "\n",
@@ -687,6 +742,15 @@ static void set_image_array_entry(flash_header_v3_t *container,
img->entry = 0x28300200;
}
break;
case DUMMY_V2X:
img->hab_flags |= IMG_TYPE_V2X_DUMMY;
img->hab_flags |= CORE_SC << BOOT_IMG_FLAGS_CORE_SHIFT;
tmp_name = "V2X Dummy";
set_image_hash(img, "/dev/null", IMAGE_HASH_ALGO_DEFAULT);
img->dst = entry;
img->entry = entry;
img->size = 0; /* dummy image has no size */
break;
default:
fprintf(stderr, "unrecognized image type (%d)\n", type);
exit(EXIT_FAILURE);
@@ -709,15 +773,26 @@ void set_container(flash_header_v3_t *container, uint16_t sw_version,
fprintf(stdout, "container flags: 0x%x\n", container->flags);
}
static int get_container_image_start_pos(image_t *image_stack, uint32_t align)
static int get_container_image_start_pos(image_t *image_stack, uint32_t align, uint32_t *v2x)
{
image_t *img_sp = image_stack;
/*8K total container header*/
int file_off = CONTAINER_IMAGE_ARRAY_START_OFFSET;
FILE *fd = NULL;
flash_header_v3_t header;
flash_header_v3_t *header;
flash_header_v3_t *header2;
void *p;
int ret;
p = calloc(1, SZ_4K);
if (!p) {
fprintf(stderr, "Fail to alloc 4K memory\n");
exit(EXIT_FAILURE);
}
header = p;
header2 = p + FIRST_CONTAINER_HEADER_LENGTH;
while (img_sp->option != NO_IMG) {
if (img_sp->option == APPEND) {
fd = fopen(img_sp->filename, "r");
@@ -726,7 +801,7 @@ static int get_container_image_start_pos(image_t *image_stack, uint32_t align)
exit(EXIT_FAILURE);
}
ret = fread(&header, sizeof(header), 1, fd);
ret = fread(header, SZ_4K, 1, fd);
if (ret != 1) {
printf("Failure Read header %d\n", ret);
exit(EXIT_FAILURE);
@@ -734,19 +809,27 @@ static int get_container_image_start_pos(image_t *image_stack, uint32_t align)
fclose(fd);
if (header.tag != IVT_HEADER_TAG_B0) {
fprintf(stderr, "header tag mismatched file %s\n", img_sp->filename);
if (header->tag != IVT_HEADER_TAG_B0) {
fprintf(stderr, "header tag mismatched \n");
exit(EXIT_FAILURE);
} else {
file_off +=
header.img[header.num_images - 1].size;
file_off = ALIGN(file_off, align);
if (header2->tag != IVT_HEADER_TAG_B0) {
file_off += header->img[header->num_images - 1].size;
file_off = ALIGN(file_off, align);
} else {
file_off = header2->img[header2->num_images - 1].offset + FIRST_CONTAINER_HEADER_LENGTH;
file_off += header2->img[header2->num_images - 1].size;
file_off = ALIGN(file_off, align);
fprintf(stderr, "Has 2nd container %x\n", file_off);
*v2x = true;
}
}
}
img_sp++;
}
free(p);
return file_off;
}
@@ -838,6 +921,7 @@ static int build_container(soc_type_t soc, uint32_t sector_size,
char *tmp_filename = NULL;
uint32_t size = 0;
uint32_t file_padding = 0;
uint32_t v2x = false;
int ret;
int container = -1;
@@ -861,7 +945,7 @@ static int build_container(soc_type_t soc, uint32_t sector_size,
set_imx_hdr_v3(&imx_header, 0);
set_imx_hdr_v3(&imx_header, 1);
file_off = get_container_image_start_pos(image_stack, sector_size);
file_off = get_container_image_start_pos(image_stack, sector_size, &v2x);
fprintf(stdout, "container image offset (aligned):%x\n", file_off);
/* step through image stack and generate the header */
@@ -870,6 +954,7 @@ static int build_container(soc_type_t soc, uint32_t sector_size,
/* stop once we reach null terminator */
while (img_sp->option != NO_IMG) {
switch (img_sp->option) {
case OEI:
case AP:
case M40:
case M41:
@@ -892,6 +977,30 @@ static int build_container(soc_type_t soc, uint32_t sector_size,
file_off += ALIGN(sbuf.st_size, sector_size);
break;
case DUMMY_V2X:
if (container < 0) {
fprintf(stderr, "No container found\n");
exit(EXIT_FAILURE);
}
tmp_filename = "dummy";
set_image_array_entry(&imx_header.fhdr[container],
soc,
img_sp,
file_off,
0,
tmp_filename,
dcd_skip);
img_sp->src = file_off;
break;
case HOLD:
if (container < 0) {
fprintf(stderr, "No container found\n");
exit(EXIT_FAILURE);
}
file_off += ALIGN(img_sp->entry, sector_size);
break;
case SECO:
case SENTINEL:
if (container < 0) {
@@ -963,11 +1072,15 @@ static int build_container(soc_type_t soc, uint32_t sector_size,
do {
if (img_sp->option == APPEND) {
copy_file(ofd, img_sp->filename, 0, 0);
file_padding += FIRST_CONTAINER_HEADER_LENGTH;
if (v2x)
file_padding += FIRST_CONTAINER_HEADER_LENGTH * 2;
else
file_padding += FIRST_CONTAINER_HEADER_LENGTH;
}
img_sp++;
} while (img_sp->option != NO_IMG);
fprintf(stderr, "%s: %x %d\n", __func__, file_padding, v2x);
/* Add padding or skip appended container */
ret = lseek(ofd, file_padding, SEEK_SET);
if (ret < 0) {
@@ -980,6 +1093,7 @@ static int build_container(soc_type_t soc, uint32_t sector_size,
/* Note: Image offset are not contained in the image */
tmp = flatten_container_header(&imx_header, container + 1,
&size, file_padding);
fprintf(stderr, "error writing image hdr %x\n", size);
/* Write image header */
if (write(ofd, tmp, size) != size) {
fprintf(stderr, "error writing image hdr\n");
@@ -1000,7 +1114,8 @@ static int build_container(soc_type_t soc, uint32_t sector_size,
img_sp->option == AP || img_sp->option == DATA ||
img_sp->option == SCD || img_sp->option == SCFW ||
img_sp->option == SECO || img_sp->option == MSG_BLOCK ||
img_sp->option == UPOWER || img_sp->option == SENTINEL) {
img_sp->option == UPOWER || img_sp->option == SENTINEL ||
img_sp->option == OEI) {
copy_file_aligned(ofd, img_sp->filename, img_sp->src,
sector_size);
}
@@ -1031,7 +1146,7 @@ int imx8image_copy_image(int outfd, struct image_tool_params *mparams)
fprintf(stdout, "CONTAINER SW VERSION:\t0x%04x\n", sw_version);
build_container(soc, sector_size, emmc_fastboot,
img_sp, dcd_skip, fuse_version, sw_version, outfd);
img_sp, false, fuse_version, sw_version, outfd);
return 0;
}
+8
View File
@@ -18,6 +18,14 @@ for f in $blobs; do
continue
fi
if [ $f = "m33-oei-ddrfw.bin" ]; then
continue
fi
if [ $f = "u-boot.bin" ]; then
continue
fi
if [ ! -f $tmp ]; then
echo "WARNING '$tmp' not found, resulting binary may be not-functional" >&2