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 <thar...@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 _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot