imx9: scmi: add i.MX95 SoC and clock related code
This patch adds i.MX95 SoC and clock related code. Because they are based on SCMI, put them in the scmi subfolder. Signed-off-by: Alice Guo <alice.guo@nxp.com> Signed-off-by: Frank Li <Frank.Li@nxp.com> Signed-off-by: Ji Luo <ji.luo@nxp.com> Signed-off-by: Jindong Yue <jindong.yue@nxp.com> Signed-off-by: Peng Fan <peng.fan@nxp.com> Signed-off-by: Ranjani Vaidyanathan <ranjani.vaidyanathan@nxp.com> Signed-off-by: Ye Li <ye.li@nxp.com>
This commit is contained in:
@@ -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
|
||||
|
@@ -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);
|
||||
|
@@ -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
|
||||
|
6
arch/arm/mach-imx/imx9/scmi/Makefile
Normal file
6
arch/arm/mach-imx/imx9/scmi/Makefile
Normal 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
arch/arm/mach-imx/imx9/scmi/clock.c
Normal file
70
arch/arm/mach-imx/imx9/scmi/clock.c
Normal 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
arch/arm/mach-imx/imx9/scmi/clock_scmi.c
Normal file
133
arch/arm/mach-imx/imx9/scmi/clock_scmi.c
Normal 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;
|
||||
}
|
731
arch/arm/mach-imx/imx9/scmi/soc.c
Normal file
731
arch/arm/mach-imx/imx9/scmi/soc.c
Normal file
@@ -0,0 +1,731 @@
|
||||
// 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
|
@@ -110,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
|
||||
|
Reference in New Issue
Block a user