diff options
| -rw-r--r-- | arch/arm/include/asm/arch-imx9/sys_proto.h | 11 | ||||
| -rw-r--r-- | arch/arm/mach-imx/imx9/clock.c | 31 | ||||
| -rw-r--r-- | arch/arm/mach-imx/imx9/soc.c | 107 | ||||
| -rw-r--r-- | board/freescale/imx93_evk/spl.c | 2 |
4 files changed, 143 insertions, 8 deletions
diff --git a/arch/arm/include/asm/arch-imx9/sys_proto.h b/arch/arm/include/asm/arch-imx9/sys_proto.h index 2f7a1292758..e4bf6a63424 100644 --- a/arch/arm/include/asm/arch-imx9/sys_proto.h +++ b/arch/arm/include/asm/arch-imx9/sys_proto.h @@ -8,7 +8,18 @@ #include <asm/mach-imx/sys_proto.h> +enum imx9_soc_voltage_mode { + VOLT_LOW_DRIVE = 0, + VOLT_NOMINAL_DRIVE, + VOLT_OVER_DRIVE, +}; + void soc_power_init(void); bool m33_is_rom_kicked(void); int m33_prepare(void); + +enum imx9_soc_voltage_mode soc_target_voltage_mode(void); + +#define is_voltage_mode(mode) (soc_target_voltage_mode() == (mode)) + #endif diff --git a/arch/arm/mach-imx/imx9/clock.c b/arch/arm/mach-imx/imx9/clock.c index 0abf4579a1e..1433e68874d 100644 --- a/arch/arm/mach-imx/imx9/clock.c +++ b/arch/arm/mach-imx/imx9/clock.c @@ -603,7 +603,7 @@ void init_clk_usdhc(u32 index) { u32 div; - if (IS_ENABLED(CONFIG_IMX9_LOW_DRIVE_MODE)) + if (is_voltage_mode(VOLT_LOW_DRIVE)) div = 3; /* 266.67 Mhz */ else div = 2; /* 400 Mhz */ @@ -700,8 +700,7 @@ void set_arm_core_max_clk(void) #endif -#if IS_ENABLED(CONFIG_IMX9_LOW_DRIVE_MODE) -struct imx_clk_setting imx_clk_settings[] = { +struct imx_clk_setting imx_clk_ld_settings[] = { /* Set A55 clk to 500M */ {ARM_A55_CLK_ROOT, SYS_PLL_PFD0, 2}, /* Set A55 periphal to 200M */ @@ -728,7 +727,7 @@ struct imx_clk_setting imx_clk_settings[] = { /* NIC_APB to 133M */ {NIC_APB_CLK_ROOT, SYS_PLL_PFD1_DIV2, 3} }; -#else + struct imx_clk_setting imx_clk_settings[] = { /* * Set A55 clk to 500M. This clock root is normally used as intermediate @@ -762,9 +761,18 @@ struct imx_clk_setting imx_clk_settings[] = { /* NIC_APB to 133M */ {NIC_APB_CLK_ROOT, SYS_PLL_PFD1_DIV2, 3} }; -#endif -int clock_init(void) +void bus_clock_init_low_drive(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(imx_clk_ld_settings); i++) { + ccm_clk_root_cfg(imx_clk_ld_settings[i].clk_root, + imx_clk_ld_settings[i].src, imx_clk_ld_settings[i].div); + } +} + +void bus_clock_init(void) { int i; @@ -772,9 +780,18 @@ int clock_init(void) ccm_clk_root_cfg(imx_clk_settings[i].clk_root, imx_clk_settings[i].src, imx_clk_settings[i].div); } +} - if (IS_ENABLED(CONFIG_IMX9_LOW_DRIVE_MODE)) +int clock_init(void) +{ + int i; + + if (is_voltage_mode(VOLT_LOW_DRIVE)) { + bus_clock_init_low_drive(); set_arm_clk(MHZ(900)); + } else { + bus_clock_init(); + } /* allow for non-secure access */ for (i = 0; i < OSCPLL_END; i++) diff --git a/arch/arm/mach-imx/imx9/soc.c b/arch/arm/mach-imx/imx9/soc.c index ba04abff262..52aafcbf99c 100644 --- a/arch/arm/mach-imx/imx9/soc.c +++ b/arch/arm/mach-imx/imx9/soc.c @@ -615,11 +615,99 @@ int arch_misc_init(void) 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) +{ +#define MAX_ASSIGNED_CLKS 8 + int cnt, j; + u32 assignedclks[MAX_ASSIGNED_CLKS]; /* max 8 clocks*/ + + 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; + + if (assignedclks[clk_index] <= new_rate) + return 0; + + assignedclks[clk_index] = new_rate; + for (j = 0; j < cnt; j++) + assignedclks[j] = cpu_to_fdt32(assignedclks[j]); + + return fdt_setprop(fdt, node_off, "assigned-clock-rates", &assignedclks, + cnt * sizeof(u32)); + } + + return -ENOENT; +} + +static int low_drive_freq_update(void *blob) +{ + int nodeoff, ret; + int i; + + /* 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) { if (fixup_thermal_trips(blob, "cpu-thermal")) printf("Failed to update cpu-thermal trip(s)"); + if (is_voltage_mode(VOLT_LOW_DRIVE)) + low_drive_freq_update(blob); + return 0; } @@ -943,3 +1031,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; +} diff --git a/board/freescale/imx93_evk/spl.c b/board/freescale/imx93_evk/spl.c index e5807134bb2..e4999baa95f 100644 --- a/board/freescale/imx93_evk/spl.c +++ b/board/freescale/imx93_evk/spl.c @@ -77,7 +77,7 @@ int power_init_board(void) /* enable DVS control through PMIC_STBY_REQ */ pmic_reg_write(dev, PCA9450_BUCK1CTRL, 0x59); - if (IS_ENABLED(CONFIG_IMX9_LOW_DRIVE_MODE)) { + if (is_voltage_mode(VOLT_LOW_DRIVE)) /* 0.75v for Low drive mode */ pmic_reg_write(dev, PCA9450_BUCK1OUT_DVS0, 0x0c); |
