
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@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 |= LTC3676_PGOOD_MASK; + pmic_reg_write(p, LTC3676_DVB1B, reg); + pmic_reg_read(p, LTC3676_DVB3B, ®); + 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 |= 0x1f; + pmic_reg_write(p, LTC3676_DVB1A, reg); + pmic_reg_read(p, LTC3676_DVB1B, ®); + reg |= 0x1f; + pmic_reg_write(p, LTC3676_DVB1B, reg); + /* SW3: VDD_ARM */ + pmic_reg_read(p, LTC3676_DVB3A, ®); + reg |= 0x1f; + pmic_reg_write(p, LTC3676_DVB3A, reg); + pmic_reg_read(p, LTC3676_DVB3B, ®); + 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@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