Add the capability to detect a resume on J7200, J784s4, j722s, j721s2
SoCs.

To detect the resume, SPL searches a magic value (0xBA) in a register
of PMIC.
This value is set by DM-Firmware during the suspend sequence.

NB: Although this is called in board_init_f(), we can use global/static
variables because CONFIG_SPL_EARLY_BSS is selected.

Signed-off-by: Richard Genoud (TI) <[email protected]>
---
 arch/arm/mach-k3/common.c                |  6 +++
 arch/arm/mach-k3/include/mach/hardware.h |  1 +
 arch/arm/mach-k3/r5/lpm-common.c         | 53 +++++++++++++++++++++++-
 3 files changed, 58 insertions(+), 2 deletions(-)

diff --git a/arch/arm/mach-k3/common.c b/arch/arm/mach-k3/common.c
index 6e382efdb3be..d934f732b330 100644
--- a/arch/arm/mach-k3/common.c
+++ b/arch/arm/mach-k3/common.c
@@ -713,3 +713,9 @@ int spl_start_uboot(void)
        return 0;
 }
 #endif
+
+/* if r5/lpm-common.c is compiled, this will be overridden */
+__weak bool j7xx_board_is_resuming(void)
+{
+       return false;
+}
diff --git a/arch/arm/mach-k3/include/mach/hardware.h 
b/arch/arm/mach-k3/include/mach/hardware.h
index 2c771a1195f5..c45bd3747163 100644
--- a/arch/arm/mach-k3/include/mach/hardware.h
+++ b/arch/arm/mach-k3/include/mach/hardware.h
@@ -137,6 +137,7 @@ u32 get_boot_device(void);
 const char *get_reset_reason(void);
 enum k3_device_type get_device_type(void);
 int k3_fit_config_match_security_state(const char *name);
+bool j7xx_board_is_resuming(void);
 
 #define writel_verify(val, addr) \
 do { \
diff --git a/arch/arm/mach-k3/r5/lpm-common.c b/arch/arm/mach-k3/r5/lpm-common.c
index 91707fd19501..5d484f6df037 100644
--- a/arch/arm/mach-k3/r5/lpm-common.c
+++ b/arch/arm/mach-k3/r5/lpm-common.c
@@ -7,17 +7,25 @@
  */
 
 #include <clk.h>
+#include <dm/device.h>
 #include <dm/read.h>
 #include <elf.h>
 #include <linux/printk.h>
 #include <linux/soc/ti/ti_sci_protocol.h>
 #include <power-domain.h>
+#include <power/pmic.h>
 #include <remoteproc.h>
 #include <mach/security.h>
 
 #include "../common.h"
 #include "../lpm-common.h"
 
+/* Magic value in PMIC register to indicate the suspend state (SOC_OFF) */
+#define K3_LPM_MAGIC_SUSPEND 0xba
+
+/* PMIC register where the magic value resides */
+#define K3_LPM_SCRATCH_PAD_REG_3 0xcb
+
 #define CONTEXT_SAVE_SZ        0x80000
 #define ATF_CERT_SZ    0x80000
 #define OPTEE_CERT_SZ  0x100000
@@ -32,9 +40,50 @@ struct lpm_addr_info {
        u32 size;
 };
 
-__weak bool j7xx_board_is_resuming(void)
+enum k3_resume_state {
+       K3_RESUME_STATE_UNKNOWN = 0,
+       K3_RESUME_STATE_BOOTING,
+       K3_RESUME_STATE_RESUMING
+};
+
+bool j7xx_board_is_resuming(void)
 {
-       return false;
+       static enum k3_resume_state k3_resuming;
+       struct udevice *pmic;
+       int ret, magic;
+
+       if (k3_resuming != K3_RESUME_STATE_UNKNOWN)
+               goto end;
+
+       ret = uclass_get_device_by_name(UCLASS_PMIC,
+                                       "pmic@48", &pmic);
+       if (ret) {
+               printf("Getting PMIC init failed: %d\n", ret);
+               goto end;
+       }
+       debug("%s: PMIC is detected (%s)\n", __func__, pmic->name);
+
+       magic = pmic_reg_read(pmic, K3_LPM_SCRATCH_PAD_REG_3);
+
+       if (magic == K3_LPM_MAGIC_SUSPEND) {
+               debug("%s: board is resuming\n", __func__);
+               k3_resuming = K3_RESUME_STATE_RESUMING;
+
+               /* clean magic suspend */
+               ret = pmic_reg_write(pmic, K3_LPM_SCRATCH_PAD_REG_3, 0);
+
+               if (ret)
+                       printf("Failed to clean magic value for suspend 
detection in PMIC\n");
+               /*
+                * For robustness, the DM should also clean the magic value at
+                * startup.
+                */
+       } else {
+               debug("%s: board is booting (no resume detected)\n", __func__);
+               k3_resuming = K3_RESUME_STATE_BOOTING;
+       }
+end:
+       return k3_resuming == K3_RESUME_STATE_RESUMING;
 }
 
 static const char *lpm_core_compatible;
-- 
2.55.0

Reply via email to