diff options
-rw-r--r-- | arch/arm/include/asm/arch-imx9/imx-regs.h | 173 | ||||
-rw-r--r-- | arch/arm/include/asm/arch-imx9/sys_proto.h | 1 | ||||
-rw-r--r-- | arch/arm/mach-imx/imx9/soc.c | 101 |
3 files changed, 275 insertions, 0 deletions
diff --git a/arch/arm/include/asm/arch-imx9/imx-regs.h b/arch/arm/include/asm/arch-imx9/imx-regs.h index fa6951ebbe8..049eca4f3a7 100644 --- a/arch/arm/include/asm/arch-imx9/imx-regs.h +++ b/arch/arm/include/asm/arch-imx9/imx-regs.h @@ -21,6 +21,24 @@ #define FSB_BASE_ADDR 0x47510000UL +#define ANATOP_BASE_ADDR 0x44480000UL + +#define BLK_CTRL_WAKEUPMIX_BASE_ADDR 0x42420000 +#define BLK_CTRL_S_ANOMIX_BASE_ADDR 0x444f0000 + +#define SRC_IPS_BASE_ADDR (0x44460000) +#define SRC_GLOBAL_RBASE (SRC_IPS_BASE_ADDR + 0x0000) + +#define SRC_DDR_RBASE (SRC_IPS_BASE_ADDR + 0x1000) +#define SRC_ML_RBASE (SRC_IPS_BASE_ADDR + 0x1800) +#define SRC_MEDIA_RBASE (SRC_IPS_BASE_ADDR + 0x2400) +#define SRC_M33P_RBASE (SRC_IPS_BASE_ADDR + 0x2800) + +#define SRC_MIX_SLICE_FUNC_STAT_PSW_STAT BIT(0) +#define SRC_MIX_SLICE_FUNC_STAT_RST_STAT BIT(2) +#define SRC_MIX_SLICE_FUNC_STAT_ISO_STAT BIT(4) +#define SRC_MIX_SLICE_FUNC_STAT_MEM_STAT BIT(12) + #if !(defined(__KERNEL_STRICT_NAMES) || defined(__ASSEMBLY__)) #include <asm/types.h> #include <stdbool.h> @@ -49,6 +67,161 @@ struct mu_type { u32 reserved5[14]; u32 mu_attr; }; + +enum mix_power_domain { + MIX_PD_MEDIAMIX, + MIX_PD_MLMIX, + MIX_PD_DDRMIX, +}; + +enum src_mix_slice_id { + SRC_MIX_EDGELOCK = 0, + SRC_MIX_AONMIX = 1, + SRC_MIX_WAKEUPMIX = 2, + SRC_MIX_DDRMIX = 3, + SRC_MIX_DDRPHY = 4, + SRC_MIX_ML = 5, + SRC_MIX_NIC = 6, + SRC_MIX_HSIO = 7, + SRC_MIX_MEDIA = 8, + SRC_MIX_CM33 = 9, + SRC_MIX_CA55C0 = 10, + SRC_MIX_CA55C1 = 11, + SRC_MIX_CA55CLUSTER = 12, +}; + +enum src_mem_slice_id { + SRC_MEM_AONMIX = 0, + SRC_MEM_WAKEUPMIX = 1, + SRC_MEM_DDRMIX = 2, + SRC_MEM_DDRPHY = 3, + SRC_MEM_ML = 4, + SRC_MEM_NIC = 5, + SRC_MEM_OCRAM = 6, + SRC_MEM_HSIO = 7, + SRC_MEM_MEDIA = 8, + SRC_MEM_CA55C0 = 9, + SRC_MEM_CA55C1 = 10, + SRC_MEM_CA55CLUSTER = 11, + SRC_MEM_L3 = 12, +}; + +struct blk_ctrl_s_aonmix_regs { + u32 cm33_irq_mask[7]; + u32 initnsvtor; + u32 reserved1[8]; + u32 ca55_irq_mask[7]; + u32 initsvtor; + u32 m33_cfg; + u32 reserved2[11]; + u32 axbs_aon_ctrl; + u32 reserved3[27]; + u32 dap_access_stkybit; + u32 reserved4[3]; + u32 lp_handshake[2]; + u32 ca55_cpuwait; + u32 ca55_rvbaraddr0_l; + u32 ca55_rvbaraddr0_h; + u32 ca55_rvbaraddr1_l; + u32 ca55_rvbaraddr1_h; + u32 s401_irq_mask; + u32 s401_reset_req_mask; + u32 s401_halt_st; + u32 ca55_mode; + u32 nmi_mask; + u32 nmi_clr; + u32 wdog_any_mask; + u32 s4v1_ipi_noclk_ref1; +}; + +struct blk_ctrl_wakeupmix_regs { + u32 upper_addr; + u32 ipg_debug_cm33; + u32 reserved[2]; + u32 qch_dis; + u32 ssi; + u32 reserved1[1]; + u32 dexsc_err; + u32 mqs_setting; + u32 sai_clk_sel; + u32 eqos_gpr; + u32 enet_clk_sel; + u32 reserved2[1]; + u32 volt_detect; + u32 i3c2_wakeup; + u32 ipg_debug_ca55c0; + u32 ipg_debug_ca55c1; + u32 axi_attr_cfg; + u32 i3c2_sda_irq; +}; + +struct src_general_regs { + u32 reserved[1]; + u32 authen_ctrl; + u32 reserved1[2]; + u32 scr; + u32 srtmr; + u32 srmask; + u32 reserved2[1]; + u32 srmr[6]; + u32 reserved3[2]; + u32 sbmr[2]; + u32 reserved4[2]; + u32 srsr; + u32 gpr[19]; + u32 reserved5[24]; + u32 gpr20; + u32 cm_quiesce; + u32 cold_reset_ssar_ack_ctrl; + u32 sp_iso_ctrl; + u32 rom_lp_ctrl; + u32 a55_deny_stat; +}; + +struct src_mem_slice_regs { + u32 reserved[1]; + u32 mem_ctrl; + u32 memlp_ctrl_0; + u32 reserved1[1]; + u32 memlp_ctrl_1; + u32 memlp_ctrl_2; + u32 mem_stat; +}; + +struct src_mix_slice_regs { + u32 reserved[1]; + u32 authen_ctrl; + u32 reserved1[2]; + u32 lpm_setting[3]; + u32 reserved2[1]; + u32 slice_sw_ctrl; + u32 single_reset_sw_ctrl; + u32 reserved3[6]; + u32 a55_hdsk_ack_ctrl; + u32 a55_hdsk_ack_stat; + u32 reserved4[2]; + u32 ssar_ack_ctrl; + u32 ssar_ack_stat; + u32 reserved5[1]; + u32 iso_off_dly_por; + u32 iso_on_dly; + u32 iso_off_dly; + u32 psw_off_lf_dly; + u32 reserved6[1]; + u32 psw_off_hf_dly; + u32 psw_on_lf_dly; + u32 psw_on_hf_dly; + u32 reserved7[1]; + u32 psw_ack_ctrl[2]; + u32 psw_ack_stat; + u32 reserved8[1]; + u32 mtr_ack_ctrl; + u32 mtr_ack_stat; + u32 reserved9[2]; + u32 upi_stat[4]; + u32 fsm_stat; + u32 func_stat; +}; #endif #endif diff --git a/arch/arm/include/asm/arch-imx9/sys_proto.h b/arch/arm/include/asm/arch-imx9/sys_proto.h index 513aa0b9581..5ae7a043398 100644 --- a/arch/arm/include/asm/arch-imx9/sys_proto.h +++ b/arch/arm/include/asm/arch-imx9/sys_proto.h @@ -8,4 +8,5 @@ #include <asm/mach-imx/sys_proto.h> +void soc_power_init(void); #endif diff --git a/arch/arm/mach-imx/imx9/soc.c b/arch/arm/mach-imx/imx9/soc.c index c71a5a92504..68f3ddd4287 100644 --- a/arch/arm/mach-imx/imx9/soc.c +++ b/arch/arm/mach-imx/imx9/soc.c @@ -28,6 +28,7 @@ #include <asm/bootm.h> #include <asm/arch-imx/cpu.h> #include <asm/mach-imx/s400_api.h> +#include <linux/delay.h> DECLARE_GLOBAL_DATA_PTR; @@ -277,3 +278,103 @@ int timer_init(void) return 0; } + +static int mix_power_init(enum mix_power_domain pd) +{ + enum src_mix_slice_id mix_id; + enum src_mem_slice_id mem_id; + struct src_mix_slice_regs *mix_regs; + struct src_mem_slice_regs *mem_regs; + struct src_general_regs *global_regs; + u32 scr, val; + + switch (pd) { + case MIX_PD_MEDIAMIX: + mix_id = SRC_MIX_MEDIA; + mem_id = SRC_MEM_MEDIA; + scr = BIT(5); + + /* Enable S400 handshake */ + struct blk_ctrl_s_aonmix_regs *s_regs = + (struct blk_ctrl_s_aonmix_regs *)BLK_CTRL_S_ANOMIX_BASE_ADDR; + + setbits_le32(&s_regs->lp_handshake[0], BIT(13)); + break; + case MIX_PD_MLMIX: + mix_id = SRC_MIX_ML; + mem_id = SRC_MEM_ML; + scr = BIT(4); + break; + case MIX_PD_DDRMIX: + mix_id = SRC_MIX_DDRMIX; + mem_id = SRC_MEM_DDRMIX; + scr = BIT(6); + break; + default: + return -EINVAL; + } + + mix_regs = (struct src_mix_slice_regs *)(ulong)(SRC_IPS_BASE_ADDR + 0x400 * (mix_id + 1)); + mem_regs = + (struct src_mem_slice_regs *)(ulong)(SRC_IPS_BASE_ADDR + 0x3800 + 0x400 * mem_id); + global_regs = (struct src_general_regs *)(ulong)SRC_GLOBAL_RBASE; + + /* Allow NS to set it */ + setbits_le32(&mix_regs->authen_ctrl, BIT(9)); + + clrsetbits_le32(&mix_regs->psw_ack_ctrl[0], BIT(28), BIT(29)); + + /* mix reset will be held until boot core write this bit to 1 */ + setbits_le32(&global_regs->scr, scr); + + /* Enable mem in Low power auto sequence */ + setbits_le32(&mem_regs->mem_ctrl, BIT(2)); + + /* Set the power down state */ + val = readl(&mix_regs->func_stat); + if (val & SRC_MIX_SLICE_FUNC_STAT_PSW_STAT) { + /* The mix is default power off, power down it to make PDN_SFT bit + * aligned with FUNC STAT + */ + setbits_le32(&mix_regs->slice_sw_ctrl, BIT(31)); + val = readl(&mix_regs->func_stat); + + /* Since PSW_STAT is 1, can't be used for power off status (SW_CTRL BIT31 set)) */ + /* Check the MEM STAT change to ensure SSAR is completed */ + while (!(val & SRC_MIX_SLICE_FUNC_STAT_MEM_STAT)) + val = readl(&mix_regs->func_stat); + + /* wait few ipg clock cycles to ensure FSM done and power off status is correct */ + /* About 5 cycles at 24Mhz, 1us is enough */ + udelay(1); + } else { + /* The mix is default power on, Do mix power cycle */ + setbits_le32(&mix_regs->slice_sw_ctrl, BIT(31)); + val = readl(&mix_regs->func_stat); + while (!(val & SRC_MIX_SLICE_FUNC_STAT_PSW_STAT)) + val = readl(&mix_regs->func_stat); + } + + /* 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) + val = readl(&mix_regs->func_stat); + + return 0; +} + +void disable_isolation(void) +{ + struct src_general_regs *global_regs = (struct src_general_regs *)(ulong)SRC_GLOBAL_RBASE; + /* clear isolation for usbphy, dsi, csi*/ + writel(0x0, &global_regs->sp_iso_ctrl); +} + +void soc_power_init(void) +{ + mix_power_init(MIX_PD_MEDIAMIX); + mix_power_init(MIX_PD_MLMIX); + + disable_isolation(); +} |