[U-Boot] [PATCH 2/5] imx: ventana: fix PMIC rails for IMX6SDL in ldobypass mode

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


The IMX6SDL has a VDD_SOC max of 1.21v when operating in ldo-bypass mode.
While the kernel technically should be in charge of setting the rails and
bypassing the internal LDO regulators if implementing ldo-bypass mode, it
is impossible to meet the VDD_SOC_IN min and max requirements while switching.

It has been found that exceeding the max of 1.21v in ldo-bypass mode
causes PCIe aborts hanging the system and not meeting the min of 1.275v
in ldo-enabled mode can produce other issues.

As a work-around we will examine the device-tree bindings during ft_board_setup
to determine if we are booting a configured for ldo-bypass and will
adjust the PMIC rails, and bypass the LDO's before booting the kernel.

Signed-off-by: Tim Harvey <tharvey at gateworks.com>
---
 board/gateworks/gw_ventana/common.c     | 103 +++++++++++++++++++++++---------
 board/gateworks/gw_ventana/common.h     |   3 +-
 board/gateworks/gw_ventana/gw_ventana.c |  29 ++++++++-
 3 files changed, 106 insertions(+), 29 deletions(-)

diff --git a/board/gateworks/gw_ventana/common.c b/board/gateworks/gw_ventana/common.c
index 929dde9..366ea93 100644
--- a/board/gateworks/gw_ventana/common.c
+++ b/board/gateworks/gw_ventana/common.c
@@ -856,7 +856,7 @@ void setup_board_gpio(int board, struct ventana_board_info *info)
 	}
 }
 
-/* setup board specific PMIC */
+/* setup initial board specific PMIC */
 void setup_pmic(void)
 {
 	struct pmic *p;
@@ -894,32 +894,81 @@ void setup_pmic(void)
 		p = pmic_get("LTC3676_PMIC");
 		if (p && !pmic_probe(p)) {
 			puts("PMIC:  LTC3676\n");
-			/*
-			 * set board-specific scalar for max CPU frequency
-			 * per CPU based on the LDO enabled Operating Ranges
-			 * defined in the respective IMX6DQ and IMX6SDL
-			 * datasheets. The voltage resulting from the R1/R2
-			 * feedback inputs on Ventana is 1308mV. Note that this
-			 * is a bit shy of the Vmin of 1350mV in the datasheet
-			 * for LDO enabled mode but is as high as we can go.
-			 *
-			 * We will rely on an OS kernel driver to properly
-			 * regulate these per CPU operating point and use LDO
-			 * bypass mode when using the higher frequency
-			 * operating points to compensate as LDO bypass mode
-			 * allows the rails be 125mV lower.
-			 */
-			/* mask PGOOD during SW1 transition */
-			pmic_reg_write(p, LTC3676_DVB1B,
-				       0x1f | LTC3676_PGOOD_MASK);
-			/* set SW1 (VDD_SOC) */
-			pmic_reg_write(p, LTC3676_DVB1A, 0x1f);
-
-			/* mask PGOOD during SW3 transition */
-			pmic_reg_write(p, LTC3676_DVB3B,
-				       0x1f | LTC3676_PGOOD_MASK);
-			/* set SW3 (VDD_ARM) */
-			pmic_reg_write(p, LTC3676_DVB3A, 0x1f);
+
+			/* Mask PGOOD during voltage transitions */
+			pmic_reg_read(p, LTC3676_DVB1B, &reg);
+			reg |= LTC3676_PGOOD_MASK;
+			pmic_reg_write(p, LTC3676_DVB1B, reg);
+			pmic_reg_read(p, LTC3676_DVB3B, &reg);
+			reg |= LTC3676_PGOOD_MASK;
+			pmic_reg_write(p, LTC3676_DVB3B, reg);
+		}
+	}
+}
+
+/*
+ * adjust PMIC rails depending on ldo-bypass or ldo-enabled mode:
+ *
+ * Because the IMX6 VDD_ARM and VDD_SOC rails have minimum values in
+ * ldo-enabled mode which can exceed the maximum values when in
+ * ldo-bypass mode we must alter the rails depending on which mode is desired.
+ *
+ * Because ldo mode is very dependent on kernel support we can examine
+ * the device-tree to decide if the kernel uses ldo-bypass mode.
+ *
+ * ldo-bypass mode min/max values at 800MHz:
+ *  IMX6DQ:  VDDARM: 1.150v - 1.30v
+ *  IMX6DQ:  VDDSOC: 1.150v - 1.30v
+ *  IMX6SDL: VDDARM: 1.150v - 1.30v
+ *  IMX6SDL: VDDSOC: 1.150v - 1.21v <--- exceeding this causes PCIe aborts
+ *
+ * ldo-enabled mode min/max values at 800Mhz are 125mV above the ldo-bypass
+ * values.
+ */
+int adjust_pmic(char ldo_enabled)
+{
+	struct pmic *p;
+	u32 reg;
+
+	debug("%s ldo_%s\n", __func__, ldo_enabled ? "enabled" : "bypass");
+	i2c_set_bus_num(CONFIG_I2C_PMIC);
+
+	/* configure LTC3676 PMIC */
+	if (!i2c_probe(CONFIG_POWER_LTC3676_I2C_ADDR)) {
+		p = pmic_get("LTC3676_PMIC");
+		if (!p)
+			return 0;
+
+		debug("Adjusting %s for ldo-%sabled\n", p->name,
+		      ldo_enabled ? "en" : "dis");
+
+		/*
+		 * if ldo_enabled mode bump the default 1.185v rails
+		 * to 1.308v max
+		 */
+		if (ldo_enabled) {
+			/* SW1: VDD_SOC */
+			pmic_reg_read(p, LTC3676_DVB1A, &reg);
+			reg |= 0x1f;
+			pmic_reg_write(p, LTC3676_DVB1A, reg);
+			pmic_reg_read(p, LTC3676_DVB1B, &reg);
+			reg |= 0x1f;
+			pmic_reg_write(p, LTC3676_DVB1B, reg);
+			/* SW3: VDD_ARM */
+			pmic_reg_read(p, LTC3676_DVB3A, &reg);
+			reg |= 0x1f;
+			pmic_reg_write(p, LTC3676_DVB3A, reg);
+			pmic_reg_read(p, LTC3676_DVB3B, &reg);
+			reg |= 0x1f;
+			pmic_reg_write(p, LTC3676_DVB3B, reg);
+		} else {
+			/* set max value to bypass FET's */
+			debug("bypassing LDO's\n");
+			set_ldo_voltage(LDO_ARM, 1500);
+			set_ldo_voltage(LDO_PU, 1500);
+			set_ldo_voltage(LDO_SOC, 1500);
 		}
 	}
+
+	return 1;
 }
diff --git a/board/gateworks/gw_ventana/common.h b/board/gateworks/gw_ventana/common.h
index d037767..3bea94b 100644
--- a/board/gateworks/gw_ventana/common.h
+++ b/board/gateworks/gw_ventana/common.h
@@ -87,8 +87,9 @@ extern struct ventana gpio_cfg[GW_UNKNOWN];
 void setup_ventana_i2c(void);
 /* configure uart iomux */
 void setup_iomux_uart(void);
-/* conifgure PMIC */
+/* configure PMIC */
 void setup_pmic(void);
+int adjust_pmic(char ldo_enabled);
 /* configure gpio iomux/defaults */
 void setup_iomux_gpio(int board, struct ventana_board_info *);
 /* late setup of GPIO (configuration per baseboard and env) */
diff --git a/board/gateworks/gw_ventana/gw_ventana.c b/board/gateworks/gw_ventana/gw_ventana.c
index 82313e8..a69549b 100644
--- a/board/gateworks/gw_ventana/gw_ventana.c
+++ b/board/gateworks/gw_ventana/gw_ventana.c
@@ -802,6 +802,24 @@ static inline void ft_delprop_path(void *blob, const char *path,
 	}
 }
 
+/* return the 'compatible' property of a cpu regulator */
+static inline const char *get_cpureg(void *blob, const char *name)
+{
+	const u32 *handle = NULL;
+	int i, len = 0;
+	const char *s = NULL;
+
+	i = fdt_path_offset(blob, "/cpus/cpu at 0");
+	if (i)
+		handle = fdt_getprop(blob, i, name, NULL);
+	if (handle)
+		i = fdt_node_offset_by_phandle(blob, fdt32_to_cpu(*handle));
+	if (i)
+		s = (char *)fdt_getprop(blob, i, "compatible", &len);
+	debug("%s:%s\n", name, s);
+	return s;
+}
+
 /*
  * called prior to booting kernel or by 'fdt boardsetup' command
  *
@@ -822,7 +840,7 @@ int ft_board_setup(void *blob, bd_t *bd)
 	const char *model = getenv("model");
 	const char *display = getenv("display");
 	int i;
-	char rev = 0;
+	char rev = 0, ldo_enabled = 0;
 
 	/* determine board revision */
 	for (i = sizeof(ventana_info.model) - 1; i > 0; i--) {
@@ -976,6 +994,15 @@ int ft_board_setup(void *blob, bd_t *bd)
 				"no-1-8-v");
 	}
 
+	/* Determine if we have a kernel using the internal IMX LDO */
+	if (!strcmp("fsl,anatop-regulator", get_cpureg(blob, "arm-supply")) &&
+	    !strcmp("fsl,anatop-regulator", get_cpureg(blob, "pu-supply")) &&
+	    !strcmp("fsl,anatop-regulator", get_cpureg(blob, "soc-supply")))
+		ldo_enabled = 1;
+	printf("   Config LDO-%s mode\n", ldo_enabled ? "enabled" : "bypass");
+	/* Adjust pmic rails depending on LDO enabled vs bypass */
+	adjust_pmic(ldo_enabled);
+
 	/*
 	 * Peripheral Config:
 	 *  remove nodes by alias path if EEPROM config tells us the
-- 
1.9.1



More information about the U-Boot mailing list