in arch/risc-v/src/mpfs/mpfs_ddr.c [2468:2983]
static void mpfs_ddr_manual_addcmd_training(struct mpfs_ddr_priv_s *priv)
{
uint32_t bclk_phase;
uint32_t bclk90_phase;
uint32_t refclk_phase;
uint32_t ca_indly;
uint32_t dpc_vals;
uint32_t j;
uint32_t i;
/* If automatic training is enabled, skip this */
if ((LIBERO_SETTING_TRAINING_SKIP_SETTING & ADDCMD_BIT) == 0)
{
return;
}
/* Apply offset & load the phase */
bclk_phase = ((priv->bclk_answer + SW_TRAINING_BCLK_SCLK_OFFSET) &
0x07) << 8;
bclk90_phase = ((priv->bclk_answer + SW_TRAINING_BCLK_SCLK_OFFSET + 2) &
0x07) << 11;
/* Store DRV & VREF initial values (to be re-applied after
* CA training)
*/
uint32_t ca_drv = getreg32(MPFS_CFG_DDR_SGMII_PHY_RPC1_DRV);
uint32_t ca_vref = (getreg32(MPFS_CFG_DDR_SGMII_PHY_DPC_BITS) >> 12) &
0x3f;
uint32_t dpc_bits_new;
uint32_t vref_answer;
uint32_t transition_a5_min_last = 129;
putreg32(0x01, MPFS_CFG_DDR_SGMII_PHY_EXPERT_MODE_EN);
for (ca_indly = 0; ca_indly < 30; ca_indly = ca_indly + 5)
{
putreg32(ca_indly, MPFS_CFG_DDR_SGMII_PHY_RPC145);
putreg32(ca_indly, MPFS_CFG_DDR_SGMII_PHY_RPC147);
uint32_t break_loop = 1;
uint32_t in_window = 0;
vref_answer = 128;
/* Begin VREF training */
for (uint32_t vref = 5; vref < 30; vref++)
{
uint32_t transition_a5_max = 0;
uint32_t transition_a5_min = 128;
uint32_t rx_a5_last;
uint32_t rx_a5;
uint32_t transition_a5;
uint32_t range_a5 = 0;
if (transition_a5_min_last > 128)
{
transition_a5_min_last = 128;
}
putreg32(0, MPFS_IOSCB_BANK_CNTL_DDR_SOFT_RESET);
/* Set VREF */
mpfs_wait_cycles(10);
dpc_bits_new = (getreg32(MPFS_CFG_DDR_SGMII_PHY_DPC_BITS) &
0xfffc0fff) | (vref << 12) | (0x1 << 18);
putreg32(dpc_bits_new, MPFS_CFG_DDR_SGMII_PHY_DPC_BITS);
mpfs_wait_cycles(10);
putreg32(1, MPFS_IOSCB_BANK_CNTL_DDR_SOFT_RESET);
mpfs_wait_cycles(10);
uint32_t deltat = 128;
for (j = 0; j < 20; j++)
{
putreg32(0x00,
MPFS_CFG_DDR_SGMII_PHY_EXPERT_DLYCNT_DIRECTION_REG1);
putreg32(0x00, MPFS_CFG_DDR_SGMII_PHY_EXPERT_DLYCNT_LOAD_REG1);
putreg32(0x180000,
MPFS_CFG_DDR_SGMII_PHY_EXPERT_DLYCNT_LOAD_REG1);
putreg32(0x00, MPFS_CFG_DDR_SGMII_PHY_EXPERT_DLYCNT_LOAD_REG1);
putreg32(0x180000,
MPFS_CFG_DDR_SGMII_PHY_EXPERT_DLYCNT_DIRECTION_REG1);
putreg32(0x00, MPFS_CFG_DDR_SGMII_PHY_EXPERT_DLYCNT_LOAD_REG1);
putreg32(0x180000,
MPFS_CFG_DDR_SGMII_PHY_EXPERT_DLYCNT_LOAD_REG1);
putreg32(0x00, MPFS_CFG_DDR_SGMII_PHY_EXPERT_DLYCNT_LOAD_REG1);
rx_a5_last = 0xf;
transition_a5 = 0;
deltat = 128;
mpfs_wait_cycles(10);
for (i = 0; i < (128 - ca_indly); i++)
{
putreg32(0x00,
MPFS_CFG_DDR_SGMII_PHY_EXPERT_DLYCNT_MOVE_REG1);
putreg32(0x180000,
MPFS_CFG_DDR_SGMII_PHY_EXPERT_DLYCNT_MOVE_REG1);
putreg32(0x00,
MPFS_CFG_DDR_SGMII_PHY_EXPERT_DLYCNT_MOVE_REG1);
mpfs_wait_cycles(10);
rx_a5 = (getreg32(
MPFS_CFG_DDR_SGMII_PHY_EXPERT_ADDCMD_LN_READBACK) \
& 0x0300) >> 8;
if (transition_a5 != 0)
{
if (((i - transition_a5) > 8))
{
break;
}
}
if (transition_a5 == 0)
{
if (((rx_a5 ^ rx_a5_last) & rx_a5))
{
transition_a5 = i;
}
else
{
rx_a5_last = rx_a5;
}
}
else
{
if ((i - transition_a5) == 4)
{
if (!((rx_a5 ^ rx_a5_last) & rx_a5))
{
/* Continue looking for transition */
transition_a5 = 0;
rx_a5_last = rx_a5;
}
}
}
}
if (transition_a5 != 0)
{
if (transition_a5 > transition_a5_max)
{
transition_a5_max = transition_a5;
}
if (transition_a5 < transition_a5_min)
{
transition_a5_min = transition_a5;
}
}
}
range_a5 = transition_a5_max - transition_a5_min;
if (transition_a5_min < 10)
{
break_loop = 0;
}
if (range_a5 <= 5)
{
if (transition_a5_min > transition_a5_min_last)
{
deltat = transition_a5_min - transition_a5_min_last;
}
else
{
deltat = transition_a5_min_last - transition_a5_min;
}
if (deltat <= 5)
{
in_window = (in_window << 1) | 1;
}
}
else
{
in_window = (in_window << 1) | 0;
}
if (vref_answer == 128)
{
if ((in_window & 0x3) == 0x3)
{
vref_answer = vref;
break;
}
}
transition_a5_min_last = transition_a5_min;
}
if (break_loop)
{
break;
}
}
putreg32(0, MPFS_IOSCB_BANK_CNTL_DDR_SOFT_RESET);
/* Set VREF */
mpfs_wait_cycles(10);
if (vref_answer == 128)
{
vref_answer = 0x10;
dpc_bits_new = (getreg32(MPFS_CFG_DDR_SGMII_PHY_DPC_BITS) & 0xfffc0fff)
| (vref_answer << 12) | (0x1 << 18);
}
else
{
vref_answer = vref_answer;
dpc_bits_new = (getreg32(MPFS_CFG_DDR_SGMII_PHY_DPC_BITS) & 0xfffc0fff)
| (vref_answer << 12) | (0x1 << 18);
}
putreg32(dpc_bits_new, MPFS_CFG_DDR_SGMII_PHY_DPC_BITS);
mpfs_wait_cycles(10);
putreg32(1, MPFS_IOSCB_BANK_CNTL_DDR_SOFT_RESET);
mpfs_wait_cycles(10000);
/* Begin manual addcmd training */
uint32_t init_del_offset = 0x8;
uint32_t a5_offset_fail;
uint32_t rpc147_offset = 0x2;
uint32_t rpc145_offset = 0x0;
uint8_t refclk_offset = mpfs_ddr_manual_addcmd_refclk_offset(priv);
a5_offset_fail = 1;
while (a5_offset_fail)
{
a5_offset_fail = 0; /* 1 indicates a fail */
putreg32(init_del_offset + rpc147_offset,
MPFS_CFG_DDR_SGMII_PHY_RPC147);
putreg32(init_del_offset + rpc145_offset,
MPFS_CFG_DDR_SGMII_PHY_RPC145);
putreg32(0x03, MPFS_CFG_DDR_SGMII_PHY_EXPERT_MODE_EN);
uint32_t rx_a5;
uint32_t rx_a5_last;
uint32_t rx_ck;
uint32_t rx_ck_last;
uint32_t transition_a5;
uint32_t transition_ck;
uint32_t difference[8] = {
0
};
uint32_t transition_ck_array[8] = {
0
};
uint32_t transitions_found;
uint32_t transition_a5_max = 0;
for (j = 0; j < 16; j++)
{
/* Increase j loop to increase number of samples on transition_a5
* (for noisy CA in LPDDR4)
*/
/* Load INDLY */
putreg32(0x00,
MPFS_CFG_DDR_SGMII_PHY_EXPERT_DLYCNT_DIRECTION_REG1);
putreg32(0x00, MPFS_CFG_DDR_SGMII_PHY_EXPERT_DLYCNT_LOAD_REG1);
putreg32(0x180000, MPFS_CFG_DDR_SGMII_PHY_EXPERT_DLYCNT_LOAD_REG1);
putreg32(0x00, MPFS_CFG_DDR_SGMII_PHY_EXPERT_DLYCNT_LOAD_REG1);
/* Load OUTDLY */
putreg32(0x180000,
MPFS_CFG_DDR_SGMII_PHY_EXPERT_DLYCNT_DIRECTION_REG1);
putreg32(0x00, MPFS_CFG_DDR_SGMII_PHY_EXPERT_DLYCNT_LOAD_REG1);
putreg32(0x180000, MPFS_CFG_DDR_SGMII_PHY_EXPERT_DLYCNT_LOAD_REG1);
putreg32(0x00, MPFS_CFG_DDR_SGMII_PHY_EXPERT_DLYCNT_LOAD_REG1);
refclk_phase = (j % 8U) << 2U;
putreg32((0x00004003 | bclk_phase | bclk90_phase | refclk_phase),
MPFS_IOSCB_DDR_PLL_PHADJ);
putreg32((0x00000003 | bclk_phase | bclk90_phase | refclk_phase),
MPFS_IOSCB_DDR_PLL_PHADJ);
putreg32((0x00004003 | bclk_phase | bclk90_phase | refclk_phase),
MPFS_IOSCB_DDR_PLL_PHADJ);
rx_a5_last = 0xf;
rx_ck_last = 0x5;
transition_a5 = 0;
transition_ck = 0;
mpfs_wait_cycles(100);
transitions_found = 0;
i = 0;
while ((!transitions_found) & (i < 128))
{
putreg32(0x00, MPFS_CFG_DDR_SGMII_PHY_EXPERT_DLYCNT_MOVE_REG1);
putreg32(0x180000,
MPFS_CFG_DDR_SGMII_PHY_EXPERT_DLYCNT_MOVE_REG1);
putreg32(0x00, MPFS_CFG_DDR_SGMII_PHY_EXPERT_DLYCNT_MOVE_REG1);
mpfs_wait_cycles(10);
rx_a5 =
(getreg32(MPFS_CFG_DDR_SGMII_PHY_EXPERT_ADDCMD_LN_READBACK) &
0x0300) >> 8;
rx_ck =
getreg32(MPFS_CFG_DDR_SGMII_PHY_EXPERT_ADDCMD_LN_READBACK) &
0x000f;
if ((transition_a5 != 0) && (transition_ck != 0))
{
if (((i - transition_a5) > 8) && ((i - transition_ck) > 8))
{
transitions_found = 1;
}
}
if (transition_ck == 0)
{
if (rx_ck_last != 0x5) /* If edge detected */
{
if (rx_ck == 0x5)
transition_ck = i; /* Transition detected at i */
}
rx_ck_last = rx_ck;
}
else
{
if ((i - transition_ck) == 4)
{
/* If rx_ck not stable after 4 increments, mark it
* a false transition
*/
if (rx_ck != rx_ck_last)
{
/* Keep looking for transition */
transition_ck = 0;
rx_ck_last = rx_ck;
}
}
}
if (transition_a5 == 0)
{
if (((rx_a5 ^ rx_a5_last) & rx_a5))
{
transition_a5 = i;
}
else
{
rx_a5_last = rx_a5;
}
}
else
{
if ((i - transition_a5) == 4)
{
if (!((rx_a5 ^ rx_a5_last) & rx_a5))
{
/* Keep looking for transition */
transition_a5 = 0;
rx_a5_last = rx_a5;
}
}
}
if ((transition_a5 != 0) && (transition_ck != 0))
{
if ((i == transition_a5) || (i == transition_ck))
{
}
}
i++;
}
if (transition_a5 > transition_a5_max)
{
transition_a5_max = transition_a5;
}
if ((transition_a5 != 0) && (transition_ck != 0) && (j < 8))
{
transition_ck_array[j] = transition_ck;
}
}
uint32_t min_diff = 0xff;
uint32_t min_refclk = 0x8;
if (transition_a5_max < 5)
{
a5_offset_fail = a5_offset_fail | 1;
}
for (uint32_t k = 0; k < 8; k++)
{
if (transition_a5_max >= transition_ck_array[k])
difference[k] = transition_a5_max - transition_ck_array[k];
else
difference[k] = 0xff;
if (difference[k] < min_diff)
{
min_diff = difference[k];
min_refclk = k;
}
}
if (min_diff == 0xff)
{
a5_offset_fail = a5_offset_fail | 1;
}
if (min_refclk == 0x8)
{
/* If ADDCMD training fails due to extremely low frequency,
* use PLL to provide offset.
*/
a5_offset_fail = a5_offset_fail | 4;
}
if (a5_offset_fail == 0)
{
refclk_phase = ((refclk_offset + min_refclk) & 0x7) << 2;
putreg32((0x00004003 | bclk_phase | bclk90_phase | refclk_phase),
MPFS_IOSCB_DDR_PLL_PHADJ);
putreg32((0x00000003 | bclk_phase | bclk90_phase | refclk_phase),
MPFS_IOSCB_DDR_PLL_PHADJ);
putreg32((0x00004003 | bclk_phase | bclk90_phase | refclk_phase),
MPFS_IOSCB_DDR_PLL_PHADJ);
/* Load INDLY */
putreg32(0x0, MPFS_CFG_DDR_SGMII_PHY_EXPERT_DLYCNT_DIRECTION_REG1);
putreg32(0x0, MPFS_CFG_DDR_SGMII_PHY_EXPERT_DLYCNT_LOAD_REG1);
putreg32(0x180000, MPFS_CFG_DDR_SGMII_PHY_EXPERT_DLYCNT_LOAD_REG1);
putreg32(0x0, MPFS_CFG_DDR_SGMII_PHY_EXPERT_DLYCNT_LOAD_REG1);
/* Load OUTDLY */
putreg32(0x180000,
MPFS_CFG_DDR_SGMII_PHY_EXPERT_DLYCNT_DIRECTION_REG1);
putreg32(0x0, MPFS_CFG_DDR_SGMII_PHY_EXPERT_DLYCNT_LOAD_REG1);
putreg32(0x180000, MPFS_CFG_DDR_SGMII_PHY_EXPERT_DLYCNT_LOAD_REG1);
putreg32(0x0, MPFS_CFG_DDR_SGMII_PHY_EXPERT_DLYCNT_LOAD_REG1);
for (uint32_t m = 0; m < min_diff; m++)
{
putreg32(0x0, MPFS_CFG_DDR_SGMII_PHY_EXPERT_DLYCNT_MOVE_REG1);
putreg32(0x180000,
MPFS_CFG_DDR_SGMII_PHY_EXPERT_DLYCNT_MOVE_REG1);
putreg32(0x0, MPFS_CFG_DDR_SGMII_PHY_EXPERT_DLYCNT_MOVE_REG1);
}
putreg32(0x0, MPFS_CFG_DDR_SGMII_PHY_EXPERT_DLYCNT_DIRECTION_REG1);
putreg32(0x0, MPFS_CFG_DDR_SGMII_PHY_EXPERT_MODE_EN);
}
else
{
if (a5_offset_fail & 0x1)
{
if (init_del_offset < 0xff)
{
/* If transition_a5 too low, increase indly offset on CK
* and CA and retrain
*/
init_del_offset += (transition_a5_max) + 5;
}
else
{
break;
}
}
}
}
/* Set VREF back to configured value */
putreg32(0, MPFS_IOSCB_BANK_CNTL_DDR_SOFT_RESET);
mpfs_wait_cycles(10);
dpc_vals = (getreg32(MPFS_CFG_DDR_SGMII_PHY_DPC_BITS) & 0xfffc0fff) |
(ca_vref << 12) | (0x1 << 18);
putreg32(dpc_vals, MPFS_CFG_DDR_SGMII_PHY_DPC_BITS);
mpfs_wait_cycles(10);
putreg32(0x01, MPFS_IOSCB_BANK_CNTL_DDR_SOFT_RESET);
mpfs_wait_cycles(10);
/* Set CA DRV back to configured value */
putreg32(ca_drv, MPFS_CFG_DDR_SGMII_PHY_RPC1_DRV);
}