[PATCH v3 04/19] mach-k3: r5: common: introduce j7xx_board_is_resuming()
Richard Genoud (TI)
richard.genoud at bootlin.com
Wed Jun 24 09:44:44 CEST 2026
Add the capability to detect a resume on J7200, J784s4, J721e, 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: As this is called in board_init_f(), there's no BSS, so we can't
use global/static variables.
NB2: For j722s HS-* devices, we need an extra call to ctrl_mmr_unlock(),
and we have to use I2C API instead of PMIC API for this to work.
This is because bind is called before anything comes up, in between either
bootrom or TIFS messing up, clearing pad config and pd config.
Signed-off-by: Richard Genoud (TI) <richard.genoud at bootlin.com>
---
arch/arm/mach-k3/common.c | 6 ++
arch/arm/mach-k3/include/mach/hardware.h | 2 +
arch/arm/mach-k3/r5/lpm-common.c | 78 +++++++++++++++++++++++-
3 files changed, 84 insertions(+), 2 deletions(-)
diff --git a/arch/arm/mach-k3/common.c b/arch/arm/mach-k3/common.c
index 2f3df5519c53..3608b76ad4d8 100644
--- a/arch/arm/mach-k3/common.c
+++ b/arch/arm/mach-k3/common.c
@@ -605,3 +605,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 81b5f1fa45ea..1c8510bf99bf 100644
--- a/arch/arm/mach-k3/include/mach/hardware.h
+++ b/arch/arm/mach-k3/include/mach/hardware.h
@@ -126,4 +126,6 @@ struct rom_extended_boot_data {
u32 get_boot_device(void);
const char *get_reset_reason(void);
+bool j7xx_board_is_resuming(void);
+
#endif /* _ASM_ARCH_HARDWARE_H_ */
diff --git a/arch/arm/mach-k3/r5/lpm-common.c b/arch/arm/mach-k3/r5/lpm-common.c
index 6bab0189b032..95f777c5029f 100644
--- a/arch/arm/mach-k3/r5/lpm-common.c
+++ b/arch/arm/mach-k3/r5/lpm-common.c
@@ -6,18 +6,28 @@
* Copyright (C) 2026 Bootlin
*/
+#include <asm/global_data.h>
#include <clk.h>
+#include <dm/device.h>
#include <dm/read.h>
#include <elf.h>
+#include <i2c.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 FW_IMAGE_SIZE 0x80000
struct lpm_addr_info {
@@ -28,9 +38,73 @@ struct lpm_addr_info {
u32 size;
};
-__weak bool j7xx_board_is_resuming(void)
+/* This is used by J722s */
+__weak void ctrl_mmr_unlock(void) { }
+
+/* in board_init_f(), there's no BSS, so we can't use global/static variables */
+bool j7xx_board_is_resuming(void)
{
- return false;
+ struct udevice *pmic, *i2c;
+ int ret, magic;
+
+ if (gd_k3_resuming() != K3_RESUME_STATE_UNKNOWN)
+ goto end;
+
+ if (IS_ENABLED(CONFIG_SOC_K3_J722S)) {
+ /*
+ * On J722S devices, i2c access fails unless MMR
+ * registers are unlocked.
+ * Moreover, it fails also if we use PMIC API instead of I2C API.
+ */
+ ctrl_mmr_unlock();
+ ret = uclass_get_device_by_name(UCLASS_I2C,
+ "i2c at 2b200000", &i2c);
+ if (ret) {
+ printf("Getting I2C failed: %d\n", ret);
+ goto end;
+ }
+ ret = dm_i2c_probe(i2c, 0x48, 0, &pmic);
+ if (ret) {
+ printf("Getting PMIC failed: %d\n", ret);
+ goto end;
+ }
+ } else {
+ ret = uclass_get_device_by_name(UCLASS_PMIC,
+ "pmic at 48", &pmic);
+ if (ret) {
+ printf("Getting PMIC init failed: %d\n", ret);
+ goto end;
+ }
+ }
+ debug("%s: PMIC is detected (%s)\n", __func__, pmic->name);
+
+ if (IS_ENABLED(CONFIG_SOC_K3_J722S))
+ magic = dm_i2c_reg_read(pmic, K3_LPM_SCRATCH_PAD_REG_3);
+ else
+ magic = pmic_reg_read(pmic, K3_LPM_SCRATCH_PAD_REG_3);
+
+ if (magic == K3_LPM_MAGIC_SUSPEND) {
+ debug("%s: board is resuming\n", __func__);
+ gd_set_k3_resuming(K3_RESUME_STATE_RESUMING);
+
+ /* clean magic suspend */
+ if (IS_ENABLED(CONFIG_SOC_K3_J722S))
+ ret = dm_i2c_reg_write(pmic, K3_LPM_SCRATCH_PAD_REG_3, 0);
+ else
+ 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__);
+ gd_set_k3_resuming(K3_RESUME_STATE_BOOTING);
+ }
+end:
+ return gd_k3_resuming() == K3_RESUME_STATE_RESUMING;
}
static int extract_lpm_region(struct lpm_addr_info *mem_addr_lpm)
More information about the U-Boot
mailing list