[U-Boot] [PATCH v3 0/7] Add VID support for QDS and RDB platforms

Adds LTC3882 voltage regulator chip support in common VID driver. And adds VID support for LS1088A QDS and RDB platforms.
Rajesh Bhagat (7): armv8: lsch3: Add serdes and DDR voltage setup board: common:vid: Add LS1088A VID Supported voltage values board: common: vid: Add board specific vdd adjust API board: common: vid: Move IR chip specific code in flag Kconfig: Add LTC3882 voltage regulator config board: common: vid: Add support for LTC3882 voltage regulator chip ls1088a: Add VID support for QDS and RDB platforms
.../cpu/armv8/fsl-layerscape/fsl_lsch3_serdes.c | 274 +++++++++++++++++++++ arch/arm/cpu/armv8/fsl-layerscape/soc.c | 34 +-- .../include/asm/arch-fsl-layerscape/fsl_serdes.h | 2 +- .../include/asm/arch-fsl-layerscape/immap_lsch3.h | 43 +++- arch/arm/include/asm/arch-fsl-layerscape/soc.h | 1 + board/freescale/common/Kconfig | 16 ++ board/freescale/common/vid.c | 119 ++++++++- board/freescale/ls1088a/ls1088a.c | 119 +++++++++ include/configs/ls1088aqds.h | 29 +++ include/configs/ls1088ardb.h | 29 +++ 10 files changed, 645 insertions(+), 21 deletions(-)

Adds SERDES voltage and reset SERDES lanes API and makes enable/disable DDR controller support 0.9V API common.
Signed-off-by: Ashish Kumar Ashish.Kumar@nxp.com Signed-off-by: Rajesh Bhagat rajesh.bhagat@nxp.com --- Changes in v3: Restructured LS1088A VID support to use common VID driver Cosmetic review comments fixed Added __iomem for accessing registers
Changes in v2: Checkpatch errors fixed
.../cpu/armv8/fsl-layerscape/fsl_lsch3_serdes.c | 274 +++++++++++++++++++++ arch/arm/cpu/armv8/fsl-layerscape/soc.c | 34 +-- .../include/asm/arch-fsl-layerscape/fsl_serdes.h | 2 +- .../include/asm/arch-fsl-layerscape/immap_lsch3.h | 34 +++ arch/arm/include/asm/arch-fsl-layerscape/soc.h | 1 + 5 files changed, 327 insertions(+), 18 deletions(-)
diff --git a/arch/arm/cpu/armv8/fsl-layerscape/fsl_lsch3_serdes.c b/arch/arm/cpu/armv8/fsl-layerscape/fsl_lsch3_serdes.c index 179cac6..39f2cdf 100644 --- a/arch/arm/cpu/armv8/fsl-layerscape/fsl_lsch3_serdes.c +++ b/arch/arm/cpu/armv8/fsl-layerscape/fsl_lsch3_serdes.c @@ -158,6 +158,280 @@ void serdes_init(u32 sd, u32 sd_addr, u32 rcwsr, u32 sd_prctl_mask, serdes_prtcl_map[NONE] = 1; }
+__weak int get_serdes_volt(void) +{ + return -1; +} + +__weak int set_serdes_volt(int svdd) +{ + return -1; +} + +int setup_serdes_volt(u32 svdd) +{ + struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR); + struct ccsr_serdes __iomem *serdes1_base; + u32 cfg_rcwsrds1 = gur_in32(&gur->rcwsr[FSL_CHASSIS3_SRDS1_REGSR - 1]); +#ifdef CONFIG_SYS_FSL_SRDS_2 + struct ccsr_serdes __iomem *serdes2_base; + u32 cfg_rcwsrds2 = gur_in32(&gur->rcwsr[FSL_CHASSIS3_SRDS2_REGSR - 1]); +#endif + u32 cfg_tmp, reg = 0; + int svdd_cur, svdd_tar; + int ret = 1; + int i; + + /* Only support switch SVDD to 900mV */ + if (svdd != 900) + return -1; + + /* Scale up to the LTC resolution is 1/4096V */ + svdd = (svdd * 4096) / 1000; + + svdd_tar = svdd; + svdd_cur = get_serdes_volt(); + if (svdd_cur < 0) + return -EINVAL; + + debug("%s: current SVDD: %x; target SVDD: %x\n", + __func__, svdd_cur, svdd_tar); + if (svdd_cur == svdd_tar) + return 0; + + serdes1_base = (void *)CONFIG_SYS_FSL_LSCH3_SERDES_ADDR; +#ifdef CONFIG_SYS_FSL_SRDS_2 + serdes2_base = (void *)(CONFIG_SYS_FSL_LSCH3_SERDES_ADDR + 0x10000); +#endif + + /* Put the all enabled lanes in reset */ +#ifdef CONFIG_SYS_FSL_SRDS_1 + cfg_tmp = cfg_rcwsrds1 & FSL_CHASSIS3_SRDS1_PRTCL_MASK; + cfg_tmp >>= FSL_CHASSIS3_SRDS1_PRTCL_SHIFT; + + for (i = 0; i < 4 && cfg_tmp & (0xf << (3 - i)); i++) { + reg = in_le32(&serdes1_base->lane[i].gcr0); + reg &= 0xFF9FFFFF; + out_le32(&serdes1_base->lane[i].gcr0, reg); + } +#endif + +#ifdef CONFIG_SYS_FSL_SRDS_2 + cfg_tmp = cfg_rcwsrds2 & FSL_CHASSIS3_SRDS2_PRTCL_MASK; + cfg_tmp >>= FSL_CHASSIS3_SRDS2_PRTCL_SHIFT; + + for (i = 0; i < 4 && cfg_tmp & (0xf << (3 - i)); i++) { + reg = in_le32(&serdes2_base->lane[i].gcr0); + reg &= 0xFF9FFFFF; + out_le32(&serdes2_base->lane[i].gcr0, reg); + } +#endif + + /* Put the all enabled PLL in reset */ +#ifdef CONFIG_SYS_FSL_SRDS_1 + cfg_tmp = cfg_rcwsrds1 & 0x3; + for (i = 0; i < 2 && !(cfg_tmp & (0x1 << (1 - i))); i++) { + reg = in_le32(&serdes1_base->bank[i].rstctl); + reg &= 0xFFFFFFBF; + reg |= 0x10000000; + out_le32(&serdes1_base->bank[i].rstctl, reg); + } + udelay(1); + + reg = in_le32(&serdes1_base->bank[i].rstctl); + reg &= 0xFFFFFF1F; + out_le32(&serdes1_base->bank[i].rstctl, reg); +#endif + +#ifdef CONFIG_SYS_FSL_SRDS_2 + cfg_tmp = cfg_rcwsrds1 & 0xC; + cfg_tmp >>= 2; + for (i = 0; i < 2 && !(cfg_tmp & (0x1 << (1 - i))); i++) { + reg = in_le32(&serdes2_base->bank[i].rstctl); + reg &= 0xFFFFFFBF; + reg |= 0x10000000; + out_le32(&serdes2_base->bank[i].rstctl, reg); + } + udelay(1); + + reg = in_le32(&serdes2_base->bank[i].rstctl); + reg &= 0xFFFFFF1F; + out_le32(&serdes2_base->bank[i].rstctl, reg); +#endif + + /* Put the Rx/Tx calibration into reset */ +#ifdef CONFIG_SYS_FSL_SRDS_1 + reg = in_le32(&serdes1_base->srdstcalcr); + reg &= 0xF7FFFFFF; + out_le32(&serdes1_base->srdstcalcr, reg); + reg = in_le32(&serdes1_base->srdsrcalcr); + reg &= 0xF7FFFFFF; + out_le32(&serdes1_base->srdsrcalcr, reg); +#endif + +#ifdef CONFIG_SYS_FSL_SRDS_2 + reg = in_le32(&serdes2_base->srdstcalcr); + reg &= 0xF7FFFFFF; + out_le32(&serdes2_base->srdstcalcr, reg); + reg = in_le32(&serdes2_base->srdsrcalcr); + reg &= 0xF7FFFFFF; + out_le32(&serdes2_base->srdsrcalcr, reg); +#endif + + ret = set_serdes_volt(svdd); + if (ret < 0) { + printf("could not change SVDD\n"); + ret = -1; + } + + /* For each PLL that’s not disabled via RCW enable the SERDES */ +#ifdef CONFIG_SYS_FSL_SRDS_1 + cfg_tmp = cfg_rcwsrds1 & 0x3; + for (i = 0; i < 2 && !(cfg_tmp & (0x1 << (1 - i))); i++) { + reg = in_le32(&serdes1_base->bank[i].rstctl); + reg |= 0x00000020; + out_le32(&serdes1_base->bank[i].rstctl, reg); + udelay(1); + + reg = in_le32(&serdes1_base->bank[i].rstctl); + reg |= 0x00000080; + out_le32(&serdes1_base->bank[i].rstctl, reg); + udelay(1); + /* Take the Rx/Tx calibration out of reset */ + if (!(cfg_tmp == 0x3 && i == 1)) { + udelay(1); + reg = in_le32(&serdes1_base->srdstcalcr); + reg |= 0x08000000; + out_le32(&serdes1_base->srdstcalcr, reg); + reg = in_le32(&serdes1_base->srdsrcalcr); + reg |= 0x08000000; + out_le32(&serdes1_base->srdsrcalcr, reg); + } + udelay(1); + } +#endif +#ifdef CONFIG_SYS_FSL_SRDS_2 + cfg_tmp = cfg_rcwsrds1 & 0xC; + cfg_tmp >>= 2; + for (i = 0; i < 2 && !(cfg_tmp & (0x1 << (1 - i))); i++) { + reg = in_le32(&serdes2_base->bank[i].rstctl); + reg |= 0x00000020; + out_le32(&serdes2_base->bank[i].rstctl, reg); + udelay(1); + + reg = in_le32(&serdes2_base->bank[i].rstctl); + reg |= 0x00000080; + out_le32(&serdes2_base->bank[i].rstctl, reg); + udelay(1); + + /* Take the Rx/Tx calibration out of reset */ + if (!(cfg_tmp == 0x3 && i == 1)) { + udelay(1); + reg = in_le32(&serdes2_base->srdstcalcr); + reg |= 0x08000000; + out_le32(&serdes2_base->srdstcalcr, reg); + reg = in_le32(&serdes2_base->srdsrcalcr); + reg |= 0x08000000; + out_le32(&serdes2_base->srdsrcalcr, reg); + } + udelay(1); + } +#endif + + /* Wait for at atleast 625us, ensure the PLLs being reset are locked */ + udelay(800); + +#ifdef CONFIG_SYS_FSL_SRDS_1 + cfg_tmp = cfg_rcwsrds1 & 0x3; + for (i = 0; i < 2 && !(cfg_tmp & (0x1 << (1 - i))); i++) { + /* if the PLL is not locked, set RST_ERR */ + reg = in_le32(&serdes1_base->bank[i].pllcr0); + if (!((reg >> 23) & 0x1)) { + reg = in_le32(&serdes1_base->bank[i].rstctl); + reg |= 0x20000000; + out_le32(&serdes1_base->bank[i].rstctl, reg); + } else { + udelay(1); + reg = in_le32(&serdes1_base->bank[i].rstctl); + reg &= 0xFFFFFFEF; + reg |= 0x00000040; + out_le32(&serdes1_base->bank[i].rstctl, reg); + udelay(1); + } + } +#endif + +#ifdef CONFIG_SYS_FSL_SRDS_2 + cfg_tmp = cfg_rcwsrds1 & 0xC; + cfg_tmp >>= 2; + + for (i = 0; i < 2 && !(cfg_tmp & (0x1 << (1 - i))); i++) { + reg = in_le32(&serdes2_base->bank[i].pllcr0); + if (!((reg >> 23) & 0x1)) { + reg = in_le32(&serdes2_base->bank[i].rstctl); + reg |= 0x20000000; + out_le32(&serdes2_base->bank[i].rstctl, reg); + } else { + udelay(1); + reg = in_le32(&serdes2_base->bank[i].rstctl); + reg &= 0xFFFFFFEF; + reg |= 0x00000040; + out_le32(&serdes2_base->bank[i].rstctl, reg); + udelay(1); + } + } +#endif + /* Take the all enabled lanes out of reset */ +#ifdef CONFIG_SYS_FSL_SRDS_1 + cfg_tmp = cfg_rcwsrds1 & FSL_CHASSIS3_SRDS1_PRTCL_MASK; + cfg_tmp >>= FSL_CHASSIS3_SRDS1_PRTCL_SHIFT; + + for (i = 0; i < 4 && cfg_tmp & (0xf << (3 - i)); i++) { + reg = in_le32(&serdes1_base->lane[i].gcr0); + reg |= 0x00600000; + out_le32(&serdes1_base->lane[i].gcr0, reg); + } +#endif +#ifdef CONFIG_SYS_FSL_SRDS_2 + cfg_tmp = cfg_rcwsrds2 & FSL_CHASSIS3_SRDS2_PRTCL_MASK; + cfg_tmp >>= FSL_CHASSIS3_SRDS2_PRTCL_SHIFT; + + for (i = 0; i < 4 && cfg_tmp & (0xf << (3 - i)); i++) { + reg = in_le32(&serdes2_base->lane[i].gcr0); + reg |= 0x00600000; + out_le32(&serdes2_base->lane[i].gcr0, reg); + } +#endif + + /* For each PLL being reset, and achieved PLL lock set RST_DONE */ +#ifdef CONFIG_SYS_FSL_SRDS_1 + cfg_tmp = cfg_rcwsrds1 & 0x3; + for (i = 0; i < 2; i++) { + reg = in_le32(&serdes1_base->bank[i].pllcr0); + if (!(cfg_tmp & (0x1 << (1 - i))) && ((reg >> 23) & 0x1)) { + reg = in_le32(&serdes1_base->bank[i].rstctl); + reg |= 0x40000000; + out_le32(&serdes1_base->bank[i].rstctl, reg); + } + } +#endif +#ifdef CONFIG_SYS_FSL_SRDS_2 + cfg_tmp = cfg_rcwsrds1 & 0xC; + cfg_tmp >>= 2; + + for (i = 0; i < 2; i++) { + reg = in_le32(&serdes2_base->bank[i].pllcr0); + if (!(cfg_tmp & (0x1 << (1 - i))) && ((reg >> 23) & 0x1)) { + reg = in_le32(&serdes2_base->bank[i].rstctl); + reg |= 0x40000000; + out_le32(&serdes2_base->bank[i].rstctl, reg); + } + } +#endif + + return ret; +} + void fsl_serdes_init(void) { #if defined(CONFIG_FSL_MC_ENET) && !defined(CONFIG_SPL_BUILD) diff --git a/arch/arm/cpu/armv8/fsl-layerscape/soc.c b/arch/arm/cpu/armv8/fsl-layerscape/soc.c index 83e2871..4e96c7b 100644 --- a/arch/arm/cpu/armv8/fsl-layerscape/soc.c +++ b/arch/arm/cpu/armv8/fsl-layerscape/soc.c @@ -404,23 +404,6 @@ static int setup_core_volt(u32 vdd) return board_setup_core_volt(vdd); }
-#ifdef CONFIG_SYS_FSL_DDR -static void ddr_enable_0v9_volt(bool en) -{ - struct ccsr_ddr __iomem *ddr = (void *)CONFIG_SYS_FSL_DDR_ADDR; - u32 tmp; - - tmp = ddr_in32(&ddr->ddr_cdr1); - - if (en) - tmp |= DDR_CDR1_V0PT9_EN; - else - tmp &= ~DDR_CDR1_V0PT9_EN; - - ddr_out32(&ddr->ddr_cdr1, tmp); -} -#endif - int setup_chip_volt(void) { int vdd; @@ -485,6 +468,23 @@ void fsl_lsch2_early_init_f(void) } #endif
+#ifdef CONFIG_SYS_FSL_DDR +void ddr_enable_0v9_volt(bool en) +{ + struct ccsr_ddr __iomem *ddr = (void *)CONFIG_SYS_FSL_DDR_ADDR; + u32 tmp; + + tmp = ddr_in32(&ddr->ddr_cdr1); + + if (en) + tmp |= DDR_CDR1_V0PT9_EN; + else + tmp &= ~DDR_CDR1_V0PT9_EN; + + ddr_out32(&ddr->ddr_cdr1, tmp); +} +#endif + #ifdef CONFIG_QSPI_AHB_INIT /* Enable 4bytes address support and fast read */ int qspi_ahb_init(void) diff --git a/arch/arm/include/asm/arch-fsl-layerscape/fsl_serdes.h b/arch/arm/include/asm/arch-fsl-layerscape/fsl_serdes.h index 12fd6b8..9becdf3 100644 --- a/arch/arm/include/asm/arch-fsl-layerscape/fsl_serdes.h +++ b/arch/arm/include/asm/arch-fsl-layerscape/fsl_serdes.h @@ -164,6 +164,7 @@ void fsl_rgmii_init(void); #ifdef CONFIG_FSL_LSCH2 const char *serdes_clock_to_string(u32 clock); int get_serdes_protocol(void); +#endif #ifdef CONFIG_SYS_HAS_SERDES /* Get the volt of SVDD in unit mV */ int get_serdes_volt(void); @@ -172,6 +173,5 @@ int set_serdes_volt(int svdd); /* The target volt of SVDD in unit mV */ int setup_serdes_volt(u32 svdd); #endif -#endif
#endif /* __FSL_SERDES_H__ */ diff --git a/arch/arm/include/asm/arch-fsl-layerscape/immap_lsch3.h b/arch/arm/include/asm/arch-fsl-layerscape/immap_lsch3.h index ffc5fa2..2706ea8 100644 --- a/arch/arm/include/asm/arch-fsl-layerscape/immap_lsch3.h +++ b/arch/arm/include/asm/arch-fsl-layerscape/immap_lsch3.h @@ -370,5 +370,39 @@ struct ccsr_reset { u32 ip_rev2; /* 0xbfc */ };
+struct ccsr_serdes { + struct { + u32 rstctl; /* Reset Control Register */ + u32 pllcr0; /* PLL Control Register 0 */ + u32 pllcr1; /* PLL Control Register 1 */ + u32 pllcr2; /* PLL Control Register 2 */ + u32 pllcr3; /* PLL Control Register 3 */ + u32 pllcr4; /* PLL Control Register 4 */ + u32 pllcr5; /* PLL Control Register 5 */ + u8 res[0x20 - 0x1c]; + } bank[2]; + u8 res1[0x90 - 0x40]; + u32 srdstcalcr; /* TX Calibration Control */ + u32 srdstcalcr1; /* TX Calibration Control1 */ + u8 res2[0xa0 - 0x98]; + u32 srdsrcalcr; /* RX Calibration Control */ + u32 srdsrcalcr1; /* RX Calibration Control1 */ + u8 res3[0xb0 - 0xa8]; + u32 srdsgr0; /* General Register 0 */ + u8 res4[0x800 - 0xb4]; + struct serdes_lane { + u32 gcr0; /* General Control Register 0 */ + u32 gcr1; /* General Control Register 1 */ + u32 gcr2; /* General Control Register 2 */ + u32 ssc0; /* Speed Switch Control 0 */ + u32 rec0; /* Receive Equalization Control 0 */ + u32 rec1; /* Receive Equalization Control 1 */ + u32 tec0; /* Transmit Equalization Control 0 */ + u32 ssc1; /* Speed Switch Control 1 */ + u8 res1[0x840 - 0x820]; + } lane[8]; + u8 res5[0x19fc - 0xa00]; +}; + #endif /*__ASSEMBLY__*/ #endif /* __ARCH_FSL_LSCH3_IMMAP_H_ */ diff --git a/arch/arm/include/asm/arch-fsl-layerscape/soc.h b/arch/arm/include/asm/arch-fsl-layerscape/soc.h index ea8aced..697f072 100644 --- a/arch/arm/include/asm/arch-fsl-layerscape/soc.h +++ b/arch/arm/include/asm/arch-fsl-layerscape/soc.h @@ -121,6 +121,7 @@ int setup_chip_volt(void); /* Setup core vdd in unit mV */ int board_setup_core_volt(u32 vdd); #endif +void ddr_enable_0v9_volt(bool en);
void cpu_name(char *name); #ifdef CONFIG_SYS_FSL_ERRATUM_A009635

Adds below voltage values supported by LS1088A Soc:
1.025 V(default), 0.9875V, 0.9750 V, 0.9V, 1.0 V, 1.0125 V, 1.0250 V
Signed-off-by: Ashish Kumar Ashish.Kumar@nxp.com Signed-off-by: Rajesh Bhagat rajesh.bhagat@nxp.com --- board/freescale/common/vid.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+)
diff --git a/board/freescale/common/vid.c b/board/freescale/common/vid.c index d6d1bfc..f4fc95b 100644 --- a/board/freescale/common/vid.c +++ b/board/freescale/common/vid.c @@ -296,15 +296,28 @@ int adjust_vdd(ulong vdd_override) unsigned long vdd_string_override; char *vdd_string; static const uint16_t vdd[32] = { +#ifdef CONFIG_ARCH_LS1088A + 10250, + 9875, +#else 10500, 0, /* reserved */ +#endif 9750, 0, /* reserved */ +#ifdef CONFIG_ARCH_LS1088A + 0, /* reserved */ +#else 9500, +#endif 0, /* reserved */ 0, /* reserved */ 0, /* reserved */ +#ifdef CONFIG_ARCH_LS1088A + 9000, +#else 0, /* reserved */ +#endif 0, /* reserved */ 0, /* reserved */ 0, /* reserved */ @@ -313,10 +326,18 @@ int adjust_vdd(ulong vdd_override) 0, /* reserved */ 0, /* reserved */ 10000, /* 1.0000V */ +#ifdef CONFIG_ARCH_LS1088A + 10125, +#else 0, /* reserved */ +#endif 10250, 0, /* reserved */ +#ifdef CONFIG_ARCH_LS1088A + 0, /* reserved */ +#else 10500, +#endif 0, /* reserved */ 0, /* reserved */ 0, /* reserved */

Adds a board specific API namely board_adjust_vdd which is required to define the board VDD adjust settings.
Signed-off-by: Ashish Kumar Ashish.Kumar@nxp.com Signed-off-by: Rajesh Bhagat rajesh.bhagat@nxp.com --- board/freescale/common/vid.c | 13 +++++++++++++ 1 file changed, 13 insertions(+)
diff --git a/board/freescale/common/vid.c b/board/freescale/common/vid.c index f4fc95b..921841f 100644 --- a/board/freescale/common/vid.c +++ b/board/freescale/common/vid.c @@ -34,6 +34,14 @@ int __weak board_vdd_drop_compensation(void) }
/* + * Board specific settings for specific voltage value + */ +int __weak board_adjust_vdd(int vdd) +{ + return 0; +} + +/* * Get the i2c address configuration for the IR regulator chip * * There are some variance in the RDB HW regarding the I2C address configuration @@ -453,6 +461,11 @@ int adjust_vdd(ulong vdd_override) vdd_last = set_voltage(i2caddress, vdd_current); }
+ if (board_adjust_vdd(vdd_target) < 0) { + ret = -1; + goto exit; + } + if (vdd_last > 0) printf("VID: Core voltage after adjustment is at %d mV\n", vdd_last);

Moves IR chip (IR36021) specific code in flag to resolve compilation issue where it is not present. For example, LS1088A is having a new LTC3882 voltage chip.
Signed-off-by: Ashish Kumar Ashish.Kumar@nxp.com Signed-off-by: Rajesh Bhagat rajesh.bhagat@nxp.com --- board/freescale/common/vid.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/board/freescale/common/vid.c b/board/freescale/common/vid.c index 921841f..cdf877d 100644 --- a/board/freescale/common/vid.c +++ b/board/freescale/common/vid.c @@ -184,6 +184,7 @@ static int read_voltage(int i2caddress) return voltage_read; }
+#ifdef CONFIG_VOL_MONITOR_IR36021_SET /* * We need to calculate how long before the voltage stops to drop * or increase. It returns with the loop count. Each loop takes @@ -243,7 +244,6 @@ static int wait_for_voltage_stable(int i2caddress) return vdd_current; }
-#ifdef CONFIG_VOL_MONITOR_IR36021_SET /* Set the voltage to the IR chip */ static int set_voltage_to_IR(int i2caddress, int vdd) { @@ -298,7 +298,12 @@ int adjust_vdd(ulong vdd_override) int re_enable = disable_interrupts(); struct ccsr_gur *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR); u32 fusesr; +#if defined(CONFIG_VOL_MONITOR_IR36021_SET) || \ + defined(CONFIG_VOL_MONITOR_IR36021_READ) u8 vid, buf; +#else + u8 vid; +#endif int vdd_target, vdd_current, vdd_last; int ret, i2caddress; unsigned long vdd_string_override; @@ -369,6 +374,8 @@ int adjust_vdd(ulong vdd_override) ret = -1; goto exit; } +#if defined(CONFIG_VOL_MONITOR_IR36021_SET) || \ + defined(CONFIG_VOL_MONITOR_IR36021_READ) ret = find_ir_chip_on_i2c(); if (ret < 0) { printf("VID: Could not find voltage regulator on I2C.\n"); @@ -393,6 +400,7 @@ int adjust_vdd(ulong vdd_override) ret = -1; goto exit; } +#endif
/* get the voltage ID from fuse status register */ fusesr = in_le32(&gur->dcfg_fusesr);

Adds below LTC3882 voltage regulator config: CONFIG_VOL_MONITOR_LTC3882_READ CONFIG_VOL_MONITOR_LTC3882_SET
Signed-off-by: Ashish Kumar Ashish.Kumar@nxp.com Signed-off-by: Rajesh Bhagat rajesh.bhagat@nxp.com --- board/freescale/common/Kconfig | 16 ++++++++++++++++ 1 file changed, 16 insertions(+)
diff --git a/board/freescale/common/Kconfig b/board/freescale/common/Kconfig index 8a5c456..3f44797 100644 --- a/board/freescale/common/Kconfig +++ b/board/freescale/common/Kconfig @@ -18,3 +18,19 @@ config CMD_ESBC_VALIDATE
esbc_validate - validate signature using RSA verification esbc_halt - put the core in spin loop (Secure Boot Only) + +config VOL_MONITOR_LTC3882_READ + depends on VID + bool "Enable the LTC3882 voltage monitor read" + default n + help + This option enables LTC3882 voltage monitor read + functionality. It is used by common VID driver. + +config VOL_MONITOR_LTC3882_SET + depends on VID + bool "Enable the LTC3882 voltage monitor set" + default n + help + This option enables LTC3882 voltage monitor set + functionality. It is used by common VID driver.

Restructures common driver to support LTC3882 voltage regulator chip.
Signed-off-by: Ashish Kumar Ashish.Kumar@nxp.com Signed-off-by: Rajesh Bhagat rajesh.bhagat@nxp.com --- Changes in v3: Restructured LS1088A VID support to use common VID driver Added the coding for voltage in comments i.e. 1/4096V Removed APIs getLSB/MSB and used bit operations.
Changes in v2: Checkpatch errors fixed
.../include/asm/arch-fsl-layerscape/immap_lsch3.h | 9 ++- board/freescale/common/vid.c | 75 ++++++++++++++++++++++ include/configs/ls1088aqds.h | 16 +++++ include/configs/ls1088ardb.h | 15 +++++ 4 files changed, 113 insertions(+), 2 deletions(-)
diff --git a/arch/arm/include/asm/arch-fsl-layerscape/immap_lsch3.h b/arch/arm/include/asm/arch-fsl-layerscape/immap_lsch3.h index 2706ea8..1394b75 100644 --- a/arch/arm/include/asm/arch-fsl-layerscape/immap_lsch3.h +++ b/arch/arm/include/asm/arch-fsl-layerscape/immap_lsch3.h @@ -184,10 +184,15 @@ struct ccsr_gur { u32 gpporcr3; u32 gpporcr4; u8 res_030[0x60-0x30]; -#define FSL_CHASSIS3_DCFG_FUSESR_VID_SHIFT 2 #define FSL_CHASSIS3_DCFG_FUSESR_VID_MASK 0x1F -#define FSL_CHASSIS3_DCFG_FUSESR_ALTVID_SHIFT 7 #define FSL_CHASSIS3_DCFG_FUSESR_ALTVID_MASK 0x1F +#if defined(CONFIG_ARCH_LS1088A) +#define FSL_CHASSIS3_DCFG_FUSESR_VID_SHIFT 25 +#define FSL_CHASSIS3_DCFG_FUSESR_ALTVID_SHIFT 20 +#else +#define FSL_CHASSIS3_DCFG_FUSESR_VID_SHIFT 2 +#define FSL_CHASSIS3_DCFG_FUSESR_ALTVID_SHIFT 7 +#endif u32 dcfg_fusesr; /* Fuse status register */ u8 res_064[0x70-0x64]; u32 devdisr; /* Device disable control 1 */ diff --git a/board/freescale/common/vid.c b/board/freescale/common/vid.c index cdf877d..197e08e 100644 --- a/board/freescale/common/vid.c +++ b/board/freescale/common/vid.c @@ -171,6 +171,35 @@ static int read_voltage_from_IR(int i2caddress) } #endif
+#ifdef CONFIG_VOL_MONITOR_LTC3882_READ +/* read the current value of the LTC Regulator Voltage */ +static int read_voltage_from_LTC(int i2caddress) +{ + int ret, vcode = 0; + + /* select the PAGE 0 using PMBus commands PAGE for VDD*/ + ret = i2c_write(I2C_VOL_MONITOR_ADDR, + PMBUS_CMD_PAGE, 1, PWM_CHANNEL0, 1); + if (ret) { + printf("VID: failed to select VDD Page 0\n"); + return ret; + } + + /*read the output voltage using PMBus command READ_VOUT*/ + ret = i2c_read(I2C_VOL_MONITOR_ADDR, + PMBUS_CMD_READ_VOUT, 1, (void *)&vcode, 2); + if (ret) { + printf("VID: failed to read the volatge\n"); + return ret; + } + + /* Scale down to the real mV as LTC resolution is 1/4096V,rounding up */ + vcode = DIV_ROUND_UP(vcode * 1000, 4096); + + return vcode; +} +#endif + static int read_voltage(int i2caddress) { int voltage_read; @@ -178,6 +207,8 @@ static int read_voltage(int i2caddress) voltage_read = read_voltage_from_INA220(i2caddress); #elif defined CONFIG_VOL_MONITOR_IR36021_READ voltage_read = read_voltage_from_IR(i2caddress); +#elif defined CONFIG_VOL_MONITOR_LTC3882_READ + voltage_read = read_voltage_from_LTC(i2caddress); #else return -1; #endif @@ -278,6 +309,42 @@ static int set_voltage_to_IR(int i2caddress, int vdd) debug("VID: Current voltage is %d mV\n", vdd_last); return vdd_last; } + +#endif + +#ifdef CONFIG_VOL_MONITOR_LTC3882_SET +/* this function sets the VDD and returns the value set */ +static int set_voltage_to_LTC(int i2caddress, int vdd) +{ + int ret, vdd_last, vdd_target = vdd; + + /* Scale up to the LTC resolution is 1/4096V */ + vdd = (vdd * 4096) / 1000; + + /* 5-byte buffer which needs to be sent following the + * PMBus command PAGE_PLUS_WRITE. + */ + u8 buff[5] = {0x04, PWM_CHANNEL0, PMBUS_CMD_VOUT_COMMAND, + vdd & 0xFF, (vdd & 0xFF00) >> 8}; + + /* Write the desired voltage code to the regulator */ + ret = i2c_write(I2C_VOL_MONITOR_ADDR, + PMBUS_CMD_PAGE_PLUS_WRITE, 1, (void *)&buff, 5); + if (ret) { + printf("VID: I2C failed to write to the volatge regulator\n"); + return -1; + } + + /* Wait for the volatge to get to the desired value */ + do { + vdd_last = read_voltage_from_LTC(i2caddress); + if (vdd_last < 0) { + printf("VID: Couldn't read sensor abort VID adjust\n"); + return -1; + } + } while (vdd_last != vdd_target); + return vdd_last; +} #endif
static int set_voltage(int i2caddress, int vdd) @@ -286,6 +353,8 @@ static int set_voltage(int i2caddress, int vdd)
#ifdef CONFIG_VOL_MONITOR_IR36021_SET vdd_last = set_voltage_to_IR(i2caddress, vdd); +#elif defined CONFIG_VOL_MONITOR_LTC3882_SET + vdd_last = set_voltage_to_LTC(i2caddress, vdd); #else #error Specific voltage monitor must be defined #endif @@ -452,6 +521,11 @@ int adjust_vdd(ulong vdd_override) } vdd_current = vdd_last; debug("VID: Core voltage is currently at %d mV\n", vdd_last); + +#ifdef CONFIG_VOL_MONITOR_LTC3882_SET + /* Set the target voltage */ + vdd_last = vdd_current = set_voltage(i2caddress, vdd_target); +#else /* * Adjust voltage to at or one step above target. * As measurements are less precise than setting the values @@ -469,6 +543,7 @@ int adjust_vdd(ulong vdd_override) vdd_last = set_voltage(i2caddress, vdd_current); }
+#endif if (board_adjust_vdd(vdd_target) < 0) { ret = -1; goto exit; diff --git a/include/configs/ls1088aqds.h b/include/configs/ls1088aqds.h index 3547b0b..8ae98e1 100644 --- a/include/configs/ls1088aqds.h +++ b/include/configs/ls1088aqds.h @@ -277,6 +277,22 @@ unsigned long get_board_ddr_clk(void); #define I2C_MUX_CH_DEFAULT 0x8 #define I2C_MUX_CH5 0xD
+#define I2C_MUX_CH_VOL_MONITOR 0xA + +/* Voltage monitor on channel 2*/ +#define I2C_VOL_MONITOR_ADDR 0x63 +#define I2C_VOL_MONITOR_BUS_V_OFFSET 0x2 +#define I2C_VOL_MONITOR_BUS_V_OVF 0x1 +#define I2C_VOL_MONITOR_BUS_V_SHIFT 3 + +/* PM Bus commands code for LTC3882*/ +#define PMBUS_CMD_PAGE 0x0 +#define PMBUS_CMD_READ_VOUT 0x8B +#define PMBUS_CMD_PAGE_PLUS_WRITE 0x05 +#define PMBUS_CMD_VOUT_COMMAND 0x21 + +#define PWM_CHANNEL0 0x0 + /* * RTC configuration */ diff --git a/include/configs/ls1088ardb.h b/include/configs/ls1088ardb.h index d943fa4..86fa033 100644 --- a/include/configs/ls1088ardb.h +++ b/include/configs/ls1088ardb.h @@ -210,6 +210,21 @@
#define CONFIG_SYS_LS_MC_BOOT_TIMEOUT_MS 5000
+#define I2C_MUX_CH_VOL_MONITOR 0xA +/* Voltage monitor on channel 2*/ +#define I2C_VOL_MONITOR_ADDR 0x63 +#define I2C_VOL_MONITOR_BUS_V_OFFSET 0x2 +#define I2C_VOL_MONITOR_BUS_V_OVF 0x1 +#define I2C_VOL_MONITOR_BUS_V_SHIFT 3 + +/* PM Bus commands code for LTC3882*/ +#define PMBUS_CMD_PAGE 0x0 +#define PMBUS_CMD_READ_VOUT 0x8B +#define PMBUS_CMD_PAGE_PLUS_WRITE 0x05 +#define PMBUS_CMD_VOUT_COMMAND 0x21 + +#define PWM_CHANNEL0 0x0 + /* * I2C bus multiplexer */

This patch adds the support for VID on LS1088AQDS and LS1088ARDB systems. It reads the fusesr register and changes the VDD accordingly by adjusting the voltage via LTC3882 regulator.
This patch also takes care of the special case of 0.9V VDD is present in fusesr register. In that case,it also changes the SERDES voltage by disabling the SERDES, changing the SVDD and then re-enabling SERDES.
Signed-off-by: Raghav Dogra raghav.dogra@nxp.com Signed-off-by: Ashish Kumar Ashish.Kumar@nxp.com Signed-off-by: Amrita Kumari amrita.kumari@nxp.com Signed-off-by: Rajesh Bhagat rajesh.bhagat@nxp.com --- Changes in v3: Restructured LS1088A VID support to use common VID driver Removed APIs getLSB/MSB and used bit operations.
Changes in v2: Checkpatch errors fixed
board/freescale/ls1088a/ls1088a.c | 119 ++++++++++++++++++++++++++++++++++++++ include/configs/ls1088aqds.h | 13 +++++ include/configs/ls1088ardb.h | 14 +++++ 3 files changed, 146 insertions(+)
diff --git a/board/freescale/ls1088a/ls1088a.c b/board/freescale/ls1088a/ls1088a.c index d1de4d1..2c65ed3 100644 --- a/board/freescale/ls1088a/ls1088a.c +++ b/board/freescale/ls1088a/ls1088a.c @@ -18,9 +18,13 @@ #include <environment.h> #include <asm/arch-fsl-layerscape/soc.h> #include <asm/arch/ppa.h> +#include <asm/arch/fsl_serdes.h> +#include <asm/arch/soc.h>
#include "../common/qixis.h" #include "ls1088a_qixis.h" +#include "../common/vid.h" +#include <fsl_immap.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -295,6 +299,119 @@ void board_retimer_init(void) /*return the default channel*/ select_i2c_ch_pca9547(I2C_MUX_CH_DEFAULT); } +int i2c_multiplexer_select_vid_channel(u8 channel) +{ + return select_i2c_ch_pca9547(channel); +} + +#ifdef CONFIG_TARGET_LS1088AQDS +/* read the current value(SVDD) of the LTM Regulator Voltage */ +int get_serdes_volt(void) +{ + int ret, vcode = 0; + + /* Select the PAGE 0 using PMBus commands PAGE for VDD */ + ret = i2c_write(I2C_SVDD_MONITOR_ADDR, + PMBUS_CMD_PAGE, 1, PWM_CHANNEL0, 1); + if (ret) { + printf("VID: failed to select VDD Page 0\n"); + return ret; + } + + /* Read the output voltage using PMBus command READ_VOUT */ + ret = i2c_read(I2C_SVDD_MONITOR_ADDR, + PMBUS_CMD_READ_VOUT, 1, (void *)&vcode, 2); + if (ret) { + printf("VID: failed to read the volatge\n"); + return ret; + } + return vcode; +} + +int set_serdes_volt(int svdd) +{ + int ret, vdd_last; + u8 buff[5] = {0x04, PWM_CHANNEL0, PMBUS_CMD_VOUT_COMMAND, + svdd & 0xFF, (svdd & 0xFF00) >> 8}; + + /* Write the desired voltage code to the SVDD regulator */ + ret = i2c_write(I2C_SVDD_MONITOR_ADDR, + PMBUS_CMD_PAGE_PLUS_WRITE, 1, (void *)&buff, 5); + if (ret) { + printf("VID: I2C failed to write to the volatge regulator\n"); + return -1; + } + + /* Wait for the volatge to get to the desired value */ + do { + vdd_last = get_serdes_volt(); + if (vdd_last < 0) { + printf("VID: Couldn't read sensor abort VID adjust\n"); + return -1; + } + } while (vdd_last != svdd); + + return 1; +} +#else +int get_serdes_volt(void) +{ + return 0; +} + +int set_serdes_volt(int svdd) +{ + int ret; + u8 brdcfg4; + + printf("SVDD changing of RDB\n"); + + /* Read the BRDCFG54 via CLPD */ + ret = i2c_read(CONFIG_SYS_I2C_FPGA_ADDR, + QIXIS_BRDCFG4_OFFSET, 1, (void *)&brdcfg4, 1); + if (ret) { + printf("VID: I2C failed to read the CPLD BRDCFG4\n"); + return -1; + } + + brdcfg4 = brdcfg4 | 0x08; + + /* Write to the BRDCFG4 */ + ret = i2c_write(CONFIG_SYS_I2C_FPGA_ADDR, + QIXIS_BRDCFG4_OFFSET, 1, (void *)&brdcfg4, 1); + if (ret) { + debug("VID: I2C failed to set the SVDD CPLD BRDCFG4\n"); + return -1; + } + + /* Wait for the volatge to get to the desired value */ + udelay(10000); + + return 1; +} +#endif + +/* this function disables the SERDES, changes the SVDD Voltage and enables it*/ +int board_adjust_vdd(int vdd) +{ + int ret = 0; + + debug("%s: vdd = %d\n", __func__, vdd); + + /* Special settings to be performed when voltage is 900mV */ + if (vdd == 900) { +#ifdef CONFIG_SYS_FSL_DDR + ddr_enable_0v9_volt(true); +#endif + ret = setup_serdes_volt(vdd); + if (ret < 0) { + ret = -1; + goto exit; + } + } +exit: + return ret; +}
int board_init(void) { @@ -314,6 +431,8 @@ int board_init(void) /* invert AQR105 IRQ pins polarity */ out_le32(irq_ccsr + IRQCR_OFFSET / 4, AQR105_IRQ_MASK); #endif + if (adjust_vdd(0) < 0) + printf("core voltage not adjusted\n");
#ifdef CONFIG_FSL_LS_PPA ppa_init(); diff --git a/include/configs/ls1088aqds.h b/include/configs/ls1088aqds.h index 8ae98e1..a1135ed 100644 --- a/include/configs/ls1088aqds.h +++ b/include/configs/ls1088aqds.h @@ -284,6 +284,19 @@ unsigned long get_board_ddr_clk(void); #define I2C_VOL_MONITOR_BUS_V_OFFSET 0x2 #define I2C_VOL_MONITOR_BUS_V_OVF 0x1 #define I2C_VOL_MONITOR_BUS_V_SHIFT 3 +#define I2C_SVDD_MONITOR_ADDR 0x4F + +#define CONFIG_VID_FLS_ENV "ls1088aqds_vdd_mv" +#ifndef CONFIG_SPL_BUILD +#define CONFIG_VID +#endif + +/* The lowest and highest voltage allowed for LS1088AQDS */ +#define VDD_MV_MIN 819 +#define VDD_MV_MAX 1212 + +#define CONFIG_VOL_MONITOR_LTC3882_SET +#define CONFIG_VOL_MONITOR_LTC3882_READ
/* PM Bus commands code for LTC3882*/ #define PMBUS_CMD_PAGE 0x0 diff --git a/include/configs/ls1088ardb.h b/include/configs/ls1088ardb.h index 86fa033..615753b 100644 --- a/include/configs/ls1088ardb.h +++ b/include/configs/ls1088ardb.h @@ -136,6 +136,7 @@
#define CONFIG_FSL_QIXIS #define CONFIG_SYS_I2C_FPGA_ADDR 0x66 +#define QIXIS_BRDCFG4_OFFSET 0x54 #define QIXIS_LBMAP_SWITCH 2 #define QIXIS_QMAP_MASK 0xe0 #define QIXIS_QMAP_SHIFT 5 @@ -216,6 +217,19 @@ #define I2C_VOL_MONITOR_BUS_V_OFFSET 0x2 #define I2C_VOL_MONITOR_BUS_V_OVF 0x1 #define I2C_VOL_MONITOR_BUS_V_SHIFT 3 +#define I2C_SVDD_MONITOR_ADDR 0x4F + +#define CONFIG_VID_FLS_ENV "ls1088ardb_vdd_mv" +#ifndef CONFIG_SPL_BUILD +#define CONFIG_VID +#endif + +/* The lowest and highest voltage allowed for LS1088ARDB */ +#define VDD_MV_MIN 819 +#define VDD_MV_MAX 1212 + +#define CONFIG_VOL_MONITOR_LTC3882_SET +#define CONFIG_VOL_MONITOR_LTC3882_READ
/* PM Bus commands code for LTC3882*/ #define PMBUS_CMD_PAGE 0x0
participants (1)
-
Rajesh Bhagat