[U-Boot] [PATCH 00/12] imx:mx6 add ldo bypass

This patch set is based on these three patches: https://patchwork.ozlabs.org/patch/426621/ https://patchwork.ozlabs.org/patch/426623/ https://patchwork.ozlabs.org/patch/426622/
If want to test this patch set, please first apply the up 3 patches.
This patch set is mainly to add ldo bypass support.
Since pmic related function is not readly in previous patch, patch 1/12, patch 2/12, patch 3/12 is first to add pmic related support, such as power_init_board, related iomux/pad settings and configuration in header file. Then ldo bypass function can be implemented.
patch 4/12 is to update mxc_ccm_regs with more registers, since ldo setting will use them.
patch 5/12 is to update fuse_bank0_regs, since ldo setting will check it.
patch 6/12 is to add a macro for setting voltage easily.
patch 7/12 is to add ldo bypass related common function.
patch 8/12, patch 9/12, patch 10/12, patch 11/12 is to implement ldo_mode_set in different boards' file.
patch 12/12 is to invoke ldo_mode_set in arch_preboot_os. Future work will integrate Device tree for i.MX6 U-Boot. Then we can move it to power_init_board.
More detailed info can see each patch's commit log.
Peng Fan (12): imx:mx6slevk add pmic and i2c configuration imx:mx6sl add I2c pad settings imx:mx6slevk implement power init board imx:mx6 update mxc_ccm_reg imx:mx6 update fuse_bank0_regs pmic:pfuze add macro for setting voltage imx:mx6 Support LDO bypass imx:mx6slevk add ldo mode set function imx:mx6sabresd Add ldo_mode_set function imx:mx6sxsabresd add ldo mode set function imx:mx6qsabreauto add ldo mode init ARM:imx call ldo_mode_set in arch_preboot_os
arch/arm/cpu/armv7/mx6/soc.c | 141 ++++++++++++++++++++++++++ arch/arm/imx-common/cpu.c | 4 + arch/arm/include/asm/arch-mx6/crm_regs.h | 87 ++++++++++++++++ arch/arm/include/asm/arch-mx6/imx-regs.h | 12 ++- arch/arm/include/asm/arch-mx6/mx6sl_pins.h | 5 + arch/arm/include/asm/arch-mx6/sys_proto.h | 9 ++ board/freescale/mx6qsabreauto/mx6qsabreauto.c | 31 ++++++ board/freescale/mx6sabresd/mx6sabresd.c | 85 ++++++++++++++++ board/freescale/mx6slevk/mx6slevk.c | 100 ++++++++++++++++++ board/freescale/mx6sxsabresd/mx6sxsabresd.c | 50 +++++++++ include/configs/mx6qsabreauto.h | 2 + include/configs/mx6sabresd.h | 2 + include/configs/mx6slevk.h | 14 +++ include/configs/mx6sxsabresd.h | 2 + include/power/pfuze100_pmic.h | 2 + 15 files changed, 542 insertions(+), 4 deletions(-)

Add pmic and i2c configuration in board header file.
Signed-off-by: Peng Fan Peng.Fan@freescale.com --- include/configs/mx6slevk.h | 12 ++++++++++++ 1 file changed, 12 insertions(+)
diff --git a/include/configs/mx6slevk.h b/include/configs/mx6slevk.h index e6c4130..9fd7619 100644 --- a/include/configs/mx6slevk.h +++ b/include/configs/mx6slevk.h @@ -48,6 +48,18 @@ #define CONFIG_CMD_FAT #define CONFIG_DOS_PARTITION
+/* I2C Configs */ +#define CONFIG_CMD_I2C +#define CONFIG_SYS_I2C +#define CONFIG_SYS_I2C_MXC +#define CONFIG_SYS_I2C_SPEED 100000 + +/* PMIC */ +#define CONFIG_POWER +#define CONFIG_POWER_I2C +#define CONFIG_POWER_PFUZE100 +#define CONFIG_POWER_PFUZE100_I2C_ADDR 0x08 + #define CONFIG_CMD_PING #define CONFIG_CMD_DHCP #define CONFIG_CMD_MII

This few pad settings are for pmic i2c.
Signed-off-by: Peng Fan Peng.Fan@freescale.com --- arch/arm/include/asm/arch-mx6/mx6sl_pins.h | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/arch/arm/include/asm/arch-mx6/mx6sl_pins.h b/arch/arm/include/asm/arch-mx6/mx6sl_pins.h index 9ded3d8..0475203 100644 --- a/arch/arm/include/asm/arch-mx6/mx6sl_pins.h +++ b/arch/arm/include/asm/arch-mx6/mx6sl_pins.h @@ -58,5 +58,10 @@ enum {
MX6_PAD_KEY_COL4__USB_USBOTG1_PWR = IOMUX_PAD(0x0484, 0x017C, 6, 0x0000, 0, 0), MX6_PAD_KEY_COL5__USB_USBOTG2_PWR = IOMUX_PAD(0x0488, 0x0180, 6, 0x0000, 0, 0), + + MX6_PAD_I2C1_SDA__I2C1_SDA = IOMUX_PAD(0x0450, 0x0160, 0x10, 0x0720, 2, 0), + MX6_PAD_I2C1_SDA__GPIO_3_13 = IOMUX_PAD(0x0450, 0x0160, 5, 0x0000, 0, 0), + MX6_PAD_I2C1_SCL__I2C1_SCL = IOMUX_PAD(0x044C, 0x015C, 0x10, 0x071C, 2, 0), + MX6_PAD_I2C1_SCL__GPIO_3_12 = IOMUX_PAD(0x044C, 0x015C, 5, 0x0000, 0, 0), }; #endif /* __ASM_ARCH_MX6_MX6SL_PINS_H__ */

Implement power_init_board and related I2C interface configuration.
After adding this, uboot can successfully detect and configure pmic.
" U-Boot 2015.01-rc4-00110-g5697113-dirty (Jan 08 2015 - 21:06:44)
CPU: Freescale i.MX6SL rev1.0 at 396 MHz Reset cause: POR Board: MX6SLEVK I2C: ready DRAM: 1 GiB PMIC: PFUZE100 ID=0x10 MMC: FSL_SDHC: 0, FSL_SDHC: 1, FSL_SDHC: 2 "
Signed-off-by: Peng Fan Peng.Fan@freescale.com --- board/freescale/mx6slevk/mx6slevk.c | 47 +++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+)
diff --git a/board/freescale/mx6slevk/mx6slevk.c b/board/freescale/mx6slevk/mx6slevk.c index 838ea6c..f74b237 100644 --- a/board/freescale/mx6slevk/mx6slevk.c +++ b/board/freescale/mx6slevk/mx6slevk.c @@ -13,13 +13,18 @@ #include <asm/arch/sys_proto.h> #include <asm/gpio.h> #include <asm/imx-common/iomux-v3.h> +#include <asm/imx-common/mxc_i2c.h> #include <asm/imx-common/spi.h> #include <asm/io.h> #include <linux/sizes.h> #include <common.h> #include <fsl_esdhc.h> +#include <i2c.h> #include <mmc.h> #include <netdev.h> +#include <power/pmic.h> +#include <power/pfuze100_pmic.h> +#include "../common/pfuze.h" #include <usb.h> #include <usb/ehci-fsl.h>
@@ -40,6 +45,11 @@ DECLARE_GLOBAL_DATA_PTR; #define SPI_PAD_CTRL (PAD_CTL_HYS | PAD_CTL_SPEED_MED | \ PAD_CTL_DSE_40ohm | PAD_CTL_SRE_FAST)
+#define I2C_PAD_CTRL (PAD_CTL_PKE | PAD_CTL_PUE | \ + PAD_CTL_PUS_100K_UP | PAD_CTL_SPEED_MED | \ + PAD_CTL_DSE_40ohm | PAD_CTL_HYS | \ + PAD_CTL_ODE | PAD_CTL_SRE_FAST) + #define ETH_PHY_RESET IMX_GPIO_NR(4, 21)
int dram_init(void) @@ -221,6 +231,39 @@ int board_mmc_init(bd_t *bis) return 0; }
+#ifdef CONFIG_SYS_I2C_MXC +#define PC MUX_PAD_CTRL(I2C_PAD_CTRL) +/* I2C1 for PMIC */ +struct i2c_pads_info i2c_pad_info1 = { + .sda = { + .i2c_mode = MX6_PAD_I2C1_SDA__I2C1_SDA | PC, + .gpio_mode = MX6_PAD_I2C1_SDA__GPIO_3_13 | PC, + .gp = IMX_GPIO_NR(3, 13), + }, + .scl = { + .i2c_mode = MX6_PAD_I2C1_SCL__I2C1_SCL | PC, + .gpio_mode = MX6_PAD_I2C1_SCL__GPIO_3_12 | PC, + .gp = IMX_GPIO_NR(3, 12), + }, +}; + +int power_init_board(void) +{ + struct pmic *p; + unsigned int ret; + + p = pfuze_common_init(I2C_PMIC); + if (!p) + return -ENODEV; + + ret = pfuze_mode_init(p, APS_PFM); + if (ret < 0) + return -EIO; + + return 0; +} +#endif + #ifdef CONFIG_FEC_MXC int board_eth_init(bd_t *bis) { @@ -297,6 +340,10 @@ int board_init(void) /* address of boot parameters */ gd->bd->bi_boot_params = PHYS_SDRAM + 0x100;
+#ifdef CONFIG_SYS_I2C_MXC + setup_i2c(0, CONFIG_SYS_I2C_SPEED, 0x7f, &i2c_pad_info1); +#endif + #ifdef CONFIG_FEC_MXC setup_fec(); #endif

Hi Peng,
On 09/01/2015 09:59, Peng Fan wrote:
Implement power_init_board and related I2C interface configuration.
After adding this, uboot can successfully detect and configure pmic.
" U-Boot 2015.01-rc4-00110-g5697113-dirty (Jan 08 2015 - 21:06:44)
CPU: Freescale i.MX6SL rev1.0 at 396 MHz Reset cause: POR Board: MX6SLEVK I2C: ready DRAM: 1 GiB PMIC: PFUZE100 ID=0x10 MMC: FSL_SDHC: 0, FSL_SDHC: 1, FSL_SDHC: 2 "
Signed-off-by: Peng Fan Peng.Fan@freescale.com
board/freescale/mx6slevk/mx6slevk.c | 47 +++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+)
diff --git a/board/freescale/mx6slevk/mx6slevk.c b/board/freescale/mx6slevk/mx6slevk.c index 838ea6c..f74b237 100644 --- a/board/freescale/mx6slevk/mx6slevk.c +++ b/board/freescale/mx6slevk/mx6slevk.c @@ -13,13 +13,18 @@ #include <asm/arch/sys_proto.h> #include <asm/gpio.h> #include <asm/imx-common/iomux-v3.h> +#include <asm/imx-common/mxc_i2c.h> #include <asm/imx-common/spi.h> #include <asm/io.h> #include <linux/sizes.h> #include <common.h> #include <fsl_esdhc.h> +#include <i2c.h> #include <mmc.h> #include <netdev.h> +#include <power/pmic.h> +#include <power/pfuze100_pmic.h> +#include "../common/pfuze.h" #include <usb.h> #include <usb/ehci-fsl.h>
@@ -40,6 +45,11 @@ DECLARE_GLOBAL_DATA_PTR; #define SPI_PAD_CTRL (PAD_CTL_HYS | PAD_CTL_SPEED_MED | \ PAD_CTL_DSE_40ohm | PAD_CTL_SRE_FAST)
+#define I2C_PAD_CTRL (PAD_CTL_PKE | PAD_CTL_PUE | \
PAD_CTL_PUS_100K_UP | PAD_CTL_SPEED_MED | \
PAD_CTL_DSE_40ohm | PAD_CTL_HYS | \
PAD_CTL_ODE | PAD_CTL_SRE_FAST)
#define ETH_PHY_RESET IMX_GPIO_NR(4, 21)
int dram_init(void) @@ -221,6 +231,39 @@ int board_mmc_init(bd_t *bis) return 0; }
+#ifdef CONFIG_SYS_I2C_MXC +#define PC MUX_PAD_CTRL(I2C_PAD_CTRL) +/* I2C1 for PMIC */ +struct i2c_pads_info i2c_pad_info1 = {
- .sda = {
.i2c_mode = MX6_PAD_I2C1_SDA__I2C1_SDA | PC,
.gpio_mode = MX6_PAD_I2C1_SDA__GPIO_3_13 | PC,
.gp = IMX_GPIO_NR(3, 13),
- },
- .scl = {
.i2c_mode = MX6_PAD_I2C1_SCL__I2C1_SCL | PC,
.gpio_mode = MX6_PAD_I2C1_SCL__GPIO_3_12 | PC,
.gp = IMX_GPIO_NR(3, 12),
- },
+};
+int power_init_board(void) +{
- struct pmic *p;
- unsigned int ret;
- p = pfuze_common_init(I2C_PMIC);
- if (!p)
return -ENODEV;
- ret = pfuze_mode_init(p, APS_PFM);
- if (ret < 0)
return -EIO;
- return 0;
+} +#endif
#ifdef CONFIG_FEC_MXC int board_eth_init(bd_t *bis) { @@ -297,6 +340,10 @@ int board_init(void) /* address of boot parameters */ gd->bd->bi_boot_params = PHYS_SDRAM + 0x100;
+#ifdef CONFIG_SYS_I2C_MXC
- setup_i2c(0, CONFIG_SYS_I2C_SPEED, 0x7f, &i2c_pad_info1);
+#endif
#ifdef CONFIG_FEC_MXC setup_fec(); #endif
Patches are quite orthogonal: patches 1-3 have nothing to do with the subject of the patchset (LDO bypass) and can flawlessly be applied.
Best regards, Stefano Babic

Add more register for structure mxc_ccm_reg.
Signed-off-by: Peng Fan Peng.Fan@freescale.com --- arch/arm/include/asm/arch-mx6/crm_regs.h | 87 ++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+)
diff --git a/arch/arm/include/asm/arch-mx6/crm_regs.h b/arch/arm/include/asm/arch-mx6/crm_regs.h index 39f3c07..55e1287 100644 --- a/arch/arm/include/asm/arch-mx6/crm_regs.h +++ b/arch/arm/include/asm/arch-mx6/crm_regs.h @@ -103,6 +103,93 @@ struct mxc_ccm_reg { u32 analog_pfd_528_set; u32 analog_pfd_528_clr; u32 analog_pfd_528_tog; + u32 reg_1p1; /* 0x4110 */ + u32 reg_1p1_set; /* 0x4114 */ + u32 reg_1p1_clr; /* 0x4118 */ + u32 reg_1p1_tog; /* 0x411c */ + u32 reg_3p0; /* 0x4120 */ + u32 reg_3p0_set; /* 0x4124 */ + u32 reg_3p0_clr; /* 0x4128 */ + u32 reg_3p0_tog; /* 0x412c */ + u32 reg_2p5; /* 0x4130 */ + u32 reg_2p5_set; /* 0x4134 */ + u32 reg_2p5_clr; /* 0x4138 */ + u32 reg_2p5_tog; /* 0x413c */ + u32 reg_core; /* 0x4140 */ + u32 reg_core_set; /* 0x4144 */ + u32 reg_core_clr; /* 0x4148 */ + u32 reg_core_tog; /* 0x414c */ + u32 ana_misc0; /* 0x4150 */ + u32 ana_misc0_set; /* 0x4154 */ + u32 ana_misc0_clr; /* 0x4158 */ + u32 ana_misc0_tog; /* 0x415c */ + u32 ana_misc1; /* 0x4160 */ + u32 ana_misc1_set; /* 0x4164 */ + u32 ana_misc1_clr; /* 0x4168 */ + u32 ana_misc1_tog; /* 0x416c */ + u32 ana_misc2; /* 0x4170 */ + u32 ana_misc2_set; /* 0x4174 */ + u32 ana_misc2_clr; /* 0x4178 */ + u32 ana_misc2_tog; /* 0x417c */ + u32 tempsense0; /* 0x4180 */ + u32 tempsense0_set; /* 0x4184 */ + u32 tempsense0_clr; /* 0x4188 */ + u32 tempsense0_tog; /* 0x418c */ + u32 tempsense1; /* 0x4190 */ + u32 tempsense1_set; /* 0x4194 */ + u32 tempsense1_clr; /* 0x4198 */ + u32 tempsense1_tog; /* 0x419c */ + u32 usb1_vbus_detect; /* 0x41a0 */ + u32 usb1_vbus_detect_set; /* 0x41a4 */ + u32 usb1_vbus_detect_clr; /* 0x41a8 */ + u32 usb1_vbus_detect_tog; /* 0x41ac */ + u32 usb1_chrg_detect; /* 0x41b0 */ + u32 usb1_chrg_detect_set; /* 0x41b4 */ + u32 usb1_chrg_detect_clr; /* 0x41b8 */ + u32 usb1_chrg_detect_tog; /* 0x41bc */ + u32 usb1_vbus_det_stat; /* 0x41c0 */ + u32 usb1_vbus_det_stat_set; /* 0x41c4 */ + u32 usb1_vbus_det_stat_clr; /* 0x41c8 */ + u32 usb1_vbus_det_stat_tog; /* 0x41cc */ + u32 usb1_chrg_det_stat; /* 0x41d0 */ + u32 usb1_chrg_det_stat_set; /* 0x41d4 */ + u32 usb1_chrg_det_stat_clr; /* 0x41d8 */ + u32 usb1_chrg_det_stat_tog; /* 0x41dc */ + u32 usb1_loopback; /* 0x41e0 */ + u32 usb1_loopback_set; /* 0x41e4 */ + u32 usb1_loopback_clr; /* 0x41e8 */ + u32 usb1_loopback_tog; /* 0x41ec */ + u32 usb1_misc; /* 0x41f0 */ + u32 usb1_misc_set; /* 0x41f4 */ + u32 usb1_misc_clr; /* 0x41f8 */ + u32 usb1_misc_tog; /* 0x41fc */ + u32 usb2_vbus_detect; /* 0x4200 */ + u32 usb2_vbus_detect_set; /* 0x4204 */ + u32 usb2_vbus_detect_clr; /* 0x4208 */ + u32 usb2_vbus_detect_tog; /* 0x420c */ + u32 usb2_chrg_detect; /* 0x4210 */ + u32 usb2_chrg_detect_set; /* 0x4214 */ + u32 usb2_chrg_detect_clr; /* 0x4218 */ + u32 usb2_chrg_detect_tog; /* 0x421c */ + u32 usb2_vbus_det_stat; /* 0x4220 */ + u32 usb2_vbus_det_stat_set; /* 0x4224 */ + u32 usb2_vbus_det_stat_clr; /* 0x4228 */ + u32 usb2_vbus_det_stat_tog; /* 0x422c */ + u32 usb2_chrg_det_stat; /* 0x4230 */ + u32 usb2_chrg_det_stat_set; /* 0x4234 */ + u32 usb2_chrg_det_stat_clr; /* 0x4238 */ + u32 usb2_chrg_det_stat_tog; /* 0x423c */ + u32 usb2_loopback; /* 0x4240 */ + u32 usb2_loopback_set; /* 0x4244 */ + u32 usb2_loopback_clr; /* 0x4248 */ + u32 usb2_loopback_tog; /* 0x424c */ + u32 usb2_misc; /* 0x4250 */ + u32 usb2_misc_set; /* 0x4254 */ + u32 usb2_misc_clr; /* 0x4258 */ + u32 usb2_misc_tog; /* 0x425c */ + u32 digprog; /* 0x4260 */ + u32 reserved1[7]; + u32 digprog_sololite; /* 0x4280 */ }; #endif

Hi Peng,
On 09/01/2015 09:59, Peng Fan wrote:
Add more register for structure mxc_ccm_reg.
Signed-off-by: Peng Fan Peng.Fan@freescale.com
arch/arm/include/asm/arch-mx6/crm_regs.h | 87 ++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+)
diff --git a/arch/arm/include/asm/arch-mx6/crm_regs.h b/arch/arm/include/asm/arch-mx6/crm_regs.h index 39f3c07..55e1287 100644 --- a/arch/arm/include/asm/arch-mx6/crm_regs.h +++ b/arch/arm/include/asm/arch-mx6/crm_regs.h @@ -103,6 +103,93 @@ struct mxc_ccm_reg { u32 analog_pfd_528_set; u32 analog_pfd_528_clr; u32 analog_pfd_528_tog;
- u32 reg_1p1; /* 0x4110 */
- u32 reg_1p1_set; /* 0x4114 */
Even if the offset can be sometimes quite useful, the best reference is the manual. You see that other fields have no offset in comments, so please remove them here.
- u32 reg_1p1_clr; /* 0x4118 */
- u32 reg_1p1_tog; /* 0x411c */
- u32 reg_3p0; /* 0x4120 */
- u32 reg_3p0_set; /* 0x4124 */
- u32 reg_3p0_clr; /* 0x4128 */
- u32 reg_3p0_tog; /* 0x412c */
- u32 reg_2p5; /* 0x4130 */
- u32 reg_2p5_set; /* 0x4134 */
- u32 reg_2p5_clr; /* 0x4138 */
- u32 reg_2p5_tog; /* 0x413c */
- u32 reg_core; /* 0x4140 */
- u32 reg_core_set; /* 0x4144 */
- u32 reg_core_clr; /* 0x4148 */
- u32 reg_core_tog; /* 0x414c */
- u32 ana_misc0; /* 0x4150 */
- u32 ana_misc0_set; /* 0x4154 */
- u32 ana_misc0_clr; /* 0x4158 */
- u32 ana_misc0_tog; /* 0x415c */
- u32 ana_misc1; /* 0x4160 */
- u32 ana_misc1_set; /* 0x4164 */
- u32 ana_misc1_clr; /* 0x4168 */
- u32 ana_misc1_tog; /* 0x416c */
- u32 ana_misc2; /* 0x4170 */
- u32 ana_misc2_set; /* 0x4174 */
- u32 ana_misc2_clr; /* 0x4178 */
- u32 ana_misc2_tog; /* 0x417c */
- u32 tempsense0; /* 0x4180 */
- u32 tempsense0_set; /* 0x4184 */
- u32 tempsense0_clr; /* 0x4188 */
- u32 tempsense0_tog; /* 0x418c */
- u32 tempsense1; /* 0x4190 */
- u32 tempsense1_set; /* 0x4194 */
- u32 tempsense1_clr; /* 0x4198 */
- u32 tempsense1_tog; /* 0x419c */
- u32 usb1_vbus_detect; /* 0x41a0 */
- u32 usb1_vbus_detect_set; /* 0x41a4 */
- u32 usb1_vbus_detect_clr; /* 0x41a8 */
- u32 usb1_vbus_detect_tog; /* 0x41ac */
- u32 usb1_chrg_detect; /* 0x41b0 */
- u32 usb1_chrg_detect_set; /* 0x41b4 */
- u32 usb1_chrg_detect_clr; /* 0x41b8 */
- u32 usb1_chrg_detect_tog; /* 0x41bc */
- u32 usb1_vbus_det_stat; /* 0x41c0 */
- u32 usb1_vbus_det_stat_set; /* 0x41c4 */
- u32 usb1_vbus_det_stat_clr; /* 0x41c8 */
- u32 usb1_vbus_det_stat_tog; /* 0x41cc */
- u32 usb1_chrg_det_stat; /* 0x41d0 */
- u32 usb1_chrg_det_stat_set; /* 0x41d4 */
- u32 usb1_chrg_det_stat_clr; /* 0x41d8 */
- u32 usb1_chrg_det_stat_tog; /* 0x41dc */
- u32 usb1_loopback; /* 0x41e0 */
- u32 usb1_loopback_set; /* 0x41e4 */
- u32 usb1_loopback_clr; /* 0x41e8 */
- u32 usb1_loopback_tog; /* 0x41ec */
- u32 usb1_misc; /* 0x41f0 */
- u32 usb1_misc_set; /* 0x41f4 */
- u32 usb1_misc_clr; /* 0x41f8 */
- u32 usb1_misc_tog; /* 0x41fc */
- u32 usb2_vbus_detect; /* 0x4200 */
- u32 usb2_vbus_detect_set; /* 0x4204 */
- u32 usb2_vbus_detect_clr; /* 0x4208 */
- u32 usb2_vbus_detect_tog; /* 0x420c */
- u32 usb2_chrg_detect; /* 0x4210 */
- u32 usb2_chrg_detect_set; /* 0x4214 */
- u32 usb2_chrg_detect_clr; /* 0x4218 */
- u32 usb2_chrg_detect_tog; /* 0x421c */
- u32 usb2_vbus_det_stat; /* 0x4220 */
- u32 usb2_vbus_det_stat_set; /* 0x4224 */
- u32 usb2_vbus_det_stat_clr; /* 0x4228 */
- u32 usb2_vbus_det_stat_tog; /* 0x422c */
- u32 usb2_chrg_det_stat; /* 0x4230 */
- u32 usb2_chrg_det_stat_set; /* 0x4234 */
- u32 usb2_chrg_det_stat_clr; /* 0x4238 */
- u32 usb2_chrg_det_stat_tog; /* 0x423c */
- u32 usb2_loopback; /* 0x4240 */
- u32 usb2_loopback_set; /* 0x4244 */
- u32 usb2_loopback_clr; /* 0x4248 */
- u32 usb2_loopback_tog; /* 0x424c */
- u32 usb2_misc; /* 0x4250 */
- u32 usb2_misc_set; /* 0x4254 */
- u32 usb2_misc_clr; /* 0x4258 */
- u32 usb2_misc_tog; /* 0x425c */
- u32 digprog; /* 0x4260 */
- u32 reserved1[7];
- u32 digprog_sololite; /* 0x4280 */
}; #endif
Best regards, Stefano Babic

Hi, Stefano
On 2/10/2015 7:03 PM, Stefano Babic wrote:
Hi Peng,
On 09/01/2015 09:59, Peng Fan wrote:
Add more register for structure mxc_ccm_reg.
Signed-off-by: Peng Fan Peng.Fan@freescale.com
arch/arm/include/asm/arch-mx6/crm_regs.h | 87 ++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+)
diff --git a/arch/arm/include/asm/arch-mx6/crm_regs.h b/arch/arm/include/asm/arch-mx6/crm_regs.h index 39f3c07..55e1287 100644 --- a/arch/arm/include/asm/arch-mx6/crm_regs.h +++ b/arch/arm/include/asm/arch-mx6/crm_regs.h @@ -103,6 +103,93 @@ struct mxc_ccm_reg { u32 analog_pfd_528_set; u32 analog_pfd_528_clr; u32 analog_pfd_528_tog;
- u32 reg_1p1; /* 0x4110 */
- u32 reg_1p1_set; /* 0x4114 */
Even if the offset can be sometimes quite useful, the best reference is the manual. You see that other fields have no offset in comments, so please remove them here.
Ok. I'll remove the offset here.
- u32 reg_1p1_clr; /* 0x4118 */
- u32 reg_1p1_tog; /* 0x411c */
- u32 reg_3p0; /* 0x4120 */
- u32 reg_3p0_set; /* 0x4124 */
- u32 reg_3p0_clr; /* 0x4128 */
- u32 reg_3p0_tog; /* 0x412c */
- u32 reg_2p5; /* 0x4130 */
- u32 reg_2p5_set; /* 0x4134 */
- u32 reg_2p5_clr; /* 0x4138 */
- u32 reg_2p5_tog; /* 0x413c */
- u32 reg_core; /* 0x4140 */
- u32 reg_core_set; /* 0x4144 */
- u32 reg_core_clr; /* 0x4148 */
- u32 reg_core_tog; /* 0x414c */
- u32 ana_misc0; /* 0x4150 */
- u32 ana_misc0_set; /* 0x4154 */
- u32 ana_misc0_clr; /* 0x4158 */
- u32 ana_misc0_tog; /* 0x415c */
- u32 ana_misc1; /* 0x4160 */
- u32 ana_misc1_set; /* 0x4164 */
- u32 ana_misc1_clr; /* 0x4168 */
- u32 ana_misc1_tog; /* 0x416c */
- u32 ana_misc2; /* 0x4170 */
- u32 ana_misc2_set; /* 0x4174 */
- u32 ana_misc2_clr; /* 0x4178 */
- u32 ana_misc2_tog; /* 0x417c */
- u32 tempsense0; /* 0x4180 */
- u32 tempsense0_set; /* 0x4184 */
- u32 tempsense0_clr; /* 0x4188 */
- u32 tempsense0_tog; /* 0x418c */
- u32 tempsense1; /* 0x4190 */
- u32 tempsense1_set; /* 0x4194 */
- u32 tempsense1_clr; /* 0x4198 */
- u32 tempsense1_tog; /* 0x419c */
- u32 usb1_vbus_detect; /* 0x41a0 */
- u32 usb1_vbus_detect_set; /* 0x41a4 */
- u32 usb1_vbus_detect_clr; /* 0x41a8 */
- u32 usb1_vbus_detect_tog; /* 0x41ac */
- u32 usb1_chrg_detect; /* 0x41b0 */
- u32 usb1_chrg_detect_set; /* 0x41b4 */
- u32 usb1_chrg_detect_clr; /* 0x41b8 */
- u32 usb1_chrg_detect_tog; /* 0x41bc */
- u32 usb1_vbus_det_stat; /* 0x41c0 */
- u32 usb1_vbus_det_stat_set; /* 0x41c4 */
- u32 usb1_vbus_det_stat_clr; /* 0x41c8 */
- u32 usb1_vbus_det_stat_tog; /* 0x41cc */
- u32 usb1_chrg_det_stat; /* 0x41d0 */
- u32 usb1_chrg_det_stat_set; /* 0x41d4 */
- u32 usb1_chrg_det_stat_clr; /* 0x41d8 */
- u32 usb1_chrg_det_stat_tog; /* 0x41dc */
- u32 usb1_loopback; /* 0x41e0 */
- u32 usb1_loopback_set; /* 0x41e4 */
- u32 usb1_loopback_clr; /* 0x41e8 */
- u32 usb1_loopback_tog; /* 0x41ec */
- u32 usb1_misc; /* 0x41f0 */
- u32 usb1_misc_set; /* 0x41f4 */
- u32 usb1_misc_clr; /* 0x41f8 */
- u32 usb1_misc_tog; /* 0x41fc */
- u32 usb2_vbus_detect; /* 0x4200 */
- u32 usb2_vbus_detect_set; /* 0x4204 */
- u32 usb2_vbus_detect_clr; /* 0x4208 */
- u32 usb2_vbus_detect_tog; /* 0x420c */
- u32 usb2_chrg_detect; /* 0x4210 */
- u32 usb2_chrg_detect_set; /* 0x4214 */
- u32 usb2_chrg_detect_clr; /* 0x4218 */
- u32 usb2_chrg_detect_tog; /* 0x421c */
- u32 usb2_vbus_det_stat; /* 0x4220 */
- u32 usb2_vbus_det_stat_set; /* 0x4224 */
- u32 usb2_vbus_det_stat_clr; /* 0x4228 */
- u32 usb2_vbus_det_stat_tog; /* 0x422c */
- u32 usb2_chrg_det_stat; /* 0x4230 */
- u32 usb2_chrg_det_stat_set; /* 0x4234 */
- u32 usb2_chrg_det_stat_clr; /* 0x4238 */
- u32 usb2_chrg_det_stat_tog; /* 0x423c */
- u32 usb2_loopback; /* 0x4240 */
- u32 usb2_loopback_set; /* 0x4244 */
- u32 usb2_loopback_clr; /* 0x4248 */
- u32 usb2_loopback_tog; /* 0x424c */
- u32 usb2_misc; /* 0x4250 */
- u32 usb2_misc_set; /* 0x4254 */
- u32 usb2_misc_clr; /* 0x4258 */
- u32 usb2_misc_tog; /* 0x425c */
- u32 digprog; /* 0x4260 */
- u32 reserved1[7];
- u32 digprog_sololite; /* 0x4280 */ }; #endif
Best regards, Stefano Babic
Thanks, Peng.

Update fuse_bank0_regs structure according reference mannual.
Signed-off-by: Peng Fan Peng.Fan@freescale.com --- arch/arm/include/asm/arch-mx6/imx-regs.h | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/arch/arm/include/asm/arch-mx6/imx-regs.h b/arch/arm/include/asm/arch-mx6/imx-regs.h index c968600..22f371d 100644 --- a/arch/arm/include/asm/arch-mx6/imx-regs.h +++ b/arch/arm/include/asm/arch-mx6/imx-regs.h @@ -624,12 +624,16 @@ struct fuse_bank0_regs { u32 rsvd1[3]; u32 uid_high; u32 rsvd2[3]; - u32 rsvd3[4]; - u32 rsvd4[4]; - u32 rsvd5[4]; + u32 cfg2; + u32 rsvd3[3]; + u32 cfg3; + u32 rsvd4[3]; + u32 cfg4; + u32 rsvd5[3]; u32 cfg5; u32 rsvd6[3]; - u32 rsvd7[4]; + u32 cfg6; + u32 rsvd7[3]; };
#ifdef CONFIG_MX6SX

On 09/01/2015 09:59, Peng Fan wrote:
Update fuse_bank0_regs structure according reference mannual.
Signed-off-by: Peng Fan Peng.Fan@freescale.com
arch/arm/include/asm/arch-mx6/imx-regs.h | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/arch/arm/include/asm/arch-mx6/imx-regs.h b/arch/arm/include/asm/arch-mx6/imx-regs.h index c968600..22f371d 100644 --- a/arch/arm/include/asm/arch-mx6/imx-regs.h +++ b/arch/arm/include/asm/arch-mx6/imx-regs.h @@ -624,12 +624,16 @@ struct fuse_bank0_regs { u32 rsvd1[3]; u32 uid_high; u32 rsvd2[3];
- u32 rsvd3[4];
- u32 rsvd4[4];
- u32 rsvd5[4];
- u32 cfg2;
- u32 rsvd3[3];
- u32 cfg3;
- u32 rsvd4[3];
- u32 cfg4;
- u32 rsvd5[3]; u32 cfg5; u32 rsvd6[3];
- u32 rsvd7[4];
- u32 cfg6;
- u32 rsvd7[3];
};
#ifdef CONFIG_MX6SX
Applied to u-boot-imx, thanks !
Best regards, Stefano Babic

"#define PFUZE100_SW1ABC_SETP(x) ((x - 3000) / 250)" This macro is for configuring SW1A/B/C Output Voltage easily.
Signed-off-by: Peng Fan Peng.Fan@freescale.com --- include/power/pfuze100_pmic.h | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/include/power/pfuze100_pmic.h b/include/power/pfuze100_pmic.h index 7474afb..d304658 100644 --- a/include/power/pfuze100_pmic.h +++ b/include/power/pfuze100_pmic.h @@ -61,6 +61,8 @@ enum { * Buck Regulators */
+#define PFUZE100_SW1ABC_SETP(x) ((x - 3000) / 250) + /* SW1A/B/C Output Voltage Configuration */ #define SW1x_0_300V 0 #define SW1x_0_325V 1

On 09/01/2015 09:59, Peng Fan wrote:
"#define PFUZE100_SW1ABC_SETP(x) ((x - 3000) / 250)" This macro is for configuring SW1A/B/C Output Voltage easily.
Signed-off-by: Peng Fan Peng.Fan@freescale.com
include/power/pfuze100_pmic.h | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/include/power/pfuze100_pmic.h b/include/power/pfuze100_pmic.h index 7474afb..d304658 100644 --- a/include/power/pfuze100_pmic.h +++ b/include/power/pfuze100_pmic.h @@ -61,6 +61,8 @@ enum {
- Buck Regulators
*/
+#define PFUZE100_SW1ABC_SETP(x) ((x - 3000) / 250)
/* SW1A/B/C Output Voltage Configuration */ #define SW1x_0_300V 0 #define SW1x_0_325V 1
To inform you: patches 1-3 must be rebased and reworked, mainly due to pmic_mode_init() (you have postpone V2 after discussion about ldo-bypass). I start applying the 5-6, that contain only new defines.
Applied to u-boot-imx, thanks !
Best regards, Stefano Babic

Hi, Stefano
On 2/10/2015 7:54 PM, Stefano Babic wrote:
On 09/01/2015 09:59, Peng Fan wrote:
"#define PFUZE100_SW1ABC_SETP(x) ((x - 3000) / 250)" This macro is for configuring SW1A/B/C Output Voltage easily.
Signed-off-by: Peng Fan Peng.Fan@freescale.com
include/power/pfuze100_pmic.h | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/include/power/pfuze100_pmic.h b/include/power/pfuze100_pmic.h index 7474afb..d304658 100644 --- a/include/power/pfuze100_pmic.h +++ b/include/power/pfuze100_pmic.h @@ -61,6 +61,8 @@ enum {
- Buck Regulators
*/
+#define PFUZE100_SW1ABC_SETP(x) ((x - 3000) / 250)
- /* SW1A/B/C Output Voltage Configuration */ #define SW1x_0_300V 0 #define SW1x_0_325V 1
To inform you: patches 1-3 must be rebased and reworked, mainly due to pmic_mode_init() (you have postpone V2 after discussion about ldo-bypass). I start applying the 5-6, that contain only new defines.
I'll rebase patches 1-3 and make the three patches a single v2 patch set.
Applied to u-boot-imx, thanks !
Best regards, Stefano Babic
Thanks, Peng.

The basic graph for voltage input is: VDDARM_IN ---> LDO_DIG(ARM) ---> VDD_ARM_CAP VDDSOC_IN ---> LDO_DIG(SOC) ---> VDD_SOC_CAP
We can bypass the LDO to save power, if the board already has pmic.
set_anatop_bypass is the function to do the bypass VDDARM and VDDSOC work.
Current only set VDDARM_IN@1.175V/VDDSOC_IN@1.175V before ldo bypass switch. So until ldo bypass switch happened, these voltage setting is set in ldo-enable mode. But in datasheet, we need 1.15V + 125mV = 1.275V for VDDARM_IN. We need to downgrade cpufreq to 400Mhz and restore after ldo bypass mode switch. So add prep_anatop_bypass/finish_anatop_bypass/set_arm_freq_400M to do this work.
LDO bypass is dependent on the flatten device tree file. If speed grading fuse is for 1.2GHz, enable LDO bypass and setup PMIC voltages. So add check for 1.2GHz core speed. So add check_1_2G function.
In ldo-bypass mode, we need trigger WDOG_B pin to reset pmic in ldo-bypass mode. So add set_wdog_reset to do this work.
Also add related function prototype in sys_proto.h
Signed-off-by: Peng Fan Peng.Fan@freescale.com Signed-off-by: Robin Gong b38343@freescale.com Signed-off-by: Nitin Garg nitin.garg@freescale.com --- arch/arm/cpu/armv7/mx6/soc.c | 141 ++++++++++++++++++++++++++++++ arch/arm/include/asm/arch-mx6/sys_proto.h | 9 ++ 2 files changed, 150 insertions(+)
diff --git a/arch/arm/cpu/armv7/mx6/soc.c b/arch/arm/cpu/armv7/mx6/soc.c index 5f5f497..5d02755 100644 --- a/arch/arm/cpu/armv7/mx6/soc.c +++ b/arch/arm/cpu/armv7/mx6/soc.c @@ -18,6 +18,7 @@ #include <asm/arch/sys_proto.h> #include <asm/imx-common/boot_mode.h> #include <asm/imx-common/dma.h> +#include <libfdt.h> #include <stdbool.h> #include <asm/arch/mxc_hdmi.h> #include <asm/arch/crm_regs.h> @@ -429,6 +430,146 @@ void s_init(void) writel(mask528, &anatop->pfd_528_clr); }
+#ifdef CONFIG_LDO_BYPASS_CHECK +DECLARE_GLOBAL_DATA_PTR; +static int ldo_bypass; + +int check_ldo_bypass(void) +{ + const int *ldo_mode; + int node; + + /* get the right fdt_blob from the global working_fdt */ + gd->fdt_blob = working_fdt; + /* Get the node from FDT for anatop ldo-bypass */ + node = fdt_node_offset_by_compatible(gd->fdt_blob, -1, + "fsl,imx6q-gpc"); + if (node < 0) { + printf("No gpc device node %d, force to ldo-enable.\n", node); + return 0; + } + ldo_mode = fdt_getprop(gd->fdt_blob, node, "fsl,ldo-bypass", NULL); + /* + * return 1 if "fsl,ldo-bypass = <1>", else return 0 if + * "fsl,ldo-bypass = <0>" or no "fsl,ldo-bypass" property + */ + ldo_bypass = fdt32_to_cpu(*ldo_mode) == 1 ? 1 : 0; + + return ldo_bypass; +} + +int check_1_2G(void) +{ + u32 reg; + int result = 0; + struct ocotp_regs *ocotp = (struct ocotp_regs *)OCOTP_BASE_ADDR; + struct fuse_bank *bank = &ocotp->bank[0]; + struct fuse_bank0_regs *fuse_bank0 = + (struct fuse_bank0_regs *)bank->fuse_regs; + + reg = readl(&fuse_bank0->cfg3); + if (((reg >> 16) & 0x3) == 0x3) { + if (ldo_bypass) { + printf("Wrong dtb file used! i.MX6Q@1.2Ghz only works with ldo-enable mode!\n"); + /* + * Currently, only imx6q-sabresd board might be here, + * since only i.MX6Q support 1.2G and only Sabresd board + * support ldo-bypass mode. So hardcode here. + * You can also modify your board(i.MX6Q) dtb name if it + * supports both ldo-bypass and ldo-enable mode. + */ + printf("Please use imx6q-sabresd-ldo.dtb!\n"); + hang(); + } + result = 1; + } + + return result; +} + +static int arm_orig_podf; +void set_arm_freq_400M(bool is_400M) +{ + struct mxc_ccm_reg *mxc_ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR; + + if (is_400M) + writel(0x1, &mxc_ccm->cacrr); + else + writel(arm_orig_podf, &mxc_ccm->cacrr); +} + +void prep_anatop_bypass(void) +{ + struct mxc_ccm_reg *mxc_ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR; + + arm_orig_podf = readl(&mxc_ccm->cacrr); + /* + * Downgrade ARM speed to 400Mhz as half of boot 800Mhz before ldo + * bypassed, also downgrade internal vddarm ldo to 0.975V. + * VDDARM_IN 0.975V + 125mV = 1.1V < Max(1.3V) + * otherwise at 800Mhz(i.mx6dl): + * VDDARM_IN 1.175V + 125mV = 1.3V = Max(1.3V) + * We need provide enough gap in this case. + * skip if boot from 400M. + */ + if (!arm_orig_podf) + set_arm_freq_400M(true); +#if !defined(CONFIG_MX6DL) && !defined(CONFIG_MX6SX) + set_ldo_voltage(LDO_ARM, 975); +#else + set_ldo_voltage(LDO_ARM, 1150); +#endif +} + +void set_wdog_reset(struct wdog_regs *wdog) +{ + u32 reg = readw(&wdog->wcr); + /* + * use WDOG_B mode to reset external pmic because it's risky for the + * following watchdog reboot in case of cpu freq at lowest 400Mhz with + * ldo-bypass mode. Because boot frequency maybe higher 800Mhz i.e. So + * in ldo-bypass mode watchdog reset will only triger POR reset, not + * WDOG reset. But below code depends on hardware design, if HW didn't + * connect WDOG_B pin to external pmic such as i.mx6slevk, we can skip + * these code since it assumed boot from 400Mhz always. + */ + reg = readw(&wdog->wcr); + reg |= 1 << 3; + /* + * WDZST bit is write-once only bit. Align this bit in kernel, + * otherwise kernel code will have no chance to set this bit. + */ + reg |= 1 << 0; + writew(reg, &wdog->wcr); +} + +int set_anatop_bypass(int wdog_reset_pin) +{ + struct mxc_ccm_reg *ccm_regs = (struct mxc_ccm_reg *)CCM_BASE_ADDR; + struct wdog_regs *wdog; + u32 reg = readl(&ccm_regs->reg_core); + + /* bypass VDDARM/VDDSOC */ + reg = reg | (0x1F << 18) | 0x1F; + writel(reg, &ccm_regs->reg_core); + + if (wdog_reset_pin == 2) + wdog = (struct wdog_regs *)WDOG2_BASE_ADDR; + else if (wdog_reset_pin == 1) + wdog = (struct wdog_regs *)WDOG1_BASE_ADDR; + else + return arm_orig_podf; + set_wdog_reset(wdog); + return arm_orig_podf; +} + +void finish_anatop_bypass(void) +{ + if (!arm_orig_podf) + set_arm_freq_400M(false); +} +#endif + #ifdef CONFIG_IMX_HDMI void imx_enable_hdmi_phy(void) { diff --git a/arch/arm/include/asm/arch-mx6/sys_proto.h b/arch/arm/include/asm/arch-mx6/sys_proto.h index 28ba844..e6f2112 100644 --- a/arch/arm/include/asm/arch-mx6/sys_proto.h +++ b/arch/arm/include/asm/arch-mx6/sys_proto.h @@ -28,6 +28,15 @@ const char *get_imx_type(u32 imxtype); unsigned imx_ddr_size(void); void set_chipselect_size(int const);
+void set_wdog_reset(struct wdog_regs *wdog); +#ifdef CONFIG_LDO_BYPASS_CHECK +int check_ldo_bypass(void); +int check_1_2G(void); +void ldo_mode_set(int ldo_bypass); +int set_anatop_bypass(int wdog_reset_pin); +void prep_anatop_bypass(void); +void finish_anatop_bypass(void); +#endif /* * Initializes on-chip ethernet controllers. * to override, implement board_eth_init()

Hi Peng,
On 09/01/2015 09:59, Peng Fan wrote:
The basic graph for voltage input is: VDDARM_IN ---> LDO_DIG(ARM) ---> VDD_ARM_CAP VDDSOC_IN ---> LDO_DIG(SOC) ---> VDD_SOC_CAP
We can bypass the LDO to save power, if the board already has pmic.
set_anatop_bypass is the function to do the bypass VDDARM and VDDSOC work.
Current only set VDDARM_IN@1.175V/VDDSOC_IN@1.175V before ldo bypass switch. So until ldo bypass switch happened, these voltage setting is set in ldo-enable mode. But in datasheet, we need 1.15V + 125mV = 1.275V for VDDARM_IN. We need to downgrade cpufreq to 400Mhz and restore after ldo bypass mode switch. So add prep_anatop_bypass/finish_anatop_bypass/set_arm_freq_400M to do this work.
LDO bypass is dependent on the flatten device tree file. If speed grading fuse is for 1.2GHz, enable LDO bypass and setup PMIC voltages. So add check for 1.2GHz core speed. So add check_1_2G function.
In ldo-bypass mode, we need trigger WDOG_B pin to reset pmic in ldo-bypass mode. So add set_wdog_reset to do this work.
Also add related function prototype in sys_proto.h
Ok - with this explanation, I would try to understand how the changes can be split. If the feature/change works for several boards, it makes sense to have it common and general. If it is only for one board, must flow into the board directory.
It looks like that ldo-bypass is strictly dependent on the board. Firstly, it must have PMIC, and not all boards have it. Your last sentence:
In ldo-bypass mode, we need trigger WDOG_B pin to reset pmic in ldo-bypass mode. So add set_wdog_reset to do this work.
This looks to me as an item very bound to the board. Could it be possible to use another pin (I do not know the schematics, I remember that such as reset pin was fix on previous i.MX) ? If answer is yes, can these changes be used by other board or are they only for sabresd ?
Signed-off-by: Peng Fan Peng.Fan@freescale.com Signed-off-by: Robin Gong b38343@freescale.com Signed-off-by: Nitin Garg nitin.garg@freescale.com
arch/arm/cpu/armv7/mx6/soc.c | 141 ++++++++++++++++++++++++++++++ arch/arm/include/asm/arch-mx6/sys_proto.h | 9 ++ 2 files changed, 150 insertions(+)
diff --git a/arch/arm/cpu/armv7/mx6/soc.c b/arch/arm/cpu/armv7/mx6/soc.c index 5f5f497..5d02755 100644 --- a/arch/arm/cpu/armv7/mx6/soc.c +++ b/arch/arm/cpu/armv7/mx6/soc.c @@ -18,6 +18,7 @@ #include <asm/arch/sys_proto.h> #include <asm/imx-common/boot_mode.h> #include <asm/imx-common/dma.h> +#include <libfdt.h> #include <stdbool.h> #include <asm/arch/mxc_hdmi.h> #include <asm/arch/crm_regs.h> @@ -429,6 +430,146 @@ void s_init(void) writel(mask528, &anatop->pfd_528_clr); }
+#ifdef CONFIG_LDO_BYPASS_CHECK +DECLARE_GLOBAL_DATA_PTR; +static int ldo_bypass;
mmmhh....global to the module ?
+int check_ldo_bypass(void) +{
- const int *ldo_mode;
- int node;
- /* get the right fdt_blob from the global working_fdt */
- gd->fdt_blob = working_fdt;
- /* Get the node from FDT for anatop ldo-bypass */
- node = fdt_node_offset_by_compatible(gd->fdt_blob, -1,
"fsl,imx6q-gpc");
- if (node < 0) {
printf("No gpc device node %d, force to ldo-enable.\n", node);
return 0;
- }
- ldo_mode = fdt_getprop(gd->fdt_blob, node, "fsl,ldo-bypass", NULL);
I am quite lost. I have searched in kernel (current TOT), and I have not found such property. Can you help me to understand ?
- /*
* return 1 if "fsl,ldo-bypass = <1>", else return 0 if
* "fsl,ldo-bypass = <0>" or no "fsl,ldo-bypass" property
*/
- ldo_bypass = fdt32_to_cpu(*ldo_mode) == 1 ? 1 : 0;
- return ldo_bypass;
+}
+int check_1_2G(void) +{
- u32 reg;
- int result = 0;
- struct ocotp_regs *ocotp = (struct ocotp_regs *)OCOTP_BASE_ADDR;
- struct fuse_bank *bank = &ocotp->bank[0];
- struct fuse_bank0_regs *fuse_bank0 =
(struct fuse_bank0_regs *)bank->fuse_regs;
- reg = readl(&fuse_bank0->cfg3);
- if (((reg >> 16) & 0x3) == 0x3) {
if (ldo_bypass) {
printf("Wrong dtb file used! i.MX6Q@1.2Ghz only works with ldo-enable mode!\n");
/*
* Currently, only imx6q-sabresd board might be here,
* since only i.MX6Q support 1.2G and only Sabresd board
* support ldo-bypass mode. So hardcode here.
* You can also modify your board(i.MX6Q) dtb name if it
* supports both ldo-bypass and ldo-enable mode.
This enforce my doubts.
*/
printf("Please use imx6q-sabresd-ldo.dtb!\n");
In any case, do not use hard-coded filenames into u-boot. They can change.
hang();
}
result = 1;
- }
- return result;
+}
+static int arm_orig_podf; +void set_arm_freq_400M(bool is_400M) +{
- struct mxc_ccm_reg *mxc_ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR;
- if (is_400M)
writel(0x1, &mxc_ccm->cacrr);
- else
writel(arm_orig_podf, &mxc_ccm->cacrr);
+}
+void prep_anatop_bypass(void) +{
- struct mxc_ccm_reg *mxc_ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR;
- arm_orig_podf = readl(&mxc_ccm->cacrr);
- /*
* Downgrade ARM speed to 400Mhz as half of boot 800Mhz before ldo
* bypassed, also downgrade internal vddarm ldo to 0.975V.
* VDDARM_IN 0.975V + 125mV = 1.1V < Max(1.3V)
* otherwise at 800Mhz(i.mx6dl):
* VDDARM_IN 1.175V + 125mV = 1.3V = Max(1.3V)
* We need provide enough gap in this case.
* skip if boot from 400M.
*/
- if (!arm_orig_podf)
set_arm_freq_400M(true);
+#if !defined(CONFIG_MX6DL) && !defined(CONFIG_MX6SX)
- set_ldo_voltage(LDO_ARM, 975);
+#else
- set_ldo_voltage(LDO_ARM, 1150);
+#endif +}
+void set_wdog_reset(struct wdog_regs *wdog) +{
- u32 reg = readw(&wdog->wcr);
- /*
* use WDOG_B mode to reset external pmic because it's risky for the
* following watchdog reboot in case of cpu freq at lowest 400Mhz with
* ldo-bypass mode. Because boot frequency maybe higher 800Mhz i.e. So
* in ldo-bypass mode watchdog reset will only triger POR reset, not
* WDOG reset. But below code depends on hardware design, if HW didn't
* connect WDOG_B pin to external pmic such as i.mx6slevk, we can skip
* these code since it assumed boot from 400Mhz always.
*/
- reg = readw(&wdog->wcr);
- reg |= 1 << 3;
- /*
* WDZST bit is write-once only bit. Align this bit in kernel,
* otherwise kernel code will have no chance to set this bit.
*/
- reg |= 1 << 0;
- writew(reg, &wdog->wcr);
+}
+int set_anatop_bypass(int wdog_reset_pin) +{
- struct mxc_ccm_reg *ccm_regs = (struct mxc_ccm_reg *)CCM_BASE_ADDR;
- struct wdog_regs *wdog;
- u32 reg = readl(&ccm_regs->reg_core);
- /* bypass VDDARM/VDDSOC */
- reg = reg | (0x1F << 18) | 0x1F;
- writel(reg, &ccm_regs->reg_core);
- if (wdog_reset_pin == 2)
wdog = (struct wdog_regs *)WDOG2_BASE_ADDR;
- else if (wdog_reset_pin == 1)
wdog = (struct wdog_regs *)WDOG1_BASE_ADDR;
- else
return arm_orig_podf;
- set_wdog_reset(wdog);
- return arm_orig_podf;
+}
+void finish_anatop_bypass(void) +{
- if (!arm_orig_podf)
set_arm_freq_400M(false);
+} +#endif
#ifdef CONFIG_IMX_HDMI void imx_enable_hdmi_phy(void) { diff --git a/arch/arm/include/asm/arch-mx6/sys_proto.h b/arch/arm/include/asm/arch-mx6/sys_proto.h index 28ba844..e6f2112 100644 --- a/arch/arm/include/asm/arch-mx6/sys_proto.h +++ b/arch/arm/include/asm/arch-mx6/sys_proto.h @@ -28,6 +28,15 @@ const char *get_imx_type(u32 imxtype); unsigned imx_ddr_size(void); void set_chipselect_size(int const);
+void set_wdog_reset(struct wdog_regs *wdog); +#ifdef CONFIG_LDO_BYPASS_CHECK
Why do we need #ifdef ?
+int check_ldo_bypass(void); +int check_1_2G(void); +void ldo_mode_set(int ldo_bypass); +int set_anatop_bypass(int wdog_reset_pin); +void prep_anatop_bypass(void); +void finish_anatop_bypass(void); +#endif /*
- Initializes on-chip ethernet controllers.
- to override, implement board_eth_init()
Best regards, Stefano Babic

On Tue, Feb 10, 2015 at 3:23 AM, Stefano Babic sbabic@denx.de wrote:
Ok - with this explanation, I would try to understand how the changes can be split. If the feature/change works for several boards, it makes sense to have it common and general. If it is only for one board, must flow into the board directory.
It should be common as there are several boards which use PMIC's and can use it.
It looks like that ldo-bypass is strictly dependent on the board. Firstly, it must have PMIC, and not all boards have it. Your last sentence:
Any board that has a PMIC capable of regulating VDD_ARM_IN and VDD_SOC_IN to the setpoints from the IMX6 datasheet can operate in LDO bypass mode, unless operating at 1.2GHz in which case the datasheet states that the LDO must be used (not bypassed) to avoid ripple sensitivity issues.
In ldo-bypass mode, we need trigger WDOG_B pin to reset pmic in ldo-bypass mode. So add set_wdog_reset to do this work.
This looks to me as an item very bound to the board. Could it be possible to use another pin (I do not know the schematics, I remember that such as reset pin was fix on previous i.MX) ? If answer is yes, can these changes be used by other board or are they only for sabresd ?
agreed - this is a board-specific pinmux
Signed-off-by: Peng Fan Peng.Fan@freescale.com Signed-off-by: Robin Gong b38343@freescale.com Signed-off-by: Nitin Garg nitin.garg@freescale.com
arch/arm/cpu/armv7/mx6/soc.c | 141 ++++++++++++++++++++++++++++++ arch/arm/include/asm/arch-mx6/sys_proto.h | 9 ++ 2 files changed, 150 insertions(+)
diff --git a/arch/arm/cpu/armv7/mx6/soc.c b/arch/arm/cpu/armv7/mx6/soc.c index 5f5f497..5d02755 100644 --- a/arch/arm/cpu/armv7/mx6/soc.c +++ b/arch/arm/cpu/armv7/mx6/soc.c @@ -18,6 +18,7 @@ #include <asm/arch/sys_proto.h> #include <asm/imx-common/boot_mode.h> #include <asm/imx-common/dma.h> +#include <libfdt.h> #include <stdbool.h> #include <asm/arch/mxc_hdmi.h> #include <asm/arch/crm_regs.h> @@ -429,6 +430,146 @@ void s_init(void) writel(mask528, &anatop->pfd_528_clr); }
+#ifdef CONFIG_LDO_BYPASS_CHECK +DECLARE_GLOBAL_DATA_PTR; +static int ldo_bypass;
mmmhh....global to the module ?
+int check_ldo_bypass(void) +{
const int *ldo_mode;
int node;
/* get the right fdt_blob from the global working_fdt */
gd->fdt_blob = working_fdt;
/* Get the node from FDT for anatop ldo-bypass */
node = fdt_node_offset_by_compatible(gd->fdt_blob, -1,
"fsl,imx6q-gpc");
if (node < 0) {
printf("No gpc device node %d, force to ldo-enable.\n", node);
return 0;
}
ldo_mode = fdt_getprop(gd->fdt_blob, node, "fsl,ldo-bypass", NULL);
I am quite lost. I have searched in kernel (current TOT), and I have not found such property. Can you help me to understand ?
Right - you won't find it because its a Freescale vendor kernel implementation only. A hack if you ask me to avoid having to doing ldo-byapss the right way.
Here are the threads that I know of regarding ldo-bypass in the kernel, where it needs to be:
https://lkml.org/lkml/2014/12/18/255 https://lkml.org/lkml/2014/10/31/3
Peng,
I think what you are trying to do here is to put the anatop regulators in bypass mode so that the Freescale vendor kernel leaves them bypassed (which is what the 3.10.x based vendor kernels supporting device-tree at http://git.freescale.com/git/cgit.cgi/imx/linux-2.6-imx.git do). This is what the Freescale vendor U-Boot does and so they have created a horrible dependence between kernel and bootloader.
Instead you may be interested in what I did for our BSP's that use the Freescale vendor kernel. Instead of touching U-Boot, I look for the fsl,ldo-bypass node in the kernel and enable it just like their bootloader would have: https://github.com/Gateworks/linux-imx6/commit/a1af6ac6f00b4da7c8a5656e8ff09...
That said, I would love to see some help getting IMX6 ldo-bypass support upstream. All of our boards have an external PMIC and are capable of bypass mode. Bypassing the LDO on such boards really helps reduce overall board power consumption as well as move heat from the CPU to the PMIC.
Tim

Hi Tim,
On Tue, Feb 10, 2015 at 12:50 PM, Tim Harvey tharvey@gateworks.com wrote:
I think what you are trying to do here is to put the anatop regulators in bypass mode so that the Freescale vendor kernel leaves them bypassed (which is what the 3.10.x based vendor kernels supporting device-tree at http://git.freescale.com/git/cgit.cgi/imx/linux-2.6-imx.git do). This is what the Freescale vendor U-Boot does and so they have created a horrible dependence between kernel and bootloader.
I agree.
Instead you may be interested in what I did for our BSP's that use the Freescale vendor kernel. Instead of touching U-Boot, I look for the fsl,ldo-bypass node in the kernel and enable it just like their bootloader would have: https://github.com/Gateworks/linux-imx6/commit/a1af6ac6f00b4da7c8a5656e8ff09...
That said, I would love to see some help getting IMX6 ldo-bypass support upstream. All of our boards have an external PMIC and are
I want to help you on upstreaming ldo-bypass support in the kernel, Tim.
Can we do like your approach, but defining imx_anatop_ldobypass_enable() inside rivers/regulator/anatop-regulator.c instead?
Regards,
Fabio Estevam

On Tue, Feb 10, 2015 at 6:59 AM, Fabio Estevam festevam@gmail.com wrote:
Hi Tim,
On Tue, Feb 10, 2015 at 12:50 PM, Tim Harvey tharvey@gateworks.com wrote:
I think what you are trying to do here is to put the anatop regulators in bypass mode so that the Freescale vendor kernel leaves them bypassed (which is what the 3.10.x based vendor kernels supporting device-tree at http://git.freescale.com/git/cgit.cgi/imx/linux-2.6-imx.git do). This is what the Freescale vendor U-Boot does and so they have created a horrible dependence between kernel and bootloader.
I agree.
Instead you may be interested in what I did for our BSP's that use the Freescale vendor kernel. Instead of touching U-Boot, I look for the fsl,ldo-bypass node in the kernel and enable it just like their bootloader would have: https://github.com/Gateworks/linux-imx6/commit/a1af6ac6f00b4da7c8a5656e8ff09...
That said, I would love to see some help getting IMX6 ldo-bypass support upstream. All of our boards have an external PMIC and are
I want to help you on upstreaming ldo-bypass support in the kernel, Tim.
Great!
Can we do like your approach, but defining imx_anatop_ldobypass_enable() inside rivers/regulator/anatop-regulator.c instead?
Yes, I think that makes sense. I hope to be able to get back to this in a couple of weeks after a round of U-Boot updates that are next on my list.
Thanks,
Tim

Hi Tim,
On 10/02/2015 15:50, Tim Harvey wrote:
On Tue, Feb 10, 2015 at 3:23 AM, Stefano Babic sbabic@denx.de wrote:
Ok - with this explanation, I would try to understand how the changes can be split. If the feature/change works for several boards, it makes sense to have it common and general. If it is only for one board, must flow into the board directory.
It should be common as there are several boards which use PMIC's and can use it.
Fully agree.
I am quite lost. I have searched in kernel (current TOT), and I have not found such property. Can you help me to understand ?
Right - you won't find it because its a Freescale vendor kernel implementation only. A hack if you ask me to avoid having to doing ldo-byapss the right way.
Exactly, this cannot flow into mainline.
Here are the threads that I know of regarding ldo-bypass in the kernel, where it needs to be:
https://lkml.org/lkml/2014/12/18/255 https://lkml.org/lkml/2014/10/31/3
Thanks for pointing out !
Peng,
I think what you are trying to do here is to put the anatop regulators in bypass mode so that the Freescale vendor kernel leaves them bypassed (which is what the 3.10.x based vendor kernels supporting device-tree at http://git.freescale.com/git/cgit.cgi/imx/linux-2.6-imx.git do). This is what the Freescale vendor U-Boot does and so they have created a horrible dependence between kernel and bootloader.
You are perfectly right.
Instead you may be interested in what I did for our BSP's that use the Freescale vendor kernel. Instead of touching U-Boot, I look for the fsl,ldo-bypass node in the kernel and enable it just like their bootloader would have: https://github.com/Gateworks/linux-imx6/commit/a1af6ac6f00b4da7c8a5656e8ff09...
Thanks - you are on the right direction ;-)
Best regards, Stefano

On Fri, Jan 9, 2015 at 12:59 AM, Peng Fan Peng.Fan@freescale.com wrote:
The basic graph for voltage input is: VDDARM_IN ---> LDO_DIG(ARM) ---> VDD_ARM_CAP VDDSOC_IN ---> LDO_DIG(SOC) ---> VDD_SOC_CAP
Hi Peng,
Glad to see someone else interested in IMX6 LDO bypass mode. I've made a couple of stabs at getting it supported in mainline but I haven't had the time to follow-through yet there.
We can bypass the LDO to save power, if the board already has pmic.
set_anatop_bypass is the function to do the bypass VDDARM and VDDSOC work.
Current only set VDDARM_IN@1.175V/VDDSOC_IN@1.175V before ldo bypass switch. So until ldo bypass switch happened, these voltage setting is set in ldo-enable mode. But in datasheet, we need 1.15V + 125mV = 1.275V for VDDARM_IN. We need to downgrade cpufreq to 400Mhz and restore after ldo bypass mode switch. So add prep_anatop_bypass/finish_anatop_bypass/set_arm_freq_400M to do this work.
LDO bypass is dependent on the flatten device tree file. If speed grading fuse is for 1.2GHz, enable LDO bypass and setup PMIC voltages. So add check for 1.2GHz core speed. So add check_1_2G function.
This isn't quite how it works. If you are 'operating at 1.2GHz' (supposing you had a processor cabable of it) you must use the LDO (to avoid ripple sensitivity issues).
In ldo-bypass mode, we need trigger WDOG_B pin to reset pmic in ldo-bypass mode. So add set_wdog_reset to do this work.
This is very board dependent. Here you are referring to a board that has a reset input to the PMIC's from the IMX6's watchdog output. In this case, this reset routing/pinmux would be needed regardless of using ldo-bypass mode or not and that should just be a pinmux of the pin your using for WDOG_B.
<snip>
diff --git a/arch/arm/cpu/armv7/mx6/soc.c b/arch/arm/cpu/armv7/mx6/soc.c index 5f5f497..5d02755 100644 --- a/arch/arm/cpu/armv7/mx6/soc.c +++ b/arch/arm/cpu/armv7/mx6/soc.c @@ -18,6 +18,7 @@ #include <asm/arch/sys_proto.h> #include <asm/imx-common/boot_mode.h> #include <asm/imx-common/dma.h> +#include <libfdt.h> #include <stdbool.h> #include <asm/arch/mxc_hdmi.h> #include <asm/arch/crm_regs.h> @@ -429,6 +430,146 @@ void s_init(void) writel(mask528, &anatop->pfd_528_clr); }
+#ifdef CONFIG_LDO_BYPASS_CHECK +DECLARE_GLOBAL_DATA_PTR; +static int ldo_bypass;
+int check_ldo_bypass(void) +{
const int *ldo_mode;
int node;
/* get the right fdt_blob from the global working_fdt */
gd->fdt_blob = working_fdt;
/* Get the node from FDT for anatop ldo-bypass */
node = fdt_node_offset_by_compatible(gd->fdt_blob, -1,
"fsl,imx6q-gpc");
if (node < 0) {
printf("No gpc device node %d, force to ldo-enable.\n", node);
return 0;
}
ldo_mode = fdt_getprop(gd->fdt_blob, node, "fsl,ldo-bypass", NULL);
/*
* return 1 if "fsl,ldo-bypass = <1>", else return 0 if
* "fsl,ldo-bypass = <0>" or no "fsl,ldo-bypass" property
*/
ldo_bypass = fdt32_to_cpu(*ldo_mode) == 1 ? 1 : 0;
return ldo_bypass;
+}
What you are doing here is relying on a device-tree binding from the Freescale 'vendor' kernel, which will NEVER make it upstream and this is one of the issues I was running into getting ldo-bypass capability upstream in the kernel.
The issue here is that LDO bypass is dependent on the following things: 1. your voltage rail requirements - which are dependent on the CPU frequency (there is a nice table in the IMX6 datasheets of voltage on each rail at each frequency operating point validated by Freescale). The exception of always using the LDO for 1.2GHz is specified here as well. 2. you have a PMIC in your design on VDD_ARM_IN and VDD_SOC_IN rails - this should be specified in the device-tree as well 3. you have valid PMIC drivers configured
In the kernel, its not desired to have a single device-tree node called 'fsl,ldo-bypass' for an enable. Instead you need to make sure that you PMIC regulators that are 'not' the internal IMX6 anatop regulators. This property is not a mainline linux device-tree binding.
+int check_1_2G(void) +{
u32 reg;
int result = 0;
struct ocotp_regs *ocotp = (struct ocotp_regs *)OCOTP_BASE_ADDR;
struct fuse_bank *bank = &ocotp->bank[0];
struct fuse_bank0_regs *fuse_bank0 =
(struct fuse_bank0_regs *)bank->fuse_regs;
reg = readl(&fuse_bank0->cfg3);
if (((reg >> 16) & 0x3) == 0x3) {
if (ldo_bypass) {
printf("Wrong dtb file used! i.MX6Q@1.2Ghz only works with ldo-enable mode!\n");
/*
* Currently, only imx6q-sabresd board might be here,
* since only i.MX6Q support 1.2G and only Sabresd board
* support ldo-bypass mode. So hardcode here.
* You can also modify your board(i.MX6Q) dtb name if it
* supports both ldo-bypass and ldo-enable mode.
*/
printf("Please use imx6q-sabresd-ldo.dtb!\n");
hang();
}
result = 1;
}
return result;
+}
While it is correct that you must not use LDO bypass when operating at 1.2GHz, that does not mean that a CPU capable of 1.2GHz can't use LDO bypass at the lower operating points.
+static int arm_orig_podf; +void set_arm_freq_400M(bool is_400M) +{
struct mxc_ccm_reg *mxc_ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR;
if (is_400M)
writel(0x1, &mxc_ccm->cacrr);
else
writel(arm_orig_podf, &mxc_ccm->cacrr);
+}
I have no idea what is going on here. Are we now running at different CPU frequencies in U-boot? The IMX6 comes up in either 800MHz or 400MHz per BOOT_CFG3 e-fuse and from the U-Boot I'm working with (still on 2010.04 but pretty sure its the same in 2014.10) the CPU frequency is never changed in the bootloader.
This brings me to the question of why does LDO bypass have anything at all do to with the bootloader?
It is true that the Freescale vendor kernel will keep the LDO in bypass mode if its registers are set that way from the bootloader, so that is probably what your after here. But again, that is a poor kernel implementation that likely won't make it upstream and a solution that doesn't handle the dynamic situation of a 1.2GHz cpu stepping down and not needing the LDO. It is also true that there are alternate device-tree's for the Freescale vendor kernel for some boards that have a PMIC such that one device-tree is setup to always use the LDO, and one is setup to never use the LDO. I think that is a result of taking the easy way out instead of giving the kernel the smarts to use the LDO only when needed on these boards.
Tim

On Tue, Feb 10, 2015 at 06:33:38AM -0800, Tim Harvey wrote:
On Fri, Jan 9, 2015 at 12:59 AM, Peng Fan Peng.Fan@freescale.com wrote:
The basic graph for voltage input is: VDDARM_IN ---> LDO_DIG(ARM) ---> VDD_ARM_CAP VDDSOC_IN ---> LDO_DIG(SOC) ---> VDD_SOC_CAP
Hi Peng,
Glad to see someone else interested in IMX6 LDO bypass mode. I've made a couple of stabs at getting it supported in mainline but I haven't had the time to follow-through yet there.
We can bypass the LDO to save power, if the board already has pmic.
set_anatop_bypass is the function to do the bypass VDDARM and VDDSOC work.
Current only set VDDARM_IN@1.175V/VDDSOC_IN@1.175V before ldo bypass switch. So until ldo bypass switch happened, these voltage setting is set in ldo-enable mode. But in datasheet, we need 1.15V + 125mV = 1.275V for VDDARM_IN. We need to downgrade cpufreq to 400Mhz and restore after ldo bypass mode switch. So add prep_anatop_bypass/finish_anatop_bypass/set_arm_freq_400M to do this work.
LDO bypass is dependent on the flatten device tree file. If speed grading fuse is for 1.2GHz, enable LDO bypass and setup PMIC voltages. So add check for 1.2GHz core speed. So add check_1_2G function.
This isn't quite how it works. If you are 'operating at 1.2GHz' (supposing you had a processor cabable of it) you must use the LDO (to avoid ripple sensitivity issues).
Hi Peng, the limitation is "must use ldo-enable mode in 1.2Ghz", NOT ldo-bypass
In ldo-bypass mode, we need trigger WDOG_B pin to reset pmic in ldo-bypass mode. So add set_wdog_reset to do this work.
This is very board dependent. Here you are referring to a board that has a reset input to the PMIC's from the IMX6's watchdog output. In this case, this reset routing/pinmux would be needed regardless of using ldo-bypass mode or not and that should just be a pinmux of the pin your using for WDOG_B.
There are two types of reboot in our chip by watchdog : SRS/warm reset (Software Reset Signal) and WDOG_B(reset signal output to external pmic to trigger next power cycle). In fact, warm reset can work most cases except ldo-bypass mode and this is why we connect WDOG_B reset and ldo-bypass here: kernel may trigger warm reset at the lowest cpu freq setpoint, for example VDDARM 0.975v@396Mhz ldo-bypass mode. i.mx6q will reboot with ldo-enable mode @792Mhz and the VDDARM_IN 0.975v can't support system boot.Thus, we need use WDOG_B pin to reset external pmic if using ldo-byapss mode.
<snip>
diff --git a/arch/arm/cpu/armv7/mx6/soc.c b/arch/arm/cpu/armv7/mx6/soc.c index 5f5f497..5d02755 100644 --- a/arch/arm/cpu/armv7/mx6/soc.c +++ b/arch/arm/cpu/armv7/mx6/soc.c @@ -18,6 +18,7 @@ #include <asm/arch/sys_proto.h> #include <asm/imx-common/boot_mode.h> #include <asm/imx-common/dma.h> +#include <libfdt.h> #include <stdbool.h> #include <asm/arch/mxc_hdmi.h> #include <asm/arch/crm_regs.h> @@ -429,6 +430,146 @@ void s_init(void) writel(mask528, &anatop->pfd_528_clr); }
+#ifdef CONFIG_LDO_BYPASS_CHECK +DECLARE_GLOBAL_DATA_PTR; +static int ldo_bypass;
+int check_ldo_bypass(void) +{
const int *ldo_mode;
int node;
/* get the right fdt_blob from the global working_fdt */
gd->fdt_blob = working_fdt;
/* Get the node from FDT for anatop ldo-bypass */
node = fdt_node_offset_by_compatible(gd->fdt_blob, -1,
"fsl,imx6q-gpc");
if (node < 0) {
printf("No gpc device node %d, force to ldo-enable.\n", node);
return 0;
}
ldo_mode = fdt_getprop(gd->fdt_blob, node, "fsl,ldo-bypass", NULL);
/*
* return 1 if "fsl,ldo-bypass = <1>", else return 0 if
* "fsl,ldo-bypass = <0>" or no "fsl,ldo-bypass" property
*/
ldo_bypass = fdt32_to_cpu(*ldo_mode) == 1 ? 1 : 0;
return ldo_bypass;
+}
What you are doing here is relying on a device-tree binding from the Freescale 'vendor' kernel, which will NEVER make it upstream and this is one of the issues I was running into getting ldo-bypass capability upstream in the kernel.
The issue here is that LDO bypass is dependent on the following things:
- your voltage rail requirements - which are dependent on the CPU
frequency (there is a nice table in the IMX6 datasheets of voltage on each rail at each frequency operating point validated by Freescale). The exception of always using the LDO for 1.2GHz is specified here as well. 2. you have a PMIC in your design on VDD_ARM_IN and VDD_SOC_IN rails
- this should be specified in the device-tree as well 3. you have valid PMIC drivers configured
In the kernel, its not desired to have a single device-tree node called 'fsl,ldo-bypass' for an enable. Instead you need to make sure that you PMIC regulators that are 'not' the internal IMX6 anatop regulators. This property is not a mainline linux device-tree binding.
Yes, understood. But we have no better solution, because we need touch both internal anatop regulator and external pmic regulator in ldo-bypass mode, that bring kernel cpufreq driver code too messy....
+int check_1_2G(void) +{
u32 reg;
int result = 0;
struct ocotp_regs *ocotp = (struct ocotp_regs *)OCOTP_BASE_ADDR;
struct fuse_bank *bank = &ocotp->bank[0];
struct fuse_bank0_regs *fuse_bank0 =
(struct fuse_bank0_regs *)bank->fuse_regs;
reg = readl(&fuse_bank0->cfg3);
if (((reg >> 16) & 0x3) == 0x3) {
if (ldo_bypass) {
printf("Wrong dtb file used! i.MX6Q@1.2Ghz only works with ldo-enable mode!\n");
/*
* Currently, only imx6q-sabresd board might be here,
* since only i.MX6Q support 1.2G and only Sabresd board
* support ldo-bypass mode. So hardcode here.
* You can also modify your board(i.MX6Q) dtb name if it
* supports both ldo-bypass and ldo-enable mode.
*/
printf("Please use imx6q-sabresd-ldo.dtb!\n");
hang();
}
result = 1;
}
return result;
+}
While it is correct that you must not use LDO bypass when operating at 1.2GHz, that does not mean that a CPU capable of 1.2GHz can't use LDO bypass at the lower operating points.
I see, but to simply things, we regard as 1.2GHz chip(fused) may running at 1.2GHz and force it work in ldo-enable mode although it has chance to running at 1Ghz. In other words, ldo-bypass mode only set once not dynamically.
+static int arm_orig_podf; +void set_arm_freq_400M(bool is_400M) +{
struct mxc_ccm_reg *mxc_ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR;
if (is_400M)
writel(0x1, &mxc_ccm->cacrr);
else
writel(arm_orig_podf, &mxc_ccm->cacrr);
+}
I have no idea what is going on here. Are we now running at different CPU frequencies in U-boot? The IMX6 comes up in either 800MHz or 400MHz per BOOT_CFG3 e-fuse and from the U-Boot I'm working with (still on 2010.04 but pretty sure its the same in 2014.10) the CPU frequency is never changed in the bootloader.
Let's try to explain why we downgrade cpufreq to 400Mhz before ldo-bypass mode switch(i.mx6q): cpufreq VDDSOC VDDARM 400Mhz 0.975v 1.175v 800Mhz 1.175v 1.175v If system boot from 800Mhz, considering VDDARM setting with 1.175v after ldo-bypass mode switch, and the voltage drop which bring by internal regulator 125mv, we have to set VDDARM 1.175v+125mv = 1.3v before ldo-bypass mode switch, but the 1.3v beyond our max voltage for VDDARM. So we have to downgrade the cpufreq to 400Mhz.
This brings me to the question of why does LDO bypass have anything at all do to with the bootloader?
We only need do once ldo-bypass switch, so we hope it can be implemented in u-boot
It is true that the Freescale vendor kernel will keep the LDO in bypass mode if its registers are set that way from the bootloader, so that is probably what your after here. But again, that is a poor kernel implementation that likely won't make it upstream and a solution that doesn't handle the dynamic situation of a 1.2GHz cpu stepping down and not needing the LDO. It is also true that there are alternate device-tree's for the Freescale vendor kernel for some boards that have a PMIC such that one device-tree is setup to always use the LDO, and one is setup to never use the LDO. I think that is a result of taking the easy way out instead of giving the kernel the smarts to use the LDO only when needed on these boards.
Tim

On Wed, Feb 11, 2015 at 2:49 AM, Robin Gong b38343@freescale.com wrote: <snip>
This is very board dependent. Here you are referring to a board that has a reset input to the PMIC's from the IMX6's watchdog output. In this case, this reset routing/pinmux would be needed regardless of using ldo-bypass mode or not and that should just be a pinmux of the pin your using for WDOG_B.
There are two types of reboot in our chip by watchdog : SRS/warm reset (Software Reset Signal) and WDOG_B(reset signal output to external pmic to trigger next power cycle). In fact, warm reset can work most cases except ldo-bypass mode and this is why we connect WDOG_B reset and ldo-bypass here: kernel may trigger warm reset at the lowest cpu freq setpoint, for example VDDARM 0.975v@396Mhz ldo-bypass mode. i.mx6q will reboot with ldo-enable mode @792Mhz and the VDDARM_IN 0.975v can't support system boot.Thus, we need use WDOG_B pin to reset external pmic if using ldo-byapss mode.
Hi Robin,
I understand that configuring WDOG_B external reset must be used when LDO bypass is used. This should be done in the kernel but you can also set this pinmux up in uboot in the board-specific init.
If your kernel is providing the PMIC driver and cpufreq driver that alter the cpu core frequencies it must also be configuring pinmux so that WDOG_B gets routed to the pin that connects to the PMIC so any reset based on that wdog (SRS or timeout) issues a hard reset to the PMIC. Failure to do so is a kernel bug. I believe this is done properly in the Freescale kernel for the reference boards.
If you are trying to take care of an issue caused by a watchdog reset (SRS or timeout) not properly resetting a PMIC (ie perhaps a PCB errata where signal doesn't go to the PMIC) then you should probably simply set the PMIC rails where they need to be for the 800MHz operation in the bootloader and not muck with the CPU frequency. Honestly, if your PMIC rails are too low for 800MHz on powerup your bootloader may not be stable anyway right? Note that the operating setpoints have the same SOC voltage for both 792MHz and 396MHz, its only the ARM voltage that is lower for 396 vs 792 and chances are your not going to have an issue just in the bootloader at that point.
<snip>
What you are doing here is relying on a device-tree binding from the Freescale 'vendor' kernel, which will NEVER make it upstream and this is one of the issues I was running into getting ldo-bypass capability upstream in the kernel.
The issue here is that LDO bypass is dependent on the following things:
- your voltage rail requirements - which are dependent on the CPU
frequency (there is a nice table in the IMX6 datasheets of voltage on each rail at each frequency operating point validated by Freescale). The exception of always using the LDO for 1.2GHz is specified here as well. 2. you have a PMIC in your design on VDD_ARM_IN and VDD_SOC_IN rails
- this should be specified in the device-tree as well 3. you have valid PMIC drivers configured
In the kernel, its not desired to have a single device-tree node called 'fsl,ldo-bypass' for an enable. Instead you need to make sure that you PMIC regulators that are 'not' the internal IMX6 anatop regulators. This property is not a mainline linux device-tree binding.
Yes, understood. But we have no better solution, because we need touch both internal anatop regulator and external pmic regulator in ldo-bypass mode, that bring kernel cpufreq driver code too messy....
I just don't see the point in having the CPU frequency changed in the bootloader - leave this up to the OS kernel. I don't think any of this patch should go into mainline uboot.
I think my kernel patch I referenced provides you with a simple kernel solution that de-couples ldo-bypass completely from the bootloader.
<snip>
While it is correct that you must not use LDO bypass when operating at 1.2GHz, that does not mean that a CPU capable of 1.2GHz can't use LDO bypass at the lower operating points.
I see, but to simply things, we regard as 1.2GHz chip(fused) may running at 1.2GHz and force it work in ldo-enable mode although it has chance to running at 1Ghz. In other words, ldo-bypass mode only set once not dynamically.
Are you saying there is an IMX6 variant that powers up per eFUSE settings at 1.2GHz? The IMX6QDLRM efuse settings I'm looking at just have two power-up frequency options: 392MHz and 792MHz.
In my opinion, your PMIC should be setting VDD_ARM and VDD_SOC at the necessary voltages for what the CPU is currently running at, in the bootloader. Its up to your OS to properly control this to its needs later. Again, if for some reason (hardware errata) you have a situation where the PMIC maybe didn't get reset and the board powers up into the bootloader at a frequency higher than the rails are set to, then simply set its rails to where they need to be for the freq your running at in the bootloader.
+static int arm_orig_podf; +void set_arm_freq_400M(bool is_400M) +{
struct mxc_ccm_reg *mxc_ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR;
if (is_400M)
writel(0x1, &mxc_ccm->cacrr);
else
writel(arm_orig_podf, &mxc_ccm->cacrr);
+}
I have no idea what is going on here. Are we now running at different CPU frequencies in U-boot? The IMX6 comes up in either 800MHz or 400MHz per BOOT_CFG3 e-fuse and from the U-Boot I'm working with (still on 2010.04 but pretty sure its the same in 2014.10) the CPU frequency is never changed in the bootloader.
Let's try to explain why we downgrade cpufreq to 400Mhz before ldo-bypass mode switch(i.mx6q): cpufreq VDDSOC VDDARM 400Mhz 0.975v 1.175v 800Mhz 1.175v 1.175v If system boot from 800Mhz, considering VDDARM setting with 1.175v after ldo-bypass mode switch, and the voltage drop which bring by internal regulator 125mv, we have to set VDDARM 1.175v+125mv = 1.3v before ldo-bypass mode switch, but the 1.3v beyond our max voltage for VDDARM. So we have to downgrade the cpufreq to 400Mhz.
Too much complexity in my opinion for the power reduction benefits while in the bootloader. Leave ldo-bypass out of the bootloader and you won't have to bother with this. The IMX6 can handle a max of 1.3V on VDD_ARM_IN and VDD_SOC_IN (and 1.5V on the output side of the LDO). So you can simply set your PMIC in the bootloader to something between that and 1.175v and be done with it right?
This brings me to the question of why does LDO bypass have anything at all do to with the bootloader?
We only need do once ldo-bypass switch, so we hope it can be implemented in u-boot
It doesn't belong in uboot. It was wrong for Freescale to create a dependence between the bootloader and the kernel when it is so easy to avoid.
I don't think any of this particular patch should go into mainline uboot.
Regards,
Tim

On Wed, Feb 11, 2015 at 7:47 AM, Tim Harvey tharvey@gateworks.com wrote:
On Wed, Feb 11, 2015 at 2:49 AM, Robin Gong b38343@freescale.com wrote:
<snip> >> >> This is very board dependent. Here you are referring to a board that >> has a reset input to the PMIC's from the IMX6's watchdog output. In >> this case, this reset routing/pinmux would be needed regardless of >> using ldo-bypass mode or not and that should just be a pinmux of the >> pin your using for WDOG_B. >> > There are two types of reboot in our chip by watchdog : SRS/warm reset > (Software Reset Signal) and WDOG_B(reset signal output to external pmic > to trigger next power cycle). In fact, warm reset can work most cases except > ldo-bypass mode and this is why we connect WDOG_B reset and ldo-bypass here: > kernel may trigger warm reset at the lowest cpu freq setpoint, for example > VDDARM 0.975v@396Mhz ldo-bypass mode. i.mx6q will reboot with ldo-enable mode > @792Mhz and the VDDARM_IN 0.975v can't support system boot.Thus, we need use > WDOG_B pin to reset external pmic if using ldo-byapss mode.
Hi Robin,
I understand that configuring WDOG_B external reset must be used when LDO bypass is used. This should be done in the kernel but you can also set this pinmux up in uboot in the board-specific init.
If your kernel is providing the PMIC driver and cpufreq driver that alter the cpu core frequencies it must also be configuring pinmux so that WDOG_B gets routed to the pin that connects to the PMIC so any reset based on that wdog (SRS or timeout) issues a hard reset to the PMIC. Failure to do so is a kernel bug. I believe this is done properly in the Freescale kernel for the reference boards.
If you are trying to take care of an issue caused by a watchdog reset (SRS or timeout) not properly resetting a PMIC (ie perhaps a PCB errata where signal doesn't go to the PMIC) then you should probably simply set the PMIC rails where they need to be for the 800MHz operation in the bootloader and not muck with the CPU frequency. Honestly, if your PMIC rails are too low for 800MHz on powerup your bootloader may not be stable anyway right? Note that the operating setpoints have the same SOC voltage for both 792MHz and 396MHz, its only the ARM voltage that is lower for 396 vs 792 and chances are your not going to have an issue just in the bootloader at that point.
Robin,
The issue your describing was interesting to me and I ran some tests and found that on a board with no reset to the PMIC, an IMX6Q CPU, ldo-bypass enabled, and the CPU freq set to 400MHz (such that VDD_ARM rail set to 0.960V for 400MHz operation) the chip does not even come out of reset (ie when SRS is set in the watchdog controller). So I don't really see any ability to work around this in bootloader software since you won't get there in this case.
Possible solutions I can think of for boards without a PMIC reset is to either blow the eFUSE so the chip comes up in 400MHz or in the kernel never allow the VDD_ARM or VDD_SOC rail to go below where they need to be for CPU startup (the only one that does is VDD_ARM) or before soft-reboot make sure the cpufreq is at 800MHz or above (which must be done at higher levels before single-cpu mode in machine_restart). This also does not deal with the case of a watchdog reset and/or a crash handler.
Are you findings different?
Tim

On Thu, Feb 12, 2015 at 04:08:51PM -0800, Tim Harvey wrote:
On Wed, Feb 11, 2015 at 7:47 AM, Tim Harvey tharvey@gateworks.com wrote:
On Wed, Feb 11, 2015 at 2:49 AM, Robin Gong b38343@freescale.com wrote:
<snip> >> >> This is very board dependent. Here you are referring to a board that >> has a reset input to the PMIC's from the IMX6's watchdog output. In >> this case, this reset routing/pinmux would be needed regardless of >> using ldo-bypass mode or not and that should just be a pinmux of the >> pin your using for WDOG_B. >> > There are two types of reboot in our chip by watchdog : SRS/warm reset > (Software Reset Signal) and WDOG_B(reset signal output to external pmic > to trigger next power cycle). In fact, warm reset can work most cases except > ldo-bypass mode and this is why we connect WDOG_B reset and ldo-bypass here: > kernel may trigger warm reset at the lowest cpu freq setpoint, for example > VDDARM 0.975v@396Mhz ldo-bypass mode. i.mx6q will reboot with ldo-enable mode > @792Mhz and the VDDARM_IN 0.975v can't support system boot.Thus, we need use > WDOG_B pin to reset external pmic if using ldo-byapss mode.
Hi Robin,
I understand that configuring WDOG_B external reset must be used when LDO bypass is used. This should be done in the kernel but you can also set this pinmux up in uboot in the board-specific init.
If your kernel is providing the PMIC driver and cpufreq driver that alter the cpu core frequencies it must also be configuring pinmux so that WDOG_B gets routed to the pin that connects to the PMIC so any reset based on that wdog (SRS or timeout) issues a hard reset to the PMIC. Failure to do so is a kernel bug. I believe this is done properly in the Freescale kernel for the reference boards.
If you are trying to take care of an issue caused by a watchdog reset (SRS or timeout) not properly resetting a PMIC (ie perhaps a PCB errata where signal doesn't go to the PMIC) then you should probably simply set the PMIC rails where they need to be for the 800MHz operation in the bootloader and not muck with the CPU frequency. Honestly, if your PMIC rails are too low for 800MHz on powerup your bootloader may not be stable anyway right? Note that the operating setpoints have the same SOC voltage for both 792MHz and 396MHz, its only the ARM voltage that is lower for 396 vs 792 and chances are your not going to have an issue just in the bootloader at that point.
Robin,
The issue your describing was interesting to me and I ran some tests and found that on a board with no reset to the PMIC, an IMX6Q CPU, ldo-bypass enabled, and the CPU freq set to 400MHz (such that VDD_ARM rail set to 0.960V for 400MHz operation) the chip does not even come out of reset (ie when SRS is set in the watchdog controller). So I don't really see any ability to work around this in bootloader software since you won't get there in this case.
Yes, ldo-bypass mode depends on reset PMIC while reboot happen. But even on this feature supported boards, we'd better provide warm reset in ldo-enable mode,for example, warm reset can keep printed log in DDR while system crash in last time and trigger watchdog reset. Someone may use DCDC instead of PMIC, or some board didn't connect WDOG_B reset with PMIC, have to use ldo-enable mode.
Possible solutions I can think of for boards without a PMIC reset is to either blow the eFUSE so the chip comes up in 400MHz or in the kernel never allow the VDD_ARM or VDD_SOC rail to go below where they need to be for CPU startup (the only one that does is VDD_ARM) or before soft-reboot make sure the cpufreq is at 800MHz or above (which must be done at higher levels before single-cpu mode in machine_restart). This also does not deal with the case of a watchdog reset and/or a crash handler.
Yes, absolutely. But we suggest connecting PMIC reset pin with WDOG_B or just use ldo-enable mode if they are not very care of power number.
Are you findings different?
Tim

On Wed, Feb 11, 2015 at 07:47:57AM -0800, Tim Harvey wrote:
On Wed, Feb 11, 2015 at 2:49 AM, Robin Gong b38343@freescale.com wrote:
<snip> >> >> This is very board dependent. Here you are referring to a board that >> has a reset input to the PMIC's from the IMX6's watchdog output. In >> this case, this reset routing/pinmux would be needed regardless of >> using ldo-bypass mode or not and that should just be a pinmux of the >> pin your using for WDOG_B. >> > There are two types of reboot in our chip by watchdog : SRS/warm reset > (Software Reset Signal) and WDOG_B(reset signal output to external pmic > to trigger next power cycle). In fact, warm reset can work most cases except > ldo-bypass mode and this is why we connect WDOG_B reset and ldo-bypass here: > kernel may trigger warm reset at the lowest cpu freq setpoint, for example > VDDARM 0.975v@396Mhz ldo-bypass mode. i.mx6q will reboot with ldo-enable mode > @792Mhz and the VDDARM_IN 0.975v can't support system boot.Thus, we need use > WDOG_B pin to reset external pmic if using ldo-byapss mode.
Hi Robin,
I understand that configuring WDOG_B external reset must be used when LDO bypass is used. This should be done in the kernel but you can also set this pinmux up in uboot in the board-specific init.
If your kernel is providing the PMIC driver and cpufreq driver that alter the cpu core frequencies it must also be configuring pinmux so that WDOG_B gets routed to the pin that connects to the PMIC so any reset based on that wdog (SRS or timeout) issues a hard reset to the PMIC. Failure to do so is a kernel bug. I believe this is done properly in the Freescale kernel for the reference boards.
pinmux is not enough. WDT bit of WDOGx_WCR need to be taken care of if you want to enable WDOG_B pin reset function. But unfortunately the current wdog driver of kernel not touch this write-once bit. To limit the impact from kernel, set this bit in u-boot.
If you are trying to take care of an issue caused by a watchdog reset (SRS or timeout) not properly resetting a PMIC (ie perhaps a PCB errata where signal doesn't go to the PMIC) then you should probably simply set the PMIC rails where they need to be for the 800MHz operation in the bootloader and not muck with the CPU frequency. Honestly, if your PMIC rails are too low for 800MHz on powerup your bootloader may not be stable anyway right? Note that the operating setpoints have the same SOC voltage for both 792MHz and 396MHz, its only the ARM voltage that is lower for 396 vs 792 and chances are your not going to have an issue just in the bootloader at that point.
As you saw in another mail, bootloader is too late. It'll hang in ROM code.
<snip> >> >> What you are doing here is relying on a device-tree binding from the >> Freescale 'vendor' kernel, which will NEVER make it upstream and this >> is one of the issues I was running into getting ldo-bypass capability >> upstream in the kernel. >> >> The issue here is that LDO bypass is dependent on the following things: >> 1. your voltage rail requirements - which are dependent on the CPU >> frequency (there is a nice table in the IMX6 datasheets of voltage on >> each rail at each frequency operating point validated by Freescale). >> The exception of always using the LDO for 1.2GHz is specified here as >> well. >> 2. you have a PMIC in your design on VDD_ARM_IN and VDD_SOC_IN rails >> - this should be specified in the device-tree as well >> 3. you have valid PMIC drivers configured >> >> In the kernel, its not desired to have a single device-tree node >> called 'fsl,ldo-bypass' for an enable. Instead you need to make sure >> that you PMIC regulators that are 'not' the internal IMX6 anatop >> regulators. This property is not a mainline linux device-tree binding. >> > Yes, understood. But we have no better solution, because we need touch both > internal anatop regulator and external pmic regulator in ldo-bypass mode, that > bring kernel cpufreq driver code too messy....
I just don't see the point in having the CPU frequency changed in the bootloader - leave this up to the OS kernel. I don't think any of this patch should go into mainline uboot.
I think my kernel patch I referenced provides you with a simple kernel solution that de-couples ldo-bypass completely from the bootloader.
Can you please share me the patch link? Thanks.
<snip> >> >> While it is correct that you must not use LDO bypass when operating at >> 1.2GHz, that does not mean that a CPU capable of 1.2GHz can't use LDO >> bypass at the lower operating points. >> > I see, but to simply things, we regard as 1.2GHz chip(fused) may running at > 1.2GHz and force it work in ldo-enable mode although it has chance to running > at 1Ghz. In other words, ldo-bypass mode only set once not dynamically.
Are you saying there is an IMX6 variant that powers up per eFUSE settings at 1.2GHz? The IMX6QDLRM efuse settings I'm looking at just have two power-up frequency options: 392MHz and 792MHz.
Sorry, I mean max frequency(SPEED_GRADING[1:0]), not power-up frequency.
In my opinion, your PMIC should be setting VDD_ARM and VDD_SOC at the necessary voltages for what the CPU is currently running at, in the bootloader. Its up to your OS to properly control this to its needs later. Again, if for some reason (hardware errata) you have a situation where the PMIC maybe didn't get reset and the board powers up into the bootloader at a frequency higher than the rails are set to, then simply set its rails to where they need to be for the freq your running at in the bootloader.
+static int arm_orig_podf; +void set_arm_freq_400M(bool is_400M) +{
struct mxc_ccm_reg *mxc_ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR;
if (is_400M)
writel(0x1, &mxc_ccm->cacrr);
else
writel(arm_orig_podf, &mxc_ccm->cacrr);
+}
I have no idea what is going on here. Are we now running at different CPU frequencies in U-boot? The IMX6 comes up in either 800MHz or 400MHz per BOOT_CFG3 e-fuse and from the U-Boot I'm working with (still on 2010.04 but pretty sure its the same in 2014.10) the CPU frequency is never changed in the bootloader.
Let's try to explain why we downgrade cpufreq to 400Mhz before ldo-bypass mode switch(i.mx6q): cpufreq VDDSOC VDDARM 400Mhz 0.975v 1.175v 800Mhz 1.175v 1.175v If system boot from 800Mhz, considering VDDARM setting with 1.175v after ldo-bypass mode switch, and the voltage drop which bring by internal regulator 125mv, we have to set VDDARM 1.175v+125mv = 1.3v before ldo-bypass mode switch, but the 1.3v beyond our max voltage for VDDARM. So we have to downgrade the cpufreq to 400Mhz.
Too much complexity in my opinion for the power reduction benefits while in the bootloader. Leave ldo-bypass out of the bootloader and you won't have to bother with this. The IMX6 can handle a max of 1.3V on VDD_ARM_IN and VDD_SOC_IN (and 1.5V on the output side of the LDO). So you can simply set your PMIC in the bootloader to something between that and 1.175v and be done with it right?
Not for power reduction, just for match with the voltage setting which data sheet saying in any time or any narrow timing window. Have to set VDDRAM_IN 1.3v for 800Mhz(VDDARM 1.175v) before ldo-bypass mode switched. And set VDDARM_IN to 1.175v after ldo-bypass mode switched. But in the narrow window which VDDARM_IN from 1.3v to 1.175v with ldo-bypass mode enabled. The 1.3v plus power ripple may beyond the max volage.
This brings me to the question of why does LDO bypass have anything at all do to with the bootloader?
We only need do once ldo-bypass switch, so we hope it can be implemented in u-boot
It doesn't belong in uboot. It was wrong for Freescale to create a dependence between the bootloader and the kernel when it is so easy to avoid.
I don't think any of this particular patch should go into mainline uboot.
Tim, thanks for your reviewing, understood your concerning. Looks it's better done in kernel.
Regards,
Tim

On Fri, Feb 13, 2015 at 12:16 AM, Robin Gong b38343@freescale.com wrote:
On Wed, Feb 11, 2015 at 07:47:57AM -0800, Tim Harvey wrote:
On Wed, Feb 11, 2015 at 2:49 AM, Robin Gong b38343@freescale.com wrote:
<snip> >> >> This is very board dependent. Here you are referring to a board that >> has a reset input to the PMIC's from the IMX6's watchdog output. In >> this case, this reset routing/pinmux would be needed regardless of >> using ldo-bypass mode or not and that should just be a pinmux of the >> pin your using for WDOG_B. >> > There are two types of reboot in our chip by watchdog : SRS/warm reset > (Software Reset Signal) and WDOG_B(reset signal output to external pmic > to trigger next power cycle). In fact, warm reset can work most cases except > ldo-bypass mode and this is why we connect WDOG_B reset and ldo-bypass here: > kernel may trigger warm reset at the lowest cpu freq setpoint, for example > VDDARM 0.975v@396Mhz ldo-bypass mode. i.mx6q will reboot with ldo-enable mode > @792Mhz and the VDDARM_IN 0.975v can't support system boot.Thus, we need use > WDOG_B pin to reset external pmic if using ldo-byapss mode.
Hi Robin,
I understand that configuring WDOG_B external reset must be used when LDO bypass is used. This should be done in the kernel but you can also set this pinmux up in uboot in the board-specific init.
If your kernel is providing the PMIC driver and cpufreq driver that alter the cpu core frequencies it must also be configuring pinmux so that WDOG_B gets routed to the pin that connects to the PMIC so any reset based on that wdog (SRS or timeout) issues a hard reset to the PMIC. Failure to do so is a kernel bug. I believe this is done properly in the Freescale kernel for the reference boards.
pinmux is not enough. WDT bit of WDOGx_WCR need to be taken care of if you want to enable WDOG_B pin reset function. But unfortunately the current wdog driver of kernel not touch this write-once bit. To limit the impact from kernel, set this bit in u-boot.
Hi Robin,
'To limit the impact from kernel, set this bit in u-boot' indicates that you are trying to create a u-boot and kernel dependence on each other which is a bad idea. The kernel should take care of everything it needs without making assumptions on what the bootloader did.
You are correct in that the current imx2_wdt.c does not 'set' the write-once WCR bit to enable the external reset but it does seem funny to me that Freescale decided to patch system.c's mxc_restart (http://git.freescale.com/git/cgit.cgi/imx/linux-2.6-imx.git/commit/arch/arm/...) to try to deal with the machine_restart case but did not patch imx2_wdt.c to deal with the watchdog timeout case.
Wouldn't these boards also hang when reset from a watchdog timeout when using ldo-enabled and CPU@397Mhz. It seems to me that you should also be patching imx2_wdt.c to set WCR for that case.
If you are trying to take care of an issue caused by a watchdog reset (SRS or timeout) not properly resetting a PMIC (ie perhaps a PCB errata where signal doesn't go to the PMIC) then you should probably simply set the PMIC rails where they need to be for the 800MHz operation in the bootloader and not muck with the CPU frequency. Honestly, if your PMIC rails are too low for 800MHz on powerup your bootloader may not be stable anyway right? Note that the operating setpoints have the same SOC voltage for both 792MHz and 396MHz, its only the ARM voltage that is lower for 396 vs 792 and chances are your not going to have an issue just in the bootloader at that point.
As you saw in another mail, bootloader is too late. It'll hang in ROM code.
<snip>
Can you please share me the patch link? Thanks.
The link was further up in the thread in response to Peng:
Instead of touching U-Boot, in my 'Freescale' kernel I look for the fsl,ldo-bypass node in the kernel init and enable it just like their bootloader would have:
https://github.com/Gateworks/linux-imx6/commit/a1af6ac6f00b4da7c8a5656e8ff09...
It is still not good to rely on the fsl,ldo-bypass property to be set (which will never make it into mainline) because this does not garuntee that ldo-bypass is setup and functioning correctly at all (ie user could have PMIC driver disabled, or not configured in device-tree properly as source for arm/soc rails) but I haven't figured out the best solution upstream yet and haven't had time to get back to it. Its still a much lesser evil than requiring that ldo-bypass be configured in the bootloader. This patch removes the dependence upon the bootloader (I will never use Freescales hacked up U-Boot - I think its still based on a 2009 branch).
I have given up on getting patches into Freescale's kernel - perhaps being an employee you will have better luck :) I'm still hoping that someday mainline linux will have all the IPU/VPU/GPU support for IMX6 that is missing (but getting very close!) which is what is forcing me to use Freescale's kernel for some of our BSP's.
Tim

Add ldo_mode_set function. If ldo_bypass is true, it will adjust voltage. If not, do nothing.
This function is board specific, so implement it in board file.
Signed-off-by: Peng Fan Peng.Fan@freescale.com Signed-off-by: Robin Gong b38343@freescale.com --- board/freescale/mx6slevk/mx6slevk.c | 61 ++++++++++++++++++++++++++++++++++--- include/configs/mx6slevk.h | 2 ++ 2 files changed, 59 insertions(+), 4 deletions(-)
diff --git a/board/freescale/mx6slevk/mx6slevk.c b/board/freescale/mx6slevk/mx6slevk.c index f74b237..fdb6672 100644 --- a/board/freescale/mx6slevk/mx6slevk.c +++ b/board/freescale/mx6slevk/mx6slevk.c @@ -247,16 +247,69 @@ struct i2c_pads_info i2c_pad_info1 = { }, };
+static struct pmic *pfuze; + +#ifdef CONFIG_LDO_BYPASS_CHECK +void ldo_mode_set(int ldo_bypass) +{ + u32 value; + int is_400M; + struct pmic *p = pfuze; + + if (!p) + return; + + /* swith to ldo_bypass mode */ + if (ldo_bypass) { + prep_anatop_bypass(); + + /* decrease VDDARM to 1.1V */ + pmic_reg_read(p, PFUZE100_SW1ABVOL, &value); + value &= ~0x3f; + value |= PFUZE100_SW1ABC_SETP(11000); + pmic_reg_write(p, PFUZE100_SW1ABVOL, value); + + /* increase VDDSOC to 1.3V */ + pmic_reg_read(p, PFUZE100_SW1CVOL, &value); + value &= ~0x3f; + value |= PFUZE100_SW1ABC_SETP(13000); + pmic_reg_write(p, PFUZE100_SW1CVOL, value); + + is_400M = set_anatop_bypass(0); + + /* + * MX6SL: VDDARM:1.175V@800M; VDDSOC:1.175V@800M + * VDDARM:0.975V@400M; VDDSOC:1.175V@400M + */ + pmic_reg_read(p, PFUZE100_SW1ABVOL, &value); + value &= ~0x3f; + if (is_400M) + value |= PFUZE100_SW1ABC_SETP(9750); + else + value |= PFUZE100_SW1ABC_SETP(11750); + pmic_reg_write(p, PFUZE100_SW1ABVOL, value); + + /* decrease VDDSOC to 1.175V */ + pmic_reg_read(p, PFUZE100_SW1CVOL, &value); + value &= ~0x3f; + value |= PFUZE100_SW1ABC_SETP(11750); + pmic_reg_write(p, PFUZE100_SW1CVOL, value); + + finish_anatop_bypass(); + printf("switch to ldo_bypass mode!\n"); + } +} +#endif + int power_init_board(void) { - struct pmic *p; unsigned int ret;
- p = pfuze_common_init(I2C_PMIC); - if (!p) + pfuze = pfuze_common_init(I2C_PMIC); + if (!pfuze) return -ENODEV;
- ret = pfuze_mode_init(p, APS_PFM); + ret = pfuze_mode_init(pfuze, APS_PFM); if (ret < 0) return -EIO;
diff --git a/include/configs/mx6slevk.h b/include/configs/mx6slevk.h index 9fd7619..56c2faf 100644 --- a/include/configs/mx6slevk.h +++ b/include/configs/mx6slevk.h @@ -60,6 +60,8 @@ #define CONFIG_POWER_PFUZE100 #define CONFIG_POWER_PFUZE100_I2C_ADDR 0x08
+#define CONFIG_LDO_BYPASS_CHECK + #define CONFIG_CMD_PING #define CONFIG_CMD_DHCP #define CONFIG_CMD_MII

If runs at 1.2GHz, enable ldo, and adjust voltage.
If ldo_bypass is true, it will adjust voltage. If not, do nothing.
This function is board specific, so implement it in board file.
Signed-off-by: Peng Fan Peng.Fan@freescale.com Signed-off-by: Robin Gong b38343@freescale.com Signed-off-by: Nitin Garg nitin.garg@freescale.com --- board/freescale/mx6sabresd/mx6sabresd.c | 85 +++++++++++++++++++++++++++++++++ include/configs/mx6sabresd.h | 2 + 2 files changed, 87 insertions(+)
diff --git a/board/freescale/mx6sabresd/mx6sabresd.c b/board/freescale/mx6sabresd/mx6sabresd.c index 59544d9..9e0a8ae 100644 --- a/board/freescale/mx6sabresd/mx6sabresd.c +++ b/board/freescale/mx6sabresd/mx6sabresd.c @@ -628,6 +628,7 @@ int board_init(void) return 0; }
+static struct pmic *pfuze; int power_init_board(void) { struct pmic *p; @@ -636,6 +637,7 @@ int power_init_board(void) p = pfuze_common_init(I2C_PMIC); if (!p) return -ENODEV; + pfuze = p;
ret = pfuze_mode_init(p, APS_PFM); if (ret < 0) @@ -656,6 +658,89 @@ int power_init_board(void) return 0; }
+#ifdef CONFIG_LDO_BYPASS_CHECK +void ldo_mode_set(int ldo_bypass) +{ + unsigned int value; + int is_400M; + unsigned char vddarm; + struct pmic *p = pfuze; + + /* increase VDDARM/VDDSOC to support 1.2G chip */ + if (check_1_2G()) { + ldo_bypass = 0; /* ldo_enable on 1.2G chip */ + printf("1.2G chip, increase VDDARM_IN/VDDSOC_IN\n"); + /* increase VDDARM to 1.425V */ + pmic_reg_read(p, PFUZE100_SW1ABVOL, &value); + value &= ~0x3f; + value |= PFUZE100_SW1ABC_SETP(14250); + pmic_reg_write(p, PFUZE100_SW1ABVOL, value); + + /* increase VDDSOC to 1.425V */ + pmic_reg_read(p, PFUZE100_SW1CVOL, &value); + value &= ~0x3f; + value |= PFUZE100_SW1ABC_SETP(14250); + pmic_reg_write(p, PFUZE100_SW1CVOL, value); + } + /* switch to ldo_bypass mode , boot on 800Mhz */ + if (ldo_bypass) { + prep_anatop_bypass(); + + /* decrease VDDARM for 400Mhz DQ:1.1V, DL:1.275V */ + pmic_reg_read(p, PFUZE100_SW1ABVOL, &value); + value &= ~0x3f; +#if defined(CONFIG_MX6DL) + value |= PFUZE100_SW1ABC_SETP(12750); +#else + value |= PFUZE100_SW1ABC_SETP(11000); +#endif + pmic_reg_write(p, PFUZE100_SW1ABVOL, value); + + /* increase VDDSOC to 1.3V */ + pmic_reg_read(p, PFUZE100_SW1CVOL, &value); + value &= ~0x3f; + value |= PFUZE100_SW1ABC_SETP(13000); + pmic_reg_write(p, PFUZE100_SW1CVOL, value); + + /* + * MX6Q: + * VDDARM:1.15V@800M; VDDSOC:1.175V@800M + * VDDARM:0.975V@400M; VDDSOC:1.175V@400M + * MX6DL: + * VDDARM:1.175V@800M; VDDSOC:1.175V@800M + * VDDARM:1.075V@400M; VDDSOC:1.175V@400M + */ + is_400M = set_anatop_bypass(2); + if (is_400M) +#if defined(CONFIG_MX6DL) + vddarm = PFUZE100_SW1ABC_SETP(10750); +#else + vddarm = PFUZE100_SW1ABC_SETP(9750); +#endif + else +#if defined(CONFIG_MX6DL) + vddarm = PFUZE100_SW1ABC_SETP(11750); +#else + vddarm = PFUZE100_SW1ABC_SETP(11500); +#endif + + pmic_reg_read(p, PFUZE100_SW1ABVOL, &value); + value &= ~0x3f; + value |= vddarm; + pmic_reg_write(p, PFUZE100_SW1ABVOL, value); + + /* decrease VDDSOC to 1.175V */ + pmic_reg_read(p, PFUZE100_SW1CVOL, &value); + value &= ~0x3f; + value |= PFUZE100_SW1ABC_SETP(11750); + pmic_reg_write(p, PFUZE100_SW1CVOL, value); + + finish_anatop_bypass(); + printf("switch to ldo_bypass mode!\n"); + } +} +#endif + #ifdef CONFIG_MXC_SPI int board_spi_cs_gpio(unsigned bus, unsigned cs) { diff --git a/include/configs/mx6sabresd.h b/include/configs/mx6sabresd.h index 99d9d4d..70dbf30 100644 --- a/include/configs/mx6sabresd.h +++ b/include/configs/mx6sabresd.h @@ -60,6 +60,8 @@ #define CONFIG_POWER_PFUZE100 #define CONFIG_POWER_PFUZE100_I2C_ADDR 0x08
+#define CONFIG_LDO_BYPASS_CHECK + /* USB Configs */ #define CONFIG_CMD_USB #ifdef CONFIG_CMD_USB

Add ldo_mode_set function. If ldo_bypass is true, it will adjust voltage. If not, do nothing.
This function is board specific, so implement it in board file.
Signed-off-by: Peng Fan Peng.Fan@freescale.com Signed-off-by: Robin Gong b38343@freescale.com --- board/freescale/mx6sxsabresd/mx6sxsabresd.c | 50 +++++++++++++++++++++++++++++ include/configs/mx6sxsabresd.h | 2 ++ 2 files changed, 52 insertions(+)
diff --git a/board/freescale/mx6sxsabresd/mx6sxsabresd.c b/board/freescale/mx6sxsabresd/mx6sxsabresd.c index fbf3337..36432c4 100644 --- a/board/freescale/mx6sxsabresd/mx6sxsabresd.c +++ b/board/freescale/mx6sxsabresd/mx6sxsabresd.c @@ -196,6 +196,7 @@ static struct i2c_pads_info i2c_pad_info1 = { }, };
+static struct pmic *pfuze; int power_init_board(void) { struct pmic *p; @@ -204,6 +205,7 @@ int power_init_board(void) p = pfuze_common_init(I2C_PMIC); if (!p) return -ENODEV; + pfuze = p;
ret = pfuze_mode_init(p, APS_PFM); if (ret < 0) @@ -218,6 +220,54 @@ int power_init_board(void) return 0; }
+#ifdef CONFIG_LDO_BYPASS_CHECK +void ldo_mode_set(int ldo_bypass) +{ + unsigned int value; + int is_400M; + u32 vddarm; + struct pmic *p = pfuze; + + if (!p) + return; + + /* switch to ldo_bypass mode */ + if (ldo_bypass) { + prep_anatop_bypass(); + /* decrease VDDARM to 1.275V */ + pmic_reg_read(p, PFUZE100_SW1ABVOL, &value); + value &= ~0x3f; + value |= PFUZE100_SW1ABC_SETP(12750); + pmic_reg_write(p, PFUZE100_SW1ABVOL, value); + + /* decrease VDDSOC to 1.3V */ + pmic_reg_read(p, PFUZE100_SW1CVOL, &value); + value &= ~0x3f; + value |= PFUZE100_SW1ABC_SETP(13000); + pmic_reg_write(p, PFUZE100_SW1CVOL, value); + + is_400M = set_anatop_bypass(1); + if (is_400M) + vddarm = PFUZE100_SW1ABC_SETP(10750); + else + vddarm = PFUZE100_SW1ABC_SETP(11750); + + pmic_reg_read(p, PFUZE100_SW1ABVOL, &value); + value &= ~0x3f; + value |= vddarm; + pmic_reg_write(p, PFUZE100_SW1ABVOL, value); + + pmic_reg_read(p, PFUZE100_SW1CVOL, &value); + value &= ~0x3f; + value |= PFUZE100_SW1ABC_SETP(11750); + pmic_reg_write(p, PFUZE100_SW1CVOL, value); + + finish_anatop_bypass(); + printf("switch to ldo_bypass mode!\n"); + } +} +#endif + #ifdef CONFIG_USB_EHCI_MX6 #define USB_OTHERREGS_OFFSET 0x800 #define UCTRL_PWR_POL (1 << 9) diff --git a/include/configs/mx6sxsabresd.h b/include/configs/mx6sxsabresd.h index 469d250..d69310e 100644 --- a/include/configs/mx6sxsabresd.h +++ b/include/configs/mx6sxsabresd.h @@ -181,6 +181,8 @@ #define CONFIG_POWER_PFUZE100 #define CONFIG_POWER_PFUZE100_I2C_ADDR 0x08
+#define CONFIG_LDO_BYPASS_CHECK + /* Network */ #define CONFIG_CMD_PING #define CONFIG_CMD_DHCP

If runs at 1.2GHz, enable ldo, and adjust voltage. Otherwise, do nothing
Signed-off-by: Peng Fan Peng.Fan@freescale.com Signed-off-by: Robin Gong b38343@freescale.com --- board/freescale/mx6qsabreauto/mx6qsabreauto.c | 31 +++++++++++++++++++++++++++ include/configs/mx6qsabreauto.h | 2 ++ 2 files changed, 33 insertions(+)
diff --git a/board/freescale/mx6qsabreauto/mx6qsabreauto.c b/board/freescale/mx6qsabreauto/mx6qsabreauto.c index b29ff2b..84ac9b7 100644 --- a/board/freescale/mx6qsabreauto/mx6qsabreauto.c +++ b/board/freescale/mx6qsabreauto/mx6qsabreauto.c @@ -29,6 +29,7 @@ #include <asm/arch/crm_regs.h> #include <pca953x.h> #include <power/pmic.h> +#include <power/pfuze100_pmic.h> #include "../common/pfuze.h"
DECLARE_GLOBAL_DATA_PTR; @@ -512,6 +513,7 @@ int board_spi_cs_gpio(unsigned bus, unsigned cs) } #endif
+static struct pmic *pfuze; int power_init_board(void) { struct pmic *p; @@ -520,6 +522,7 @@ int power_init_board(void) p = pfuze_common_init(I2C_PMIC); if (!p) return -ENODEV; + pfuze = p;
ret = pfuze_mode_init(p, APS_PFM); if (ret < 0) @@ -528,6 +531,34 @@ int power_init_board(void) return 0; }
+#ifdef CONFIG_LDO_BYPASS_CHECK +void ldo_mode_set(int ldo_bypass) +{ + unsigned int value; + struct pmic *p = pfuze; + + if (!p) + return; + + /* increase VDDARM/VDDSOC to support 1.2G chip */ + if (check_1_2G()) { + ldo_bypass = 0; /* ldo_enable on 1.2G chip */ + printf("1.2G chip, increase VDDARM_IN/VDDSOC_IN\n"); + /* increase VDDARM to 1.425V */ + pmic_reg_read(p, PFUZE100_SW1ABVOL, &value); + value &= ~0x3f; + value |= PFUZE100_SW1ABC_SETP(14250); + pmic_reg_write(p, PFUZE100_SW1ABVOL, value); + + /* increase VDDSOC to 1.425V */ + pmic_reg_read(p, PFUZE100_SW1CVOL, &value); + value &= ~0x3f; + value |= PFUZE100_SW1ABC_SETP(14250); + pmic_reg_write(p, PFUZE100_SW1CVOL, value); + } +} +#endif + #ifdef CONFIG_CMD_BMODE static const struct boot_mode board_boot_modes[] = { /* 4 bit bus width */ diff --git a/include/configs/mx6qsabreauto.h b/include/configs/mx6qsabreauto.h index 51042ca..5b4fb65 100644 --- a/include/configs/mx6qsabreauto.h +++ b/include/configs/mx6qsabreauto.h @@ -80,4 +80,6 @@ #define CONFIG_POWER_PFUZE100 #define CONFIG_POWER_PFUZE100_I2C_ADDR 0x08
+#define CONFIG_LDO_BYPASS_CHECK + #endif /* __MX6QSABREAUTO_CONFIG_H */

Current i.MX6 U-Boot does not support device tree. We check ldo-bypass from dtb file which is loaded when running `run loadfdt`.
Future work is needed to integrate device tree in uboot. And move related function invoke in power_init_board.
Signed-off-by: Peng Fan Peng.Fan@freescale.com Signed-off-by: Robin Gong b38343@freescale.com --- arch/arm/imx-common/cpu.c | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/arch/arm/imx-common/cpu.c b/arch/arm/imx-common/cpu.c index 28ccd29..1e518f2 100644 --- a/arch/arm/imx-common/cpu.c +++ b/arch/arm/imx-common/cpu.c @@ -204,6 +204,10 @@ u32 get_ahb_clk(void)
void arch_preboot_os(void) { +#if defined(CONFIG_LDO_BYPASS_CHECK) + ldo_mode_set(check_ldo_bypass()); +#endif + #if defined(CONFIG_CMD_SATA) sata_stop(); #if defined(CONFIG_MX6)
participants (6)
-
Fabio Estevam
-
Peng Fan
-
Peng Fan
-
Robin Gong
-
Stefano Babic
-
Tim Harvey