diff --git a/arch/powerpc/include/asm/opal-api.h b/arch/powerpc/include/asm/opal-api.h
index 8365353330b4..93ea1f79e295 100644
--- a/arch/powerpc/include/asm/opal-api.h
+++ b/arch/powerpc/include/asm/opal-api.h
@@ -210,7 +210,9 @@
 #define OPAL_PCI_GET_PBCQ_TUNNEL_BAR		164
 #define OPAL_PCI_SET_PBCQ_TUNNEL_BAR		165
 #define	OPAL_NX_COPROC_INIT			167
-#define OPAL_LAST				167
+#define OPAL_IDLE_SAVE				170
+#define OPAL_IDLE_RESTORE			171
+#define OPAL_LAST				171
 
 #define QUIESCE_HOLD			1 /* Spin all calls at entry */
 #define QUIESCE_REJECT			2 /* Fail all calls with OPAL_BUSY */
diff --git a/arch/powerpc/include/asm/opal.h b/arch/powerpc/include/asm/opal.h
index ff3866473afe..26995e16171e 100644
--- a/arch/powerpc/include/asm/opal.h
+++ b/arch/powerpc/include/asm/opal.h
@@ -356,6 +356,9 @@ extern int opal_handle_hmi_exception(struct pt_regs *regs);
 extern void opal_shutdown(void);
 extern int opal_resync_timebase(void);
 
+extern int opal_cpuidle_save(u64 psscr);
+extern int opal_cpuidle_restore(u64 psscr, u64 srr1);
+
 extern void opal_lpc_init(void);
 
 extern void opal_kmsg_init(void);
diff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h
index 822d3236ad7f..26fa6c1836f4 100644
--- a/arch/powerpc/include/asm/processor.h
+++ b/arch/powerpc/include/asm/processor.h
@@ -510,7 +510,8 @@ static inline unsigned long get_clean_sp(unsigned long sp, int is_32)
 
 /* asm stubs */
 extern unsigned long isa300_idle_stop_noloss(unsigned long psscr_val);
-extern unsigned long isa300_idle_stop_mayloss(unsigned long psscr_val);
+extern unsigned long isa300_idle_stop_mayloss(unsigned long psscr_val,
+						bool request_opal_call);
 extern unsigned long isa206_idle_insn_mayloss(unsigned long type);
 
 extern unsigned long cpuidle_disable;
diff --git a/arch/powerpc/kernel/idle_book3s.S b/arch/powerpc/kernel/idle_book3s.S
index ffdee1ab4388..a2014d152035 100644
--- a/arch/powerpc/kernel/idle_book3s.S
+++ b/arch/powerpc/kernel/idle_book3s.S
@@ -52,14 +52,16 @@ _GLOBAL(isa300_idle_stop_noloss)
 _GLOBAL(isa300_idle_stop_mayloss)
 	mtspr 	SPRN_PSSCR,r3
 	std	r1,PACAR1(r13)
-	mflr	r4
+	mflr	r7
 	mfcr	r5
 	/* use stack red zone rather than a new frame */
 	addi	r6,r1,-INT_FRAME_SIZE
 	SAVE_GPR(2, r6)
 	SAVE_NVGPRS(r6)
-	std	r4,_LINK(r6)
+	std	r7,_LINK(r6)
 	std	r5,_CCR(r6)
+	cmpwi	r4,0
+	bne	opal_cpuidle_save
 	PPC_STOP
 	b	.	/* catch bugs */
 
diff --git a/arch/powerpc/platforms/powernv/idle.c b/arch/powerpc/platforms/powernv/idle.c
index 681a23a066bb..bcfe08022e65 100644
--- a/arch/powerpc/platforms/powernv/idle.c
+++ b/arch/powerpc/platforms/powernv/idle.c
@@ -171,6 +171,7 @@ static void pnv_fastsleep_workaround_apply(void *info)
 
 static bool power7_fastsleep_workaround_entry = true;
 static bool power7_fastsleep_workaround_exit = true;
+static bool request_opal_call = false;
 
 /*
  * Used to store fastsleep workaround state
@@ -604,6 +605,7 @@ static unsigned long power9_idle_stop(unsigned long psscr, bool mmu_on)
 	unsigned long mmcr0 = 0;
 	struct p9_sprs sprs;
 	bool sprs_saved = false;
+	bool is_hv_loss = false;
 
 	memset(&sprs, 0, sizeof(sprs));
 
@@ -648,7 +650,9 @@ static unsigned long power9_idle_stop(unsigned long psscr, bool mmu_on)
 		  */
 		mmcr0		= mfspr(SPRN_MMCR0);
 	}
-	if ((psscr & PSSCR_RL_MASK) >= pnv_first_hv_loss_level) {
+
+	is_hv_loss = (psscr & PSSCR_RL_MASK) >= pnv_first_hv_loss_level;
+	if (is_hv_loss && (!request_opal_call)) {
 		sprs.lpcr	= mfspr(SPRN_LPCR);
 		sprs.hfscr	= mfspr(SPRN_HFSCR);
 		sprs.fscr	= mfspr(SPRN_FSCR);
@@ -674,7 +678,8 @@ static unsigned long power9_idle_stop(unsigned long psscr, bool mmu_on)
 		atomic_start_thread_idle();
 	}
 
-	srr1 = isa300_idle_stop_mayloss(psscr);
+	srr1 = isa300_idle_stop_mayloss(psscr,
+			is_hv_loss && request_opal_call);
 
 #ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
 	local_paca->requested_psscr = 0;
@@ -685,6 +690,25 @@ static unsigned long power9_idle_stop(unsigned long psscr, bool mmu_on)
 	WARN_ON_ONCE(!srr1);
 	WARN_ON_ONCE(mfmsr() & (MSR_IR|MSR_DR));
 
+	/*
+	 * On POWER9, SRR1 bits do not match exactly as expected.
+	 * SRR1_WS_GPRLOSS (10b) can also result in SPR loss, so
+	 * always test PSSCR if there is any state loss.
+	 */
+	if (likely(((psscr & PSSCR_PLS) >> 60) < pnv_first_hv_loss_level)) {
+		if (sprs_saved)
+			atomic_stop_thread_idle();
+		goto out;
+	}
+
+	if (request_opal_call) {
+		opal_cpuidle_restore(psscr, srr1);
+		goto opal_return;
+	}
+
+	/* HV state loss */
+	BUG_ON(!sprs_saved);
+
 	if ((srr1 & SRR1_WAKESTATE) != SRR1_WS_NOLOSS) {
 		unsigned long mmcra;
 
@@ -712,19 +736,6 @@ static unsigned long power9_idle_stop(unsigned long psscr, bool mmu_on)
 	if (unlikely((srr1 & SRR1_WAKEMASK_P8) == SRR1_WAKEHMI))
 		hmi_exception_realmode(NULL);
 
-	/*
-	 * On POWER9, SRR1 bits do not match exactly as expected.
-	 * SRR1_WS_GPRLOSS (10b) can also result in SPR loss, so
-	 * always test PSSCR if there is any state loss.
-	 */
-	if (likely((psscr & PSSCR_RL_MASK) < pnv_first_hv_loss_level)) {
-		if (sprs_saved)
-			atomic_stop_thread_idle();
-		goto out;
-	}
-
-	/* HV state loss */
-	BUG_ON(!sprs_saved);
 
 	atomic_lock_thread_idle();
 
@@ -771,6 +782,7 @@ static unsigned long power9_idle_stop(unsigned long psscr, bool mmu_on)
 
 	mtspr(SPRN_SPRG3,	local_paca->sprg_vdso);
 
+opal_return:
 	if (!radix_enabled())
 		__slb_restore_bolted_realmode();
 
@@ -1284,6 +1296,7 @@ static int pnv_parse_cpuidle_dt(void)
 	u32 *temp_u32;
 	u64 *temp_u64;
 	const char **temp_string;
+	bool fall_back_to_opal = false;
 
 	np = of_find_node_by_path("/ibm,opal/power-mgt");
 	if (!np) {
@@ -1396,23 +1409,48 @@ static int pnv_parse_cpuidle_dt(void)
 	/* Parse each child node with appropriate parser_fn */
 	for_each_child_of_node(np1, dt_node) {
 		bool found_known_version = false;
-		/* we don't have state falling back to opal*/
-		for (i = 0; i < nr_known_versions ; i++) {
-			if (of_device_is_compatible(dt_node, known_versions[i].name)) {
-				rc = known_versions[i].parser_fn(dt_node);
+		if (!fall_back_to_opal) {
+			/* we don't have state falling back to opal*/
+			for (i = 0; i < nr_known_versions ; i++) {
+				if (of_device_is_compatible(dt_node, known_versions[i].name)) {
+					rc = known_versions[i].parser_fn(dt_node);
+					if (rc) {
+						pr_err("%s could not parse\n", known_versions[i].name);
+						continue;
+					}
+					found_known_version = true;
+				}
+			}
+		}
+
+		/*
+		 * If any previous state falls back to opal_call
+		 * Then all futher states will either call opal_call
+		 * or not be included for cpuidle/cpuoffline.
+		 *
+		 * Moreover, having any intermediate state with no
+		 * kernel support or opal support can be potentially
+		 * dangerous, as hardware can potentially wakeup from
+		 * that state. Hence, no futher states are added to
+		 * to cpuidle/cpuoffline
+		 */
+		if (!found_known_version || fall_back_to_opal) {
+			if (of_device_is_compatible(dt_node, "opal-support")) {
+				rc = known_versions[0].parser_fn(dt_node);
 				if (rc) {
-					pr_err("%s could not parse\n", known_versions[i].name);
+					pr_err("%s could not parse\n", "opal-support");
 					continue;
 				}
-				found_known_version = true;
+				fall_back_to_opal = true;
+			} else {
+				pr_info("Unsupported state, skipping all further state\n");
+				goto out;
 			}
 		}
-		if (!found_known_version) {
-			pr_info("Unsupported state, skipping all further state\n");
-			goto out;
-		}
 		nr_pnv_idle_states++;
 	}
+	if (fall_back_to_opal)
+		request_opal_call = true;
 out:
 	kfree(temp_u32);
 	kfree(temp_u64);
diff --git a/arch/powerpc/platforms/powernv/opal-wrappers.S b/arch/powerpc/platforms/powernv/opal-wrappers.S
index 251528231a9e..7a039a81a67e 100644
--- a/arch/powerpc/platforms/powernv/opal-wrappers.S
+++ b/arch/powerpc/platforms/powernv/opal-wrappers.S
@@ -331,3 +331,5 @@ OPAL_CALL(opal_pci_set_pbcq_tunnel_bar,		OPAL_PCI_SET_PBCQ_TUNNEL_BAR);
 OPAL_CALL(opal_sensor_read_u64,			OPAL_SENSOR_READ_U64);
 OPAL_CALL(opal_sensor_group_enable,		OPAL_SENSOR_GROUP_ENABLE);
 OPAL_CALL(opal_nx_coproc_init,			OPAL_NX_COPROC_INIT);
+OPAL_CALL(opal_cpuidle_save,			OPAL_IDLE_SAVE);
+OPAL_CALL(opal_cpuidle_restore,			OPAL_IDLE_RESTORE);
