mirror of
https://github.com/u-boot/u-boot.git
synced 2024-11-24 04:34:22 +08:00
armv8/fsl_lsch2: Add chip power supply voltage setup
Set up chip power supply voltage according to voltage ID. The fuse status register provides the values from on-chip voltage ID fuses programmed at the factory. These values define the voltage requirements for the chip. Main operations: 1. Set up the core voltage 2. Set up the SERDES voltage and reset SERDES lanes 3. Enable/disable DDR controller support 0.9V if needed Signed-off-by: Hou Zhiqiang <Zhiqiang.Hou@nxp.com> Reviewed-by: York Sun <york.sun@nxp.com>
This commit is contained in:
parent
6424577b1b
commit
031acdbae8
@ -129,6 +129,278 @@ void serdes_init(u32 sd, u32 sd_addr, u32 sd_prctl_mask, u32 sd_prctl_shift,
|
||||
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 *serdes1_base;
|
||||
#ifdef CONFIG_SYS_FSL_SRDS_2
|
||||
struct ccsr_serdes *serdes2_base;
|
||||
#endif
|
||||
u32 cfg_rcw4 = gur_in32(&gur->rcwsr[4]);
|
||||
u32 cfg_rcw5 = gur_in32(&gur->rcwsr[5]);
|
||||
u32 cfg_tmp, reg = 0;
|
||||
int svdd_cur, svdd_tar;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
/* Only support switch SVDD to 900mV/1000mV */
|
||||
if (svdd != 900 && svdd != 1000)
|
||||
return -EINVAL;
|
||||
|
||||
svdd_tar = svdd;
|
||||
svdd_cur = get_serdes_volt();
|
||||
if (svdd_cur < 0)
|
||||
return -EINVAL;
|
||||
|
||||
debug("%s: current SVDD: %dmV; target SVDD: %dmV\n",
|
||||
__func__, svdd_cur, svdd_tar);
|
||||
if (svdd_cur == svdd_tar)
|
||||
return 0;
|
||||
|
||||
serdes1_base = (void *)CONFIG_SYS_FSL_SERDES_ADDR;
|
||||
#ifdef CONFIG_SYS_FSL_SRDS_2
|
||||
serdes2_base = (void *)serdes1_base + 0x10000;
|
||||
#endif
|
||||
|
||||
/* Put the all enabled lanes in reset */
|
||||
#ifdef CONFIG_SYS_FSL_SRDS_1
|
||||
cfg_tmp = cfg_rcw4 & FSL_CHASSIS2_RCWSR4_SRDS1_PRTCL_MASK;
|
||||
cfg_tmp >>= FSL_CHASSIS2_RCWSR4_SRDS1_PRTCL_SHIFT;
|
||||
|
||||
for (i = 0; i < 4 && cfg_tmp & (0xf << (3 - i)); i++) {
|
||||
reg = in_be32(&serdes1_base->lane[i].gcr0);
|
||||
reg &= 0xFF9FFFFF;
|
||||
out_be32(&serdes1_base->lane[i].gcr0, reg);
|
||||
}
|
||||
#endif
|
||||
#ifdef CONFIG_SYS_FSL_SRDS_2
|
||||
cfg_tmp = cfg_rcw4 & FSL_CHASSIS2_RCWSR4_SRDS2_PRTCL_MASK;
|
||||
cfg_tmp >>= FSL_CHASSIS2_RCWSR4_SRDS2_PRTCL_SHIFT;
|
||||
|
||||
for (i = 0; i < 4 && cfg_tmp & (0xf << (3 - i)); i++) {
|
||||
reg = in_be32(&serdes2_base->lane[i].gcr0);
|
||||
reg &= 0xFF9FFFFF;
|
||||
out_be32(&serdes2_base->lane[i].gcr0, reg);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Put the all enabled PLL in reset */
|
||||
#ifdef CONFIG_SYS_FSL_SRDS_1
|
||||
cfg_tmp = (cfg_rcw5 >> 22) & 0x3;
|
||||
for (i = 0; i < 2 && !(cfg_tmp & (0x1 << (1 - i))); i++) {
|
||||
reg = in_be32(&serdes1_base->bank[i].rstctl);
|
||||
reg &= 0xFFFFFFBF;
|
||||
reg |= 0x10000000;
|
||||
out_be32(&serdes1_base->bank[i].rstctl, reg);
|
||||
udelay(1);
|
||||
|
||||
reg = in_be32(&serdes1_base->bank[i].rstctl);
|
||||
reg &= 0xFFFFFF1F;
|
||||
out_be32(&serdes1_base->bank[i].rstctl, reg);
|
||||
}
|
||||
udelay(1);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SYS_FSL_SRDS_2
|
||||
cfg_tmp = (cfg_rcw5 >> 20) & 0x3;
|
||||
for (i = 0; i < 2 && !(cfg_tmp & (0x1 << (1 - i))); i++) {
|
||||
reg = in_be32(&serdes2_base->bank[i].rstctl);
|
||||
reg &= 0xFFFFFFBF;
|
||||
reg |= 0x10000000;
|
||||
out_be32(&serdes2_base->bank[i].rstctl, reg);
|
||||
udelay(1);
|
||||
|
||||
reg = in_be32(&serdes2_base->bank[i].rstctl);
|
||||
reg &= 0xFFFFFF1F;
|
||||
out_be32(&serdes2_base->bank[i].rstctl, reg);
|
||||
}
|
||||
udelay(1);
|
||||
#endif
|
||||
|
||||
/* Put the Rx/Tx calibration into reset */
|
||||
#ifdef CONFIG_SYS_FSL_SRDS_1
|
||||
reg = in_be32(&serdes1_base->srdstcalcr);
|
||||
reg &= 0xF7FFFFFF;
|
||||
out_be32(&serdes1_base->srdstcalcr, reg);
|
||||
reg = in_be32(&serdes1_base->srdsrcalcr);
|
||||
reg &= 0xF7FFFFFF;
|
||||
out_be32(&serdes1_base->srdsrcalcr, reg);
|
||||
|
||||
#endif
|
||||
#ifdef CONFIG_SYS_FSL_SRDS_2
|
||||
reg = in_be32(&serdes2_base->srdstcalcr);
|
||||
reg &= 0xF7FFFFFF;
|
||||
out_be32(&serdes2_base->srdstcalcr, reg);
|
||||
reg = in_be32(&serdes2_base->srdsrcalcr);
|
||||
reg &= 0xF7FFFFFF;
|
||||
out_be32(&serdes2_base->srdsrcalcr, reg);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* If SVDD set failed, will not return directly, so that the
|
||||
* serdes lanes can complete reseting.
|
||||
*/
|
||||
ret = set_serdes_volt(svdd_tar);
|
||||
if (ret)
|
||||
printf("%s: Failed to set SVDD\n", __func__);
|
||||
|
||||
/* Wait for SVDD to stabilize */
|
||||
udelay(100);
|
||||
|
||||
/* For each PLL that’s not disabled via RCW */
|
||||
#ifdef CONFIG_SYS_FSL_SRDS_1
|
||||
cfg_tmp = (cfg_rcw5 >> 22) & 0x3;
|
||||
for (i = 0; i < 2 && !(cfg_tmp & (0x1 << (1 - i))); i++) {
|
||||
reg = in_be32(&serdes1_base->bank[i].rstctl);
|
||||
reg |= 0x00000020;
|
||||
out_be32(&serdes1_base->bank[i].rstctl, reg);
|
||||
udelay(1);
|
||||
|
||||
reg = in_be32(&serdes1_base->bank[i].rstctl);
|
||||
reg |= 0x00000080;
|
||||
out_be32(&serdes1_base->bank[i].rstctl, reg);
|
||||
|
||||
/* Take the Rx/Tx calibration out of reset */
|
||||
if (!(cfg_tmp == 0x3 && i == 1)) {
|
||||
udelay(1);
|
||||
reg = in_be32(&serdes1_base->srdstcalcr);
|
||||
reg |= 0x08000000;
|
||||
out_be32(&serdes1_base->srdstcalcr, reg);
|
||||
reg = in_be32(&serdes1_base->srdsrcalcr);
|
||||
reg |= 0x08000000;
|
||||
out_be32(&serdes1_base->srdsrcalcr, reg);
|
||||
}
|
||||
}
|
||||
udelay(1);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SYS_FSL_SRDS_2
|
||||
cfg_tmp = (cfg_rcw5 >> 20) & 0x3;
|
||||
for (i = 0; i < 2 && !(cfg_tmp & (0x1 << (1 - i))); i++) {
|
||||
reg = in_be32(&serdes2_base->bank[i].rstctl);
|
||||
reg |= 0x00000020;
|
||||
out_be32(&serdes2_base->bank[i].rstctl, reg);
|
||||
udelay(1);
|
||||
|
||||
reg = in_be32(&serdes2_base->bank[i].rstctl);
|
||||
reg |= 0x00000080;
|
||||
out_be32(&serdes2_base->bank[i].rstctl, reg);
|
||||
|
||||
/* Take the Rx/Tx calibration out of reset */
|
||||
if (!(cfg_tmp == 0x3 && i == 1)) {
|
||||
udelay(1);
|
||||
reg = in_be32(&serdes2_base->srdstcalcr);
|
||||
reg |= 0x08000000;
|
||||
out_be32(&serdes2_base->srdstcalcr, reg);
|
||||
reg = in_be32(&serdes2_base->srdsrcalcr);
|
||||
reg |= 0x08000000;
|
||||
out_be32(&serdes2_base->srdsrcalcr, reg);
|
||||
}
|
||||
}
|
||||
udelay(1);
|
||||
|
||||
#endif
|
||||
|
||||
/* Wait for at lesat 625us to ensure the PLLs being reset are locked */
|
||||
udelay(800);
|
||||
|
||||
#ifdef CONFIG_SYS_FSL_SRDS_1
|
||||
cfg_tmp = (cfg_rcw5 >> 22) & 0x3;
|
||||
for (i = 0; i < 2 && !(cfg_tmp & (0x1 << (1 - i))); i++) {
|
||||
/* if the PLL is not locked, set RST_ERR */
|
||||
reg = in_be32(&serdes1_base->bank[i].pllcr0);
|
||||
if (!((reg >> 23) & 0x1)) {
|
||||
reg = in_be32(&serdes1_base->bank[i].rstctl);
|
||||
reg |= 0x20000000;
|
||||
out_be32(&serdes1_base->bank[i].rstctl, reg);
|
||||
} else {
|
||||
udelay(1);
|
||||
reg = in_be32(&serdes1_base->bank[i].rstctl);
|
||||
reg &= 0xFFFFFFEF;
|
||||
reg |= 0x00000040;
|
||||
out_be32(&serdes1_base->bank[i].rstctl, reg);
|
||||
udelay(1);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SYS_FSL_SRDS_2
|
||||
cfg_tmp = (cfg_rcw5 >> 20) & 0x3;
|
||||
for (i = 0; i < 2 && !(cfg_tmp & (0x1 << (1 - i))); i++) {
|
||||
reg = in_be32(&serdes2_base->bank[i].pllcr0);
|
||||
if (!((reg >> 23) & 0x1)) {
|
||||
reg = in_be32(&serdes2_base->bank[i].rstctl);
|
||||
reg |= 0x20000000;
|
||||
out_be32(&serdes2_base->bank[i].rstctl, reg);
|
||||
} else {
|
||||
udelay(1);
|
||||
reg = in_be32(&serdes2_base->bank[i].rstctl);
|
||||
reg &= 0xFFFFFFEF;
|
||||
reg |= 0x00000040;
|
||||
out_be32(&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_rcw4 & FSL_CHASSIS2_RCWSR4_SRDS1_PRTCL_MASK;
|
||||
cfg_tmp >>= FSL_CHASSIS2_RCWSR4_SRDS1_PRTCL_SHIFT;
|
||||
|
||||
for (i = 0; i < 4 && cfg_tmp & (0xf << (3 - i)); i++) {
|
||||
reg = in_be32(&serdes1_base->lane[i].gcr0);
|
||||
reg |= 0x00600000;
|
||||
out_be32(&serdes1_base->lane[i].gcr0, reg);
|
||||
}
|
||||
#endif
|
||||
#ifdef CONFIG_SYS_FSL_SRDS_2
|
||||
cfg_tmp = cfg_rcw4 & FSL_CHASSIS2_RCWSR4_SRDS2_PRTCL_MASK;
|
||||
cfg_tmp >>= FSL_CHASSIS2_RCWSR4_SRDS2_PRTCL_SHIFT;
|
||||
|
||||
for (i = 0; i < 4 && cfg_tmp & (0xf << (3 - i)); i++) {
|
||||
reg = in_be32(&serdes2_base->lane[i].gcr0);
|
||||
reg |= 0x00600000;
|
||||
out_be32(&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_rcw5 >> 22) & 0x3;
|
||||
for (i = 0; i < 2; i++) {
|
||||
reg = in_be32(&serdes1_base->bank[i].pllcr0);
|
||||
if (!(cfg_tmp & (0x1 << (1 - i))) && ((reg >> 23) & 0x1)) {
|
||||
reg = in_be32(&serdes1_base->bank[i].rstctl);
|
||||
reg |= 0x40000000;
|
||||
out_be32(&serdes1_base->bank[i].rstctl, reg);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef CONFIG_SYS_FSL_SRDS_2
|
||||
cfg_tmp = (cfg_rcw5 >> 20) & 0x3;
|
||||
for (i = 0; i < 2; i++) {
|
||||
reg = in_be32(&serdes2_base->bank[i].pllcr0);
|
||||
if (!(cfg_tmp & (0x1 << (1 - i))) && ((reg >> 23) & 0x1)) {
|
||||
reg = in_be32(&serdes2_base->bank[i].rstctl);
|
||||
reg |= 0x40000000;
|
||||
out_be32(&serdes2_base->bank[i].rstctl, reg);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void fsl_serdes_init(void)
|
||||
{
|
||||
#ifdef CONFIG_SYS_FSL_SRDS_1
|
||||
|
@ -336,6 +336,95 @@ static void erratum_a010539(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Get VDD in the unit mV from voltage ID */
|
||||
int get_core_volt_from_fuse(void)
|
||||
{
|
||||
struct ccsr_gur *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
|
||||
int vdd;
|
||||
u32 fusesr;
|
||||
u8 vid;
|
||||
|
||||
fusesr = in_be32(&gur->dcfg_fusesr);
|
||||
debug("%s: fusesr = 0x%x\n", __func__, fusesr);
|
||||
vid = (fusesr >> FSL_CHASSIS2_DCFG_FUSESR_ALTVID_SHIFT) &
|
||||
FSL_CHASSIS2_DCFG_FUSESR_ALTVID_MASK;
|
||||
if ((vid == 0) || (vid == FSL_CHASSIS2_DCFG_FUSESR_ALTVID_MASK)) {
|
||||
vid = (fusesr >> FSL_CHASSIS2_DCFG_FUSESR_VID_SHIFT) &
|
||||
FSL_CHASSIS2_DCFG_FUSESR_VID_MASK;
|
||||
}
|
||||
debug("%s: VID = 0x%x\n", __func__, vid);
|
||||
switch (vid) {
|
||||
case 0x00: /* VID isn't supported */
|
||||
vdd = -EINVAL;
|
||||
debug("%s: The VID feature is not supported\n", __func__);
|
||||
break;
|
||||
case 0x08: /* 0.9V silicon */
|
||||
vdd = 900;
|
||||
break;
|
||||
case 0x10: /* 1.0V silicon */
|
||||
vdd = 1000;
|
||||
break;
|
||||
default: /* Other core voltage */
|
||||
vdd = -EINVAL;
|
||||
printf("%s: The VID(%x) isn't supported\n", __func__, vid);
|
||||
break;
|
||||
}
|
||||
debug("%s: The required minimum volt of CORE is %dmV\n", __func__, vdd);
|
||||
|
||||
return vdd;
|
||||
}
|
||||
|
||||
__weak int board_switch_core_volt(u32 vdd)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
vdd = get_core_volt_from_fuse();
|
||||
/* Nothing to do for silicons doesn't support VID */
|
||||
if (vdd < 0)
|
||||
return vdd;
|
||||
|
||||
if (setup_core_volt(vdd))
|
||||
printf("%s: Switch core VDD to %dmV failed\n", __func__, vdd);
|
||||
#ifdef CONFIG_SYS_HAS_SERDES
|
||||
if (setup_serdes_volt(vdd))
|
||||
printf("%s: Switch SVDD to %dmV failed\n", __func__, vdd);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SYS_FSL_DDR
|
||||
if (vdd == 900)
|
||||
ddr_enable_0v9_volt(true);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void fsl_lsch2_early_init_f(void)
|
||||
{
|
||||
struct ccsr_cci400 *cci = (struct ccsr_cci400 *)CONFIG_SYS_CCI400_ADDR;
|
||||
|
@ -162,6 +162,14 @@ int is_serdes_prtcl_valid(int serdes, u32 prtcl);
|
||||
#ifdef CONFIG_FSL_LSCH2
|
||||
const char *serdes_clock_to_string(u32 clock);
|
||||
int get_serdes_protocol(void);
|
||||
#ifdef CONFIG_SYS_HAS_SERDES
|
||||
/* Get the volt of SVDD in unit mV */
|
||||
int get_serdes_volt(void);
|
||||
/* Set the volt of SVDD in unit mV */
|
||||
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__ */
|
||||
|
@ -99,6 +99,9 @@ struct ccsr_ahci {
|
||||
void fsl_lsch3_early_init_f(void);
|
||||
#elif defined(CONFIG_FSL_LSCH2)
|
||||
void fsl_lsch2_early_init_f(void);
|
||||
int setup_chip_volt(void);
|
||||
/* Setup core vdd in unit mV */
|
||||
int board_setup_core_volt(u32 vdd);
|
||||
#endif
|
||||
|
||||
void cpu_name(char *name);
|
||||
|
@ -173,6 +173,7 @@ typedef struct ddr4_spd_eeprom_s generic_spd_eeprom_t;
|
||||
|
||||
/* DDR_CDR1 */
|
||||
#define DDR_CDR1_DHC_EN 0x80000000
|
||||
#define DDR_CDR1_V0PT9_EN 0x40000000
|
||||
#define DDR_CDR1_ODT_SHIFT 17
|
||||
#define DDR_CDR1_ODT_MASK 0x6
|
||||
#define DDR_CDR2_ODT_MASK 0x1
|
||||
|
Loading…
Reference in New Issue
Block a user