[U-Boot] [PATCH 5/5] imx: ventana: enable ldo-bypass mode on compatible kernels if ldobypass env set

Tim Harvey tharvey at gateworks.com
Fri Jun 17 15:01:53 CEST 2016


The IMX6 has internal LDO's for VDD_ARM and VDD_SOC which can be used with a
fixed voltage PMIC. However, if you have a PMIC capable of varying its output
voltages, you can bypass the IMX6 LDO's in what is known as 'ldo-bypass' mode
in which case the IMX6 internal LDO's are bypassed (their FET's are set to
their maximum voltage effectively opening them completely) and the PMIC
adjusts the voltage rails per the imx6-cpufreq driver which implements
Dynamic Voltage and Frequency Scaling (DVFS).

The advantage of ldo-bypass mode is that it improves CPU power efficiency
by using the more efficient switching regulators in the PMIC which reduces
overall power consumption as well as the CPU thermal output power. The
downside of ldo-bypass mode is that switching regulators are inherently
more noisy that LDO's and in certain cases according to Freescale such as
when running at 1.2GHz for processor grades that support this frequency
ldo-enabled mode is required.

Gateworks Ventana downstream vendor kernels support ldo-bypass mode as they
have a PMIC driver capable of regulating VDD_ARM and VDD_SOC however recent
kernels have defaulted to ldo-enabled mode for greater stability.

This patch allows the bootloader to switch to ldo-bypass mode on kernels
and boards that support it by setting the ldobypass env var to 1.

Signed-off-by: Tim Harvey <tharvey at gateworks.com>
---
 board/gateworks/gw_ventana/gw_ventana.c | 125 +++++++++++++++++++++++++++++++-
 1 file changed, 124 insertions(+), 1 deletion(-)

diff --git a/board/gateworks/gw_ventana/gw_ventana.c b/board/gateworks/gw_ventana/gw_ventana.c
index a69549b..c02ded7 100644
--- a/board/gateworks/gw_ventana/gw_ventana.c
+++ b/board/gateworks/gw_ventana/gw_ventana.c
@@ -814,12 +814,129 @@ static inline const char *get_cpureg(void *blob, const char *name)
 		handle = fdt_getprop(blob, i, name, NULL);
 	if (handle)
 		i = fdt_node_offset_by_phandle(blob, fdt32_to_cpu(*handle));
-	if (i)
+	if (i) {
 		s = (char *)fdt_getprop(blob, i, "compatible", &len);
+		if (!s) {
+			i = fdt_parent_offset(blob, i);
+			i = fdt_parent_offset(blob, i);
+			s = (char *)fdt_getprop(blob, i, "compatible", &len);
+		}
+	}
 	debug("%s:%s\n", name, s);
 	return s;
 }
 
+static int dt_find_regulator(void *blob, int offset, const char *name)
+{
+	int i, len;
+	const char *n;
+
+	offset = fdt_first_subnode(blob, offset);
+	if (offset) {
+		fdt_for_each_subnode(blob, i, offset) {
+			n = fdt_getprop(blob, i, "regulator-name", &len);
+			if (strcmp(name, n) == 0)
+				return i;
+		}
+	}
+
+	return -FDT_ERR_NOTFOUND;
+}
+
+/* Enable LDO-bypass mode by manipulating device-tree cpu0 reguatlors
+ *
+ * This requires the following
+ * (which the Gateworks downstream vendor kernel have):
+ * - gpc: ldo-bypass property
+ * - ltc3676/pfuze100 driver with vddarm and vddsoc named regulators
+ *
+ * Returns: 0 on success, -EINVAL if dt does not support ldo-bypass
+ */
+static int disable_dt_ldo(void *blob)
+{
+	int i, cpu, gpc, gpu, vpu, pmic;
+	const u32 *bypass = 0;
+	int len;
+	u32 reg_arm = 0, reg_soc = 0, reg_pu = 0;
+
+	debug("%s\n", __func__);
+
+	/* get necessary dt nodes */
+	gpc = fdt_node_offset_by_compatible(blob, -1, "fsl,imx6q-gpc");
+	if (gpc < 0)
+		debug("%s: can't find gpc\n", __func__);
+	cpu = fdt_node_offset_by_compatible(blob, -1, "arm,cortex-a9");
+	if (cpu < 0)
+		debug("%s: can't find cpu\n", __func__);
+	vpu = fdt_node_offset_by_compatible(blob, -1, "fsl,imx6-vpu");
+	if (vpu < 0)
+		debug("%s: can't find vpu\n", __func__);
+	gpu = fdt_node_offset_by_compatible(blob, -1, "fsl,imx6q-gpu");
+	if (gpu < 0)
+		debug("%s: can't find gpu\n", __func__);
+	pmic = fdt_node_offset_by_compatible(blob, -1, "lltc,ltc3676");
+	if (pmic < 0)
+		pmic = fdt_node_offset_by_compatible(blob, -1, "fsl,pfuze100");
+	if (pmic < 0)
+		debug("%s: can't find LTC3676/PFUZE100 pmic\n", __func__);
+	if (gpc >= 0)
+		bypass = fdt_getprop(blob, gpc, "fsl,ldo-bypass", &len);
+
+	/*
+	 * Get PMIC VDD_ARM/VDD_SOC regulators
+	 * Note: this requires the PMIC regulators to be named
+	 */
+	i = dt_find_regulator(blob, pmic, "vddarm");
+	if (i > 0)
+		reg_arm = fdt_get_phandle(blob, i);
+	i = dt_find_regulator(blob, pmic, "vddsoc");
+	if (i > 0)
+		reg_soc = fdt_get_phandle(blob, i);
+	/* pu_dummy only exists on fsl 3.10.x kernels */
+	i = fdt_node_offset_by_compatible(blob, -1, "fsl,imx6-dummy-pureg");
+	if (i > 0) {
+		reg_pu = fdt_get_phandle(blob, i);
+		/* if pu_dummy exists, we need a handle to it */
+		if (!reg_pu) {
+			debug("%s failed - missing reg_pu handle\n", __func__);
+			return -EINVAL;
+		}
+	}
+
+	/* make sure we have a dt that supports ldo-bypass */
+	if (!gpc || !cpu || !vpu || !gpu || !pmic) {
+		debug("%s failed - missing gpc|cpu|vpu|gpu|pmic nodes\n",
+		      __func__);
+		return -EINVAL;
+	}
+	/* make sure we can switch to ldo-bypass: have pmic reg handles */
+	if (!reg_arm || !reg_soc || !bypass) {
+		debug("%s failed - missing reg_arm|reg_soc|bypass\n", __func__);
+		return -EINVAL;
+	}
+
+	if (fdt32_to_cpu(*bypass)) {
+		debug("%s LDO already bypassed\n", __func__);
+		return -EINVAL;
+	}
+
+	/* set cpu arm-supply and soc-supply to PMIC regulators */
+	fdt_setprop_inplace_u32(blob, cpu, "arm-supply", reg_arm);
+	fdt_setprop_inplace_u32(blob, cpu, "soc-supply", reg_soc);
+	/* set vpu/gpu/gpc pu supplies to dummy regulator (3.10.x only) */
+	if (reg_pu) {
+		fdt_setprop_inplace_u32(blob, cpu, "pu-supply", reg_pu);
+		fdt_setprop_inplace_u32(blob, gpu, "pu-supply", reg_pu);
+		fdt_setprop_inplace_u32(blob, vpu, "pu-supply", reg_pu);
+		fdt_setprop_inplace_u32(blob, gpc, "pu-supply", reg_pu);
+	}
+
+	/* set fsl,ldo-bypass property of gcp to 1 */
+	fdt_setprop_inplace_u32(blob, gpc, "fsl,ldo-bypass", 1);
+
+	return 0;
+}
+
 /*
  * called prior to booting kernel or by 'fdt boardsetup' command
  *
@@ -881,6 +998,12 @@ int ft_board_setup(void *blob, bd_t *bd)
 	/* set desired digital video capture format */
 	ft_sethdmiinfmt(blob, getenv("hdmiinfmt"));
 
+	/* enable LDO-bypass mode */
+	if (getenv("ldobypass")) {
+		if (!disable_dt_ldo(blob))
+			printf("   Set LDO-bypass mode\n");
+	}
+
 	/*
 	 * disable serial2 node for GW54xx for compatibility with older
 	 * 3.10.x kernel that improperly had this node enabled in the DT
-- 
1.9.1



More information about the U-Boot mailing list