[RFC][PATCH] ARM: dts: mx6sx: Handle shared VDD_ARM/VDD_SOC rail
Marek Vasut
marex at denx.de
Thu Aug 4 06:11:33 PDT 2022
It seems that powering off the CPU core results in some stability bug
in case both the VDD_ARM and VDD_SOC power rails share the same supply.
Further investigation shows that the system hangs on WFI instruction,
which triggers pdn_req in GPC, which in turn powers down CPU core.
However, it turns out that not powering down the CPU core on pdn_req
is sufficient to always wake the system from WFI. This would indicate
that powering down the CPU core leads to some power leakage between
VDD_ARM and VDD_SOC, since VDD_ARM is off and VDD_SOC is still on.
This would in turn destabilize the CPU core and lead to the hang.
Further details at https://community.nxp.com/thread/504898
Signed-off-by: Marek Vasut <marex at denx.de>
---
Cc: Fabio Estevam <festevam at denx.de>
Cc: NXP Linux Team <linux-imx at nxp.com>
Cc: Peng Fan <peng.fan at nxp.com>
Cc: Shawn Guo <shawnguo at kernel.org>
To: linux-arm-kernel at lists.infradead.org
---
arch/arm/mach-imx/gpc.c | 55 ++++++++++++++++++++++++++++++++++++++++-
1 file changed, 54 insertions(+), 1 deletion(-)
diff --git a/arch/arm/mach-imx/gpc.c b/arch/arm/mach-imx/gpc.c
index ebc4339b8be48..87bba68c237c8 100644
--- a/arch/arm/mach-imx/gpc.c
+++ b/arch/arm/mach-imx/gpc.c
@@ -28,6 +28,7 @@
#define GPC_MAX_IRQS (IMR_NUM * 32)
static void __iomem *gpc_base;
+static bool shared_arm_soc_vdd_rail;
static u32 gpc_wake_irqs[IMR_NUM];
static u32 gpc_saved_imrs[IMR_NUM];
@@ -45,7 +46,17 @@ void imx_gpc_set_arm_power_down_timing(u32 sw2iso, u32 sw)
void imx_gpc_set_arm_power_in_lpm(bool power_off)
{
- writel_relaxed(power_off, gpc_base + GPC_PGC_CPU_PDN);
+ /*
+ * FIXME: Do not power off the CPU core on pdn_req , as it
+ * seems that on MX6SX, there is some sort of voltage leak
+ * between the VDD_ARM and VDD_SOC through the CPU core in
+ * case both are supplied from the same voltage rail.
+ *
+ * If VDD_ARM is off, then the leaking current from VDD_SOC
+ * destabilizes the CPU core and it might fail to wake up.
+ */
+ if (!shared_arm_soc_vdd_rail)
+ writel_relaxed(power_off, gpc_base + GPC_PGC_CPU_PDN);
}
void imx_gpc_set_l2_mem_power_in_lpm(bool power_off)
@@ -224,6 +235,46 @@ static const struct irq_domain_ops imx_gpc_domain_ops = {
.free = irq_domain_free_irqs_common,
};
+static void __init imx_gpc_check_shared_arm_soc_vdd_rail(void)
+{
+ struct device_node *np_vdd_arm, *np_vdd_soc, *np_vin_arm, *np_vin_soc;
+ struct device_node *cpus, *np;
+ static int once;
+
+ if (once++)
+ return;
+
+ cpus = of_find_node_by_path("/cpus");
+ if (!cpus)
+ return;
+
+ for_each_child_of_node(cpus, np) {
+ np_vdd_arm = of_parse_phandle(np, "arm-supply", 0);
+ if (!np_vdd_arm)
+ continue;
+
+ np_vin_arm = of_parse_phandle(np_vdd_arm, "vin-supply", 0);
+ if (!np_vin_arm)
+ continue;
+
+ np_vdd_soc = of_parse_phandle(np, "soc-supply", 0);
+ if (!np_vdd_soc)
+ continue;
+
+ np_vin_soc = of_parse_phandle(np_vdd_soc, "vin-supply", 0);
+ if (!np_vin_soc)
+ continue;
+
+ if (np_vin_arm != np_vin_soc)
+ continue;
+
+ /* VDD_ARM and VDD_SOC are connected to the same supply */
+ shared_arm_soc_vdd_rail = true;
+ pr_err("VDD_ARM/VDD_SOC share the same supply, cannot disable CPU core power in idle!\n");
+ return;
+ }
+}
+
static int __init imx_gpc_init(struct device_node *node,
struct device_node *parent)
{
@@ -245,6 +296,8 @@ static int __init imx_gpc_init(struct device_node *node,
if (WARN_ON(!gpc_base))
return -ENOMEM;
+ imx_gpc_check_shared_arm_soc_vdd_rail();
+
domain = irq_domain_add_hierarchy(parent_domain, 0, GPC_MAX_IRQS,
node, &imx_gpc_domain_ops,
NULL);
--
2.35.1
More information about the linux-arm-kernel
mailing list