summaryrefslogtreecommitdiff
path: root/arch/arm/mach-imx/imx9/soc.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-imx/imx9/soc.c')
-rw-r--r--arch/arm/mach-imx/imx9/soc.c258
1 files changed, 204 insertions, 54 deletions
diff --git a/arch/arm/mach-imx/imx9/soc.c b/arch/arm/mach-imx/imx9/soc.c
index f88e7a222dd..04b21207a28 100644
--- a/arch/arm/mach-imx/imx9/soc.c
+++ b/arch/arm/mach-imx/imx9/soc.c
@@ -96,10 +96,16 @@ int mmc_get_env_dev(void)
*/
u32 get_cpu_speed_grade_hz(void)
{
- u32 speed, max_speed;
+ int ret;
+ u32 bank, word, speed, max_speed;
u32 val;
- fuse_read(2, 3, &val);
+ bank = HW_CFG1 / NUM_WORDS_PER_BANK;
+ word = HW_CFG1 % NUM_WORDS_PER_BANK;
+ ret = fuse_read(bank, word, &val);
+ if (ret)
+ val = 0; /* If read fuse failed, return as blank fuse */
+
val = FIELD_GET(SPEED_GRADING_MASK, val) & 0xF;
speed = MHZ(2300) - val * MHZ(100);
@@ -122,9 +128,15 @@ u32 get_cpu_speed_grade_hz(void)
*/
u32 get_cpu_temp_grade(int *minc, int *maxc)
{
- u32 val;
+ int ret;
+ u32 bank, word, val;
+
+ bank = HW_CFG1 / NUM_WORDS_PER_BANK;
+ word = HW_CFG1 % NUM_WORDS_PER_BANK;
+ ret = fuse_read(bank, word, &val);
+ if (ret)
+ val = 0; /* If read fuse failed, return as blank fuse */
- fuse_read(2, 3, &val);
val = FIELD_GET(MARKETING_GRADING_MASK, val);
if (minc && maxc) {
@@ -160,13 +172,29 @@ static void set_cpu_info(struct ele_get_info_data *info)
static u32 get_cpu_variant_type(u32 type)
{
- /* word 19 */
- u32 val = readl((ulong)FSB_BASE_ADDR + 0x8000 + (19 << 2));
- u32 val2 = readl((ulong)FSB_BASE_ADDR + 0x8000 + (20 << 2));
+ u32 bank, word, val, val2;
+ int ret;
+
+ bank = HW_CFG1 / NUM_WORDS_PER_BANK;
+ word = HW_CFG1 % NUM_WORDS_PER_BANK;
+ ret = fuse_read(bank, word, &val);
+ if (ret)
+ val = 0; /* If read fuse failed, return as blank fuse */
+
+ bank = HW_CFG2 / NUM_WORDS_PER_BANK;
+ word = HW_CFG2 % NUM_WORDS_PER_BANK;
+ ret = fuse_read(bank, word, &val2);
+ if (ret)
+ val2 = 0; /* If read fuse failed, return as blank fuse */
+
bool npu_disable = !!(val & BIT(13));
bool core1_disable = !!(val & BIT(15));
u32 pack_9x9_fused = BIT(4) | BIT(17) | BIT(19) | BIT(24);
+ /* Low performance 93 part */
+ if (((val >> 6) & 0x3F) == 0xE && npu_disable)
+ return core1_disable ? MXC_CPU_IMX9301 : MXC_CPU_IMX9302;
+
if ((val2 & pack_9x9_fused) == pack_9x9_fused)
type = MXC_CPU_IMX9322;
@@ -216,15 +244,9 @@ static void disable_wdog(void __iomem *wdog_base)
void init_wdog(void)
{
- u32 src_val;
-
disable_wdog((void __iomem *)WDG3_BASE_ADDR);
disable_wdog((void __iomem *)WDG4_BASE_ADDR);
disable_wdog((void __iomem *)WDG5_BASE_ADDR);
-
- src_val = readl(0x54460018); /* reset mask */
- src_val &= ~0x1c;
- writel(src_val, 0x54460018);
}
static struct mm_region imx93_mem_map[] = {
@@ -480,12 +502,21 @@ void imx_get_mac_from_fuse(int dev_id, unsigned char *mac)
if (ret)
goto err;
- mac[0] = val[1] >> 24;
- mac[1] = val[1] >> 16;
- mac[2] = val[0] >> 24;
- mac[3] = val[0] >> 16;
- mac[4] = val[0] >> 8;
- mac[5] = val[0];
+ if (is_imx93() && is_soc_rev(CHIP_REV_1_0)) {
+ mac[0] = val[1] >> 24;
+ mac[1] = val[1] >> 16;
+ mac[2] = val[0] >> 24;
+ mac[3] = val[0] >> 16;
+ mac[4] = val[0] >> 8;
+ mac[5] = val[0];
+ } else {
+ mac[0] = val[0] >> 24;
+ mac[1] = val[0] >> 16;
+ mac[2] = val[0] >> 8;
+ mac[3] = val[0];
+ mac[4] = val[1] >> 24;
+ mac[5] = val[1] >> 16;
+ }
}
debug("%s: MAC%d: %02x.%02x.%02x.%02x.%02x.%02x\n",
@@ -507,64 +538,152 @@ int print_cpuinfo(void)
return 0;
}
-static int fixup_thermal_trips(void *blob, const char *name)
+void build_info(void)
+{
+ u32 fw_version, sha1, res, 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;
+}
+
+struct low_drive_freq_entry {
+ const char *node_path;
+ u32 clk;
+ u32 new_rate;
+};
+
+static int low_drive_fdt_fix_clock(void *fdt, int node_off, u32 clk_index, u32 new_rate)
{
- int minc, maxc;
- int node, trip;
+#define MAX_ASSIGNED_CLKS 8
+ int cnt, j;
+ u32 assignedclks[MAX_ASSIGNED_CLKS]; /* max 8 clocks*/
- node = fdt_path_offset(blob, "/thermal-zones");
- if (node < 0)
- return node;
+ cnt = fdtdec_get_int_array_count(fdt, node_off, "assigned-clock-rates",
+ assignedclks, MAX_ASSIGNED_CLKS);
+ if (cnt > 0) {
+ if (cnt <= clk_index)
+ return -ENOENT;
- node = fdt_subnode_offset(blob, node, name);
- if (node < 0)
- return node;
+ if (assignedclks[clk_index] <= new_rate)
+ return 0;
- node = fdt_subnode_offset(blob, node, "trips");
- if (node < 0)
- return node;
+ assignedclks[clk_index] = new_rate;
+ for (j = 0; j < cnt; j++)
+ assignedclks[j] = cpu_to_fdt32(assignedclks[j]);
- get_cpu_temp_grade(&minc, &maxc);
+ return fdt_setprop(fdt, node_off, "assigned-clock-rates", &assignedclks,
+ cnt * sizeof(u32));
+ }
- fdt_for_each_subnode(trip, blob, node) {
- const char *type;
- int temp, ret;
+ return -ENOENT;
+}
- type = fdt_getprop(blob, trip, "type", NULL);
- if (!type)
- continue;
+static int low_drive_freq_update(void *blob)
+{
+ int nodeoff, ret;
+ int i;
- temp = 0;
- if (!strcmp(type, "critical"))
- temp = 1000 * maxc;
- else if (!strcmp(type, "passive"))
- temp = 1000 * (maxc - 10);
- if (temp) {
- ret = fdt_setprop_u32(blob, trip, "temperature", temp);
- if (ret)
- return ret;
+ /* Update kernel dtb clocks for low drive mode */
+ struct low_drive_freq_entry table[] = {
+ {"/soc@0/bus@42800000/mmc@42850000", 0, 266666667},
+ {"/soc@0/bus@42800000/mmc@42860000", 0, 266666667},
+ {"/soc@0/bus@42800000/mmc@428b0000", 0, 266666667},
+ };
+
+ for (i = 0; i < ARRAY_SIZE(table); i++) {
+ nodeoff = fdt_path_offset(blob, table[i].node_path);
+ if (nodeoff >= 0) {
+ ret = low_drive_fdt_fix_clock(blob, nodeoff, table[i].clk,
+ table[i].new_rate);
+ if (!ret)
+ printf("%s freq updated\n", table[i].node_path);
+ }
+ }
+
+ return 0;
+}
+
+#ifdef CONFIG_OF_BOARD_FIXUP
+#ifndef CONFIG_SPL_BUILD
+int board_fix_fdt(void *fdt)
+{
+ /* Update dtb clocks for low drive mode */
+ if (is_voltage_mode(VOLT_LOW_DRIVE)) {
+ int nodeoff;
+ int i;
+
+ struct low_drive_freq_entry table[] = {
+ {"/soc@0/bus@42800000/mmc@42850000", 0, 266666667},
+ {"/soc@0/bus@42800000/mmc@42860000", 0, 266666667},
+ {"/soc@0/bus@42800000/mmc@428b0000", 0, 266666667},
+ };
+
+ for (i = 0; i < ARRAY_SIZE(table); i++) {
+ nodeoff = fdt_path_offset(fdt, table[i].node_path);
+ if (nodeoff >= 0)
+ low_drive_fdt_fix_clock(fdt, nodeoff, table[i].clk,
+ table[i].new_rate);
}
}
return 0;
}
+#endif
+#endif
int ft_system_setup(void *blob, struct bd_info *bd)
{
+ static const char * const nodes_path[] = {
+ "/cpus/cpu@0",
+ "/cpus/cpu@100",
+ };
+
if (fixup_thermal_trips(blob, "cpu-thermal"))
printf("Failed to update cpu-thermal trip(s)");
+ if (is_imx9351() || is_imx9331() || is_imx9321() || is_imx9311() || is_imx9301())
+ disable_cpu_nodes(blob, nodes_path, 1, 2);
+
+ if (is_voltage_mode(VOLT_LOW_DRIVE))
+ low_drive_freq_update(blob);
+
return 0;
}
#if defined(CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG)
void get_board_serial(struct tag_serialnr *serialnr)
{
- printf("UID: 0x%x 0x%x 0x%x 0x%x\n",
- gd->arch.uid[0], gd->arch.uid[1], gd->arch.uid[2], gd->arch.uid[3]);
+ 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 = gd->arch.uid[0];
- serialnr->high = gd->arch.uid[3];
+ serialnr->low = __be32_to_cpu(gd->arch.uid[1]);
+ serialnr->high = __be32_to_cpu(gd->arch.uid[0]);
}
#endif
@@ -586,7 +705,7 @@ int arch_cpu_init(void)
/* Disable wdog */
init_wdog();
- clock_init();
+ clock_init_early();
trdc_early_init();
@@ -752,7 +871,7 @@ static int mix_power_init(enum mix_power_domain pd)
/* power on */
clrbits_le32(&mix_regs->slice_sw_ctrl, BIT(31));
val = readl(&mix_regs->func_stat);
- while (val & SRC_MIX_SLICE_FUNC_STAT_ISO_STAT)
+ while (val & SRC_MIX_SLICE_FUNC_STAT_SSAR_STAT)
val = readl(&mix_regs->func_stat);
return 0;
@@ -792,7 +911,7 @@ int m33_prepare(void)
(struct src_general_regs *)(ulong)SRC_GLOBAL_RBASE;
struct blk_ctrl_s_aonmix_regs *s_regs =
(struct blk_ctrl_s_aonmix_regs *)BLK_CTRL_S_ANOMIX_BASE_ADDR;
- u32 val;
+ u32 val, i;
if (m33_is_rom_kicked())
return -EPERM;
@@ -817,6 +936,18 @@ int m33_prepare(void)
/* Set ELE LP handshake for M33 reset */
setbits_le32(&s_regs->lp_handshake[0], BIT(6));
+ /* OSCCA enabled, reconfigure TRDC for TCM access, otherwise ECC init will raise error */
+ val = readl(BLK_CTRL_NS_ANOMIX_BASE_ADDR + 0x28);
+ if (val & BIT(0)) {
+ trdc_mbc_set_control(0x44270000, 1, 0, 0x6600);
+
+ for (i = 0; i < 32; i++)
+ trdc_mbc_blk_config(0x44270000, 1, 3, 0, i, true, 0);
+
+ for (i = 0; i < 32; i++)
+ trdc_mbc_blk_config(0x44270000, 1, 3, 1, i, true, 0);
+ }
+
/* Clear M33 TCM for ECC */
memset((void *)(ulong)0x201e0000, 0, 0x40000);
@@ -864,3 +995,22 @@ int psci_sysreset_get_status(struct udevice *dev, char *buf, int size)
return 0;
}
+
+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_imx93()) {
+ if (speed == 1700000000)
+ voltage = VOLT_OVER_DRIVE;
+ else if (speed == 1400000000)
+ voltage = VOLT_NOMINAL_DRIVE;
+ else if (speed == 900000000 || speed == 800000000)
+ voltage = VOLT_LOW_DRIVE;
+ else
+ printf("Unexpected A55 freq %u, default to OD\n", speed);
+ }
+
+ return voltage;
+}