imx: imx9: Add MIX power init

Add power init of MEDIAMIX, MLMIX and DDRMIX. And clear isolation
of MIPI DSI/CSI, USBPHY after the power up.

SPL should call the power init in its boot sequence before accessing
above three MIX and USB.

Signed-off-by: Peng Fan <peng.fan@nxp.com>
diff --git a/arch/arm/include/asm/arch-imx9/imx-regs.h b/arch/arm/include/asm/arch-imx9/imx-regs.h
index fa6951e..049eca4 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 @@
 	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 513aa0b..5ae7a04 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 c71a5a9..68f3ddd 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 @@
 
 	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();
+}