[U-Boot] [PATCH v6 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 | 312 +++++++++++++++++++++ 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 | 129 ++++++++- board/freescale/ls1088a/ls1088a.c | 120 ++++++++ include/configs/ls1088aqds.h | 29 ++ include/configs/ls1088ardb.h | 29 ++ 10 files changed, 694 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 v6: - Corrected indentation/alignment issues at various places - Changed NULL ENTRY in srds_prctl_info array to id as zero - Corrected the PLL Reset logic, moved code inside for loop - Used error code(-EINVAL) in setup_serdes_volt API
Changes in v5: - Moved local macros to static functions - Used array to handle PRCTL mask and shift operations
Changes in v4: - Added local macros instead of magical numbers - Created macros to remove duplicate code
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 | 312 +++++++++++++++++++++ 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, 365 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..3e4b0bc 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,318 @@ 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; +} + +#define LNAGCR0_RESET_MASK 0xFF9FFFFF +#define LNAGCR0_RT_RSTB 0x00600000 +#define RSTCTL_RESET_MASK_1 0xFFFFFFBF +#define RSTCTL_RESET_MASK_2 0xFFFFFF1F +#define RSTCTL_RESET_MASK_3 0xFFFFFFEF +#define RSTCTL_RSTREQ 0x10000000 +#define RSTCTL_RSTERR 0x20000000 +#define RSTCTL_SDEN 0x00000020 +#define RSTCTL_SDRST_B 0x00000040 +#define RSTCTL_PLLRST_B 0x00000080 +#define RSTCTL_RST_DONE 0x40000000 +#define TCALCR_RESET_MASK 0xF7FFFFFF +#define TCALCR_CALRST_B 0x08000000 + +struct serdes_prctl_info { + u32 id; + u32 mask; + u32 shift; +}; + +struct serdes_prctl_info srds_prctl_info[] = { +#ifdef CONFIG_SYS_FSL_SRDS_1 + {.id = 1, + .mask = FSL_CHASSIS3_SRDS1_PRTCL_MASK, + .shift = FSL_CHASSIS3_SRDS1_PRTCL_SHIFT + }, + +#endif +#ifdef CONFIG_SYS_FSL_SRDS_2 + {.id = 2, + .mask = FSL_CHASSIS3_SRDS2_PRTCL_MASK, + .shift = FSL_CHASSIS3_SRDS2_PRTCL_SHIFT + }, +#endif + {.id = 0, + .mask = 0, + .shift = 0 + } /* NULL ENTRY */ +}; + +static int get_serdes_prctl_info_idx(u32 serdes_id) +{ + int pos = 0; + struct serdes_prctl_info *srds_info; + + /* loop until NULL ENTRY defined by .id=0 */ + for (srds_info = srds_prctl_info; srds_info->id != 0; + srds_info++, pos++) { + if (srds_info->id == serdes_id) + return pos; + } + + return -1; +} + +static void do_enabled_lanes_reset(u32 serdes_id, u32 cfg, + struct ccsr_serdes __iomem *serdes_base, + bool cmplt) +{ + int i, pos; + u32 cfg_tmp, reg = 0; + + pos = get_serdes_prctl_info_idx(serdes_id); + if (pos == -1) { + printf("invalid serdes_id %d\n", serdes_id); + return; + } + + cfg_tmp = cfg & srds_prctl_info[pos].mask; + cfg_tmp >>= srds_prctl_info[pos].shift; + + for (i = 0; i < 4 && cfg_tmp & (0xf << (3 - i)); i++) { + reg = in_le32(&serdes_base->lane[i].gcr0); + reg = (cmplt ? reg | LNAGCR0_RT_RSTB : + reg & LNAGCR0_RESET_MASK); + out_le32(&serdes_base->lane[i].gcr0, reg); + } +} + +static void do_pll_reset(u32 cfg, + struct ccsr_serdes __iomem *serdes_base) +{ + int i; + u32 reg = 0; + + for (i = 0; i < 2 && !(cfg & (0x1 << (1 - i))); i++) { + reg = in_le32(&serdes_base->bank[i].rstctl); + reg &= RSTCTL_RESET_MASK_1; + reg |= RSTCTL_RSTREQ; + out_le32(&serdes_base->bank[i].rstctl, reg); + udelay(1); + + reg = in_le32(&serdes_base->bank[i].rstctl); + reg &= RSTCTL_RESET_MASK_2; + out_le32(&serdes_base->bank[i].rstctl, reg); + } + udelay(1); +} + +static void do_rx_tx_cal_reset(struct ccsr_serdes __iomem *serdes_base) +{ + u32 reg = 0; + + reg = in_le32(&serdes_base->srdstcalcr); + reg &= TCALCR_RESET_MASK; + out_le32(&serdes_base->srdstcalcr, reg); + reg = in_le32(&serdes_base->srdsrcalcr); + reg &= TCALCR_RESET_MASK; + out_le32(&serdes_base->srdsrcalcr, reg); +} + +static void do_rx_tx_cal_reset_comp(u32 cfg, int i, + struct ccsr_serdes __iomem *serdes_base) +{ + u32 reg = 0; + + if (!(cfg == 0x3 && i == 1)) { + udelay(1); + reg = in_le32(&serdes_base->srdstcalcr); + reg |= TCALCR_CALRST_B; + out_le32(&serdes_base->srdstcalcr, reg); + reg = in_le32(&serdes_base->srdsrcalcr); + reg |= TCALCR_CALRST_B; + out_le32(&serdes_base->srdsrcalcr, reg); + } + udelay(1); +} + +static void do_pll_reset_done(u32 cfg, + struct ccsr_serdes __iomem *serdes_base) +{ + int i; + u32 reg = 0; + + for (i = 0; i < 2; i++) { + reg = in_le32(&serdes_base->bank[i].pllcr0); + if (!(cfg & (0x1 << (1 - i))) && ((reg >> 23) & 0x1)) { + reg = in_le32(&serdes_base->bank[i].rstctl); + reg |= RSTCTL_RST_DONE; + out_le32(&serdes_base->bank[i].rstctl, reg); + } + } +} + +static void do_serdes_enable(u32 cfg, + struct ccsr_serdes __iomem *serdes_base) +{ + int i; + u32 reg = 0; + + for (i = 0; i < 2 && !(cfg & (0x1 << (1 - i))); i++) { + reg = in_le32(&serdes_base->bank[i].rstctl); + reg |= RSTCTL_SDEN; + out_le32(&serdes_base->bank[i].rstctl, reg); + udelay(1); + + reg = in_le32(&serdes_base->bank[i].rstctl); + reg |= RSTCTL_PLLRST_B; + out_le32(&serdes_base->bank[i].rstctl, reg); + udelay(1); + /* Take the Rx/Tx calibration out of reset */ + do_rx_tx_cal_reset_comp(cfg, i, serdes_base); + } +} + +static void do_pll_lock(u32 cfg, + struct ccsr_serdes __iomem *serdes_base) +{ + int i; + u32 reg = 0; + + for (i = 0; i < 2 && !(cfg & (0x1 << (1 - i))); i++) { + /* if the PLL is not locked, set RST_ERR */ + reg = in_le32(&serdes_base->bank[i].pllcr0); + if (!((reg >> 23) & 0x1)) { + reg = in_le32(&serdes_base->bank[i].rstctl); + reg |= RSTCTL_RSTERR; + out_le32(&serdes_base->bank[i].rstctl, reg); + } else { + udelay(1); + reg = in_le32(&serdes_base->bank[i].rstctl); + reg &= RSTCTL_RESET_MASK_3; + reg |= RSTCTL_SDRST_B; + out_le32(&serdes_base->bank[i].rstctl, reg); + udelay(1); + } + } +} + +int setup_serdes_volt(u32 svdd) +{ + struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR); + struct ccsr_serdes __iomem *serdes1_base = + (void *)CONFIG_SYS_FSL_LSCH3_SERDES_ADDR; + u32 cfg_rcwsrds1 = gur_in32(&gur->rcwsr[FSL_CHASSIS3_SRDS1_REGSR - 1]); +#ifdef CONFIG_SYS_FSL_SRDS_2 + struct ccsr_serdes __iomem *serdes2_base = + (void *)(CONFIG_SYS_FSL_LSCH3_SERDES_ADDR + 0x10000); + u32 cfg_rcwsrds2 = gur_in32(&gur->rcwsr[FSL_CHASSIS3_SRDS2_REGSR - 1]); +#endif + u32 cfg_tmp; + int svdd_cur, svdd_tar; + int ret = 1; + + /* Only support switch SVDD to 900mV */ + if (svdd != 900) + return -EINVAL; + + /* 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; + + /* Put the all enabled lanes in reset */ +#ifdef CONFIG_SYS_FSL_SRDS_1 + do_enabled_lanes_reset(1, cfg_rcwsrds1, serdes1_base, false); +#endif + +#ifdef CONFIG_SYS_FSL_SRDS_2 + do_enabled_lanes_reset(2, cfg_rcwsrds2, serdes2_base, false); +#endif + + /* Put the all enabled PLL in reset */ +#ifdef CONFIG_SYS_FSL_SRDS_1 + cfg_tmp = cfg_rcwsrds1 & 0x3; + do_pll_reset(cfg_tmp, serdes1_base); +#endif + +#ifdef CONFIG_SYS_FSL_SRDS_2 + cfg_tmp = cfg_rcwsrds1 & 0xC; + cfg_tmp >>= 2; + do_pll_reset(cfg_tmp, serdes2_base); +#endif + + /* Put the Rx/Tx calibration into reset */ +#ifdef CONFIG_SYS_FSL_SRDS_1 + do_rx_tx_cal_reset(serdes1_base); +#endif + +#ifdef CONFIG_SYS_FSL_SRDS_2 + do_rx_tx_cal_reset(serdes2_base); +#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; + do_serdes_enable(cfg_tmp, serdes1_base); +#endif +#ifdef CONFIG_SYS_FSL_SRDS_2 + cfg_tmp = cfg_rcwsrds1 & 0xC; + cfg_tmp >>= 2; + do_serdes_enable(cfg_tmp, serdes2_base); +#endif + + /* Wait for at at least 625us, ensure the PLLs being reset are locked */ + udelay(800); + +#ifdef CONFIG_SYS_FSL_SRDS_1 + cfg_tmp = cfg_rcwsrds1 & 0x3; + do_pll_lock(cfg_tmp, serdes1_base); +#endif + +#ifdef CONFIG_SYS_FSL_SRDS_2 + cfg_tmp = cfg_rcwsrds1 & 0xC; + cfg_tmp >>= 2; + do_pll_lock(cfg_tmp, serdes2_base); +#endif + /* Take the all enabled lanes out of reset */ +#ifdef CONFIG_SYS_FSL_SRDS_1 + do_enabled_lanes_reset(1, cfg_rcwsrds1, serdes1_base, true); +#endif +#ifdef CONFIG_SYS_FSL_SRDS_2 + do_enabled_lanes_reset(2, cfg_rcwsrds2, serdes2_base, true); +#endif + + /* For each PLL being reset, and achieved PLL lock set RST_DONE */ +#ifdef CONFIG_SYS_FSL_SRDS_1 + cfg_tmp = cfg_rcwsrds1 & 0x3; + do_pll_reset_done(cfg_tmp, serdes1_base); +#endif +#ifdef CONFIG_SYS_FSL_SRDS_2 + cfg_tmp = cfg_rcwsrds1 & 0xC; + cfg_tmp >>= 2; + do_pll_reset_done(cfg_tmp, serdes2_base); +#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 497a4b5..47d89b2 100644 --- a/arch/arm/cpu/armv8/fsl-layerscape/soc.c +++ b/arch/arm/cpu/armv8/fsl-layerscape/soc.c @@ -513,23 +513,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; @@ -598,6 +581,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 957e23b..47e8b5a 100644 --- a/arch/arm/include/asm/arch-fsl-layerscape/immap_lsch3.h +++ b/arch/arm/include/asm/arch-fsl-layerscape/immap_lsch3.h @@ -387,5 +387,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 247f09e..8c242c0 100644 --- a/arch/arm/include/asm/arch-fsl-layerscape/soc.h +++ b/arch/arm/include/asm/arch-fsl-layerscape/soc.h @@ -125,6 +125,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

On 11/13/2017 11:06 PM, Rajesh Bhagat wrote:
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 v6:
- Corrected indentation/alignment issues at various places
- Changed NULL ENTRY in srds_prctl_info array to id as zero
- Corrected the PLL Reset logic, moved code inside for loop
- Used error code(-EINVAL) in setup_serdes_volt API
Changes in v5:
- Moved local macros to static functions
- Used array to handle PRCTL mask and shift operations
Changes in v4:
- Added local macros instead of magical numbers
- Created macros to remove duplicate code
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 | 312 +++++++++++++++++++++ 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, 365 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..3e4b0bc 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,318 @@ 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;
+}
+#define LNAGCR0_RESET_MASK 0xFF9FFFFF +#define LNAGCR0_RT_RSTB 0x00600000 +#define RSTCTL_RESET_MASK_1 0xFFFFFFBF +#define RSTCTL_RESET_MASK_2 0xFFFFFF1F +#define RSTCTL_RESET_MASK_3 0xFFFFFFEF +#define RSTCTL_RSTREQ 0x10000000 +#define RSTCTL_RSTERR 0x20000000 +#define RSTCTL_SDEN 0x00000020 +#define RSTCTL_SDRST_B 0x00000040 +#define RSTCTL_PLLRST_B 0x00000080 +#define RSTCTL_RST_DONE 0x40000000 +#define TCALCR_RESET_MASK 0xF7FFFFFF +#define TCALCR_CALRST_B 0x08000000
+struct serdes_prctl_info {
- u32 id;
- u32 mask;
- u32 shift;
+};
+struct serdes_prctl_info srds_prctl_info[] = { +#ifdef CONFIG_SYS_FSL_SRDS_1
- {.id = 1,
.mask = FSL_CHASSIS3_SRDS1_PRTCL_MASK,
.shift = FSL_CHASSIS3_SRDS1_PRTCL_SHIFT
- },
+#endif +#ifdef CONFIG_SYS_FSL_SRDS_2
- {.id = 2,
.mask = FSL_CHASSIS3_SRDS2_PRTCL_MASK,
.shift = FSL_CHASSIS3_SRDS2_PRTCL_SHIFT
- },
+#endif
- {.id = 0,
.mask = 0,
.shift = 0
- } /* NULL ENTRY */
+};
A simple {} will do the same.
+static int get_serdes_prctl_info_idx(u32 serdes_id) +{
- int pos = 0;
- struct serdes_prctl_info *srds_info;
- /* loop until NULL ENTRY defined by .id=0 */
- for (srds_info = srds_prctl_info; srds_info->id != 0;
srds_info++, pos++) {
if (srds_info->id == serdes_id)
return pos;
- }
- return -1;
+}
+static void do_enabled_lanes_reset(u32 serdes_id, u32 cfg,
struct ccsr_serdes __iomem *serdes_base,
bool cmplt)
+{
- int i, pos;
- u32 cfg_tmp, reg = 0;
- pos = get_serdes_prctl_info_idx(serdes_id);
- if (pos == -1) {
printf("invalid serdes_id %d\n", serdes_id);
return;
- }
- cfg_tmp = cfg & srds_prctl_info[pos].mask;
- cfg_tmp >>= srds_prctl_info[pos].shift;
- for (i = 0; i < 4 && cfg_tmp & (0xf << (3 - i)); i++) {
reg = in_le32(&serdes_base->lane[i].gcr0);
reg = (cmplt ? reg | LNAGCR0_RT_RSTB :
reg & LNAGCR0_RESET_MASK);
out_le32(&serdes_base->lane[i].gcr0, reg);
- }
+}
Have you considered to use clrbits_le32(), setbits_le32(), clrsetbits_le32() here and below as I suggested on previous review?
York

-----Original Message----- From: York Sun Sent: Tuesday, November 14, 2017 10:27 PM To: Rajesh Bhagat rajesh.bhagat@nxp.com; u-boot@lists.denx.de Cc: Prabhakar Kushwaha prabhakar.kushwaha@nxp.com; Priyanka Jain priyanka.jain@nxp.com; Ashish Kumar ashish.kumar@nxp.com Subject: Re: [PATCH v6 1/7] armv8: lsch3: Add serdes and DDR voltage setup
On 11/13/2017 11:06 PM, Rajesh Bhagat wrote:
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 v6:
- Corrected indentation/alignment issues at various places
- Changed NULL ENTRY in srds_prctl_info array to id as zero
- Corrected the PLL Reset logic, moved code inside for loop
- Used error code(-EINVAL) in setup_serdes_volt API
Changes in v5:
- Moved local macros to static functions
- Used array to handle PRCTL mask and shift operations
Changes in v4:
- Added local macros instead of magical numbers
- Created macros to remove duplicate code
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 | 312
+++++++++++++++++++++
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, 365 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..3e4b0bc 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,318 @@ 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;
+}
+#define LNAGCR0_RESET_MASK 0xFF9FFFFF +#define LNAGCR0_RT_RSTB 0x00600000 +#define RSTCTL_RESET_MASK_1 0xFFFFFFBF +#define RSTCTL_RESET_MASK_2 0xFFFFFF1F +#define RSTCTL_RESET_MASK_3 0xFFFFFFEF +#define RSTCTL_RSTREQ 0x10000000 +#define RSTCTL_RSTERR 0x20000000 +#define RSTCTL_SDEN 0x00000020 +#define RSTCTL_SDRST_B 0x00000040 +#define RSTCTL_PLLRST_B 0x00000080 +#define RSTCTL_RST_DONE 0x40000000 +#define TCALCR_RESET_MASK 0xF7FFFFFF +#define TCALCR_CALRST_B 0x08000000
+struct serdes_prctl_info {
- u32 id;
- u32 mask;
- u32 shift;
+};
+struct serdes_prctl_info srds_prctl_info[] = { #ifdef +CONFIG_SYS_FSL_SRDS_1
- {.id = 1,
.mask = FSL_CHASSIS3_SRDS1_PRTCL_MASK,
.shift = FSL_CHASSIS3_SRDS1_PRTCL_SHIFT
- },
+#endif +#ifdef CONFIG_SYS_FSL_SRDS_2
- {.id = 2,
.mask = FSL_CHASSIS3_SRDS2_PRTCL_MASK,
.shift = FSL_CHASSIS3_SRDS2_PRTCL_SHIFT
- },
+#endif
- {.id = 0,
.mask = 0,
.shift = 0
- } /* NULL ENTRY */
+};
A simple {} will do the same.
Will take care in v7.
+static int get_serdes_prctl_info_idx(u32 serdes_id) {
- int pos = 0;
- struct serdes_prctl_info *srds_info;
- /* loop until NULL ENTRY defined by .id=0 */
- for (srds_info = srds_prctl_info; srds_info->id != 0;
srds_info++, pos++) {
if (srds_info->id == serdes_id)
return pos;
- }
- return -1;
+}
+static void do_enabled_lanes_reset(u32 serdes_id, u32 cfg,
struct ccsr_serdes __iomem *serdes_base,
bool cmplt)
+{
- int i, pos;
- u32 cfg_tmp, reg = 0;
- pos = get_serdes_prctl_info_idx(serdes_id);
- if (pos == -1) {
printf("invalid serdes_id %d\n", serdes_id);
return;
- }
- cfg_tmp = cfg & srds_prctl_info[pos].mask;
- cfg_tmp >>= srds_prctl_info[pos].shift;
- for (i = 0; i < 4 && cfg_tmp & (0xf << (3 - i)); i++) {
reg = in_le32(&serdes_base->lane[i].gcr0);
reg = (cmplt ? reg | LNAGCR0_RT_RSTB :
reg & LNAGCR0_RESET_MASK);
out_le32(&serdes_base->lane[i].gcr0, reg);
- }
+}
Have you considered to use clrbits_le32(), setbits_le32(), clrsetbits_le32() here and below as I suggested on previous review?
I missed the comment, Let me update the patch with these APIs in v7.
- Rajesh
York

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 --- Changes in v6: None
Changes in v5: None
Changes in v4: None
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 --- Changes in v6: None
Changes in v5: None
Changes in v4: None
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 --- Changes in v6: None
Changes in v5: None
Changes in v4: None
board/freescale/common/vid.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-)
diff --git a/board/freescale/common/vid.c b/board/freescale/common/vid.c index 921841f..8acadc4 100644 --- a/board/freescale/common/vid.c +++ b/board/freescale/common/vid.c @@ -41,6 +41,8 @@ int __weak board_adjust_vdd(int vdd) return 0; }
+#if defined(CONFIG_VOL_MONITOR_IR36021_SET) || \ + defined(CONFIG_VOL_MONITOR_IR36021_READ) /* * Get the i2c address configuration for the IR regulator chip * @@ -73,6 +75,7 @@ static int find_ir_chip_on_i2c(void) } return -1; } +#endif
/* Maximum loop count waiting for new voltage to take effect */ #define MAX_LOOP_WAIT_NEW_VOL 100 @@ -184,6 +187,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 +247,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 +301,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 +377,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 +403,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); @@ -532,6 +543,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"); @@ -556,6 +569,7 @@ int adjust_vdd(ulong vdd_override) ret = -1; goto exit; } +#endif
/* get the voltage ID from fuse status register */ fusesr = in_be32(&gur->dcfg_fusesr); @@ -666,6 +680,8 @@ static int print_vdd(void) debug("VID : I2c failed to switch channel\n"); return -1; } +#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"); @@ -674,6 +690,7 @@ static int print_vdd(void) i2caddress = ret; debug("VID: IR Chip found on I2C address 0x%02x\n", i2caddress); } +#endif
/* * Read voltage monitor to check real voltage.

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 --- Changes in v6: None
Changes in v5: None
Changes in v4: None
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 v6: None
Changes in v5: None
Changes in v4: None
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 | 76 ++++++++++++++++++++++ include/configs/ls1088aqds.h | 16 +++++ include/configs/ls1088ardb.h | 15 +++++ 4 files changed, 114 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 47e8b5a..642df2f 100644 --- a/arch/arm/include/asm/arch-fsl-layerscape/immap_lsch3.h +++ b/arch/arm/include/asm/arch-fsl-layerscape/immap_lsch3.h @@ -201,10 +201,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 8acadc4..871f92a 100644 --- a/board/freescale/common/vid.c +++ b/board/freescale/common/vid.c @@ -174,6 +174,36 @@ 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; + u8 chan = PWM_CHANNEL0; + + /* select the PAGE 0 using PMBus commands PAGE for VDD*/ + ret = i2c_write(I2C_VOL_MONITOR_ADDR, + PMBUS_CMD_PAGE, 1, &chan, 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; @@ -181,6 +211,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 @@ -281,6 +313,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) @@ -289,6 +357,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 @@ -455,6 +525,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 @@ -472,6 +547,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 310e8fd..76570f2 100644 --- a/include/configs/ls1088aqds.h +++ b/include/configs/ls1088aqds.h @@ -280,6 +280,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 c7d1fd3..feffd33 100644 --- a/include/configs/ls1088ardb.h +++ b/include/configs/ls1088ardb.h @@ -211,6 +211,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 v6: None
Changes in v5: None
Changes in v4: None
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 | 121 ++++++++++++++++++++++++++++++++++++++ include/configs/ls1088aqds.h | 13 ++++ include/configs/ls1088ardb.h | 14 +++++ 3 files changed, 148 insertions(+)
diff --git a/board/freescale/ls1088a/ls1088a.c b/board/freescale/ls1088a/ls1088a.c index 96d9ae7..94f76df 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;
@@ -296,6 +300,121 @@ void board_retimer_init(void) 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; + u8 chan = PWM_CHANNEL0; + + /* Select the PAGE 0 using PMBus commands PAGE for VDD */ + ret = i2c_write(I2C_SVDD_MONITOR_ADDR, + PMBUS_CMD_PAGE, 1, &chan, 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) { init_final_memctl_regs(); @@ -314,6 +433,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 76570f2..417fe17 100644 --- a/include/configs/ls1088aqds.h +++ b/include/configs/ls1088aqds.h @@ -287,6 +287,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 feffd33..283b35c 100644 --- a/include/configs/ls1088ardb.h +++ b/include/configs/ls1088ardb.h @@ -137,6 +137,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 @@ -217,6 +218,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 (2)
-
Rajesh Bhagat
-
York Sun