blob: b7dfebd93cc4c0c478278275426d6fb88efe8a73 [file] [log] [blame]
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) Marvell International Ltd. and its affiliates
*/
#include "ddr3_init.h"
#include "mv_ddr_training_db.h"
#include "mv_ddr_common.h"
#include "mv_ddr_regs.h"
#define TYPICAL_PBS_VALUE 12
u32 nominal_adll[MAX_INTERFACE_NUM * MAX_BUS_NUM];
enum hws_training_ip_stat train_status[MAX_INTERFACE_NUM];
u8 result_mat[MAX_INTERFACE_NUM][MAX_BUS_NUM][BUS_WIDTH_IN_BITS];
u8 result_mat_rx_dqs[MAX_INTERFACE_NUM][MAX_BUS_NUM][MAX_CS_NUM];
/* 4-EEWA, 3-EWA, 2-SWA, 1-Fail, 0-Pass */
u8 result_all_bit[MAX_BUS_NUM * BUS_WIDTH_IN_BITS * MAX_INTERFACE_NUM];
u8 max_pbs_per_pup[MAX_INTERFACE_NUM][MAX_BUS_NUM];
u8 min_pbs_per_pup[MAX_INTERFACE_NUM][MAX_BUS_NUM];
u8 max_adll_per_pup[MAX_INTERFACE_NUM][MAX_BUS_NUM];
u8 min_adll_per_pup[MAX_INTERFACE_NUM][MAX_BUS_NUM];
u32 pbsdelay_per_pup[NUM_OF_PBS_MODES][MAX_INTERFACE_NUM][MAX_BUS_NUM][MAX_CS_NUM];
u8 adll_shift_lock[MAX_INTERFACE_NUM][MAX_BUS_NUM];
u8 adll_shift_val[MAX_INTERFACE_NUM][MAX_BUS_NUM];
enum hws_pattern pbs_pattern = PATTERN_VREF;
static u8 pup_state[MAX_INTERFACE_NUM][MAX_BUS_NUM];
/*
* Name: ddr3_tip_pbs
* Desc: PBS
* Args: TBD
* Notes:
* Returns: OK if success, other error code if fail.
*/
int ddr3_tip_pbs(u32 dev_num, enum pbs_dir pbs_mode)
{
u32 res0[MAX_INTERFACE_NUM];
int adll_tap = MEGA / mv_ddr_freq_get(medium_freq) / 64;
int pad_num = 0;
enum hws_search_dir search_dir =
(pbs_mode == PBS_RX_MODE) ? HWS_HIGH2LOW : HWS_LOW2HIGH;
enum hws_dir dir = (pbs_mode == PBS_RX_MODE) ? OPER_READ : OPER_WRITE;
int iterations = (pbs_mode == PBS_RX_MODE) ? 31 : 63;
u32 res_valid_mask = (pbs_mode == PBS_RX_MODE) ? 0x1f : 0x3f;
int init_val = (search_dir == HWS_LOW2HIGH) ? 0 : iterations;
enum hws_edge_compare search_edge = EDGE_FP;
u32 pup = 0, bit = 0, if_id = 0, all_lock = 0, cs_num = 0;
u32 reg_addr = 0;
u32 validation_val = 0;
u32 cs_enable_reg_val[MAX_INTERFACE_NUM];
u16 *mask_results_dq_reg_map = ddr3_tip_get_mask_results_dq_reg();
u8 temp = 0;
u32 octets_per_if_num = ddr3_tip_dev_attr_get(dev_num, MV_ATTR_OCTET_PER_INTERFACE);
struct mv_ddr_topology_map *tm = mv_ddr_topology_map_get();
/* save current cs enable reg val */
for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
VALIDATE_IF_ACTIVE(tm->if_act_mask, if_id);
/* save current cs enable reg val */
CHECK_STATUS(ddr3_tip_if_read
(dev_num, ACCESS_TYPE_UNICAST, if_id,
DUAL_DUNIT_CFG_REG, cs_enable_reg_val, MASK_ALL_BITS));
/* enable single cs */
CHECK_STATUS(ddr3_tip_if_write
(dev_num, ACCESS_TYPE_UNICAST, if_id,
DUAL_DUNIT_CFG_REG, (1 << 3), (1 << 3)));
}
reg_addr = (pbs_mode == PBS_RX_MODE) ?
CRX_PHY_REG(effective_cs) :
CTX_PHY_REG(effective_cs);
ddr3_tip_read_adll_value(dev_num, nominal_adll, reg_addr, MASK_ALL_BITS);
/* stage 1 shift ADLL */
ddr3_tip_ip_training(dev_num, ACCESS_TYPE_MULTICAST,
PARAM_NOT_CARE, ACCESS_TYPE_MULTICAST,
PARAM_NOT_CARE, RESULT_PER_BIT,
HWS_CONTROL_ELEMENT_ADLL, search_dir, dir,
tm->if_act_mask, init_val, iterations,
pbs_pattern, search_edge, CS_SINGLE, cs_num,
train_status);
validation_val = (pbs_mode == PBS_RX_MODE) ? 0x1f : 0;
for (pup = 0; pup < octets_per_if_num; pup++) {
VALIDATE_BUS_ACTIVE(tm->bus_act_mask, pup);
for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
VALIDATE_IF_ACTIVE(tm->if_act_mask, if_id);
min_adll_per_pup[if_id][pup] =
(pbs_mode == PBS_RX_MODE) ? 0x1f : 0x3f;
pup_state[if_id][pup] = 0x3;
adll_shift_lock[if_id][pup] = 1;
max_adll_per_pup[if_id][pup] = 0x0;
}
}
/* EBA */
for (pup = 0; pup < octets_per_if_num; pup++) {
VALIDATE_BUS_ACTIVE(tm->bus_act_mask, pup);
for (bit = 0; bit < BUS_WIDTH_IN_BITS; bit++) {
CHECK_STATUS(ddr3_tip_if_read
(dev_num, ACCESS_TYPE_MULTICAST,
PARAM_NOT_CARE,
mask_results_dq_reg_map[
bit + pup * BUS_WIDTH_IN_BITS],
res0, MASK_ALL_BITS));
for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1;
if_id++) {
VALIDATE_IF_ACTIVE(tm->if_act_mask, if_id);
DEBUG_PBS_ENGINE(DEBUG_LEVEL_TRACE,
("FP I/F %d, bit:%d, pup:%d res0 0x%x\n",
if_id, bit, pup,
res0[if_id]));
if (pup_state[if_id][pup] != 3)
continue;
/* if not EBA state than move to next pup */
if ((res0[if_id] & 0x2000000) == 0) {
DEBUG_PBS_ENGINE(DEBUG_LEVEL_TRACE,
("-- Fail Training IP\n"));
/* training machine failed */
pup_state[if_id][pup] = 1;
adll_shift_lock[if_id][pup] = 0;
continue;
}
else if ((res0[if_id] & res_valid_mask) ==
validation_val) {
DEBUG_PBS_ENGINE(DEBUG_LEVEL_TRACE,
("-- FAIL EBA %d %d %d %d\n",
if_id, bit, pup,
res0[if_id]));
pup_state[if_id][pup] = 4;
/* this pup move to EEBA */
adll_shift_lock[if_id][pup] = 0;
continue;
} else {
/*
* The search ended in Pass we need
* Fail
*/
res0[if_id] =
(pbs_mode == PBS_RX_MODE) ?
((res0[if_id] &
res_valid_mask) + 1) :
((res0[if_id] &
res_valid_mask) - 1);
max_adll_per_pup[if_id][pup] =
(max_adll_per_pup[if_id][pup] <
res0[if_id]) ?
(u8)res0[if_id] :
max_adll_per_pup[if_id][pup];
min_adll_per_pup[if_id][pup] =
(res0[if_id] >
min_adll_per_pup[if_id][pup]) ?
min_adll_per_pup[if_id][pup] :
(u8)
res0[if_id];
/*
* vs the Rx we are searching for the
* smallest value of DQ shift so all
* Bus would fail
*/
adll_shift_val[if_id][pup] =
(pbs_mode == PBS_RX_MODE) ?
max_adll_per_pup[if_id][pup] :
min_adll_per_pup[if_id][pup];
}
}
}
}
/* EEBA */
for (pup = 0; pup < octets_per_if_num; pup++) {
VALIDATE_BUS_ACTIVE(tm->bus_act_mask, pup);
for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
VALIDATE_IF_ACTIVE(tm->if_act_mask, if_id);
if (pup_state[if_id][pup] != 4)
continue;
/*
* if pup state different from EEBA than move to
* next pup
*/
reg_addr = (pbs_mode == PBS_RX_MODE) ?
(0x54 + effective_cs * 0x10) :
(0x14 + effective_cs * 0x10);
CHECK_STATUS(ddr3_tip_bus_write
(dev_num, ACCESS_TYPE_UNICAST, if_id,
ACCESS_TYPE_UNICAST, pup, DDR_PHY_DATA,
reg_addr, 0x1f));
reg_addr = (pbs_mode == PBS_RX_MODE) ?
(0x55 + effective_cs * 0x10) :
(0x15 + effective_cs * 0x10);
CHECK_STATUS(ddr3_tip_bus_write
(dev_num, ACCESS_TYPE_UNICAST, if_id,
ACCESS_TYPE_UNICAST, pup, DDR_PHY_DATA,
reg_addr, 0x1f));
/* initialize the Edge2 Max. */
adll_shift_val[if_id][pup] = 0;
min_adll_per_pup[if_id][pup] =
(pbs_mode == PBS_RX_MODE) ? 0x1f : 0x3f;
max_adll_per_pup[if_id][pup] = 0x0;
ddr3_tip_ip_training(dev_num, ACCESS_TYPE_MULTICAST,
PARAM_NOT_CARE,
ACCESS_TYPE_MULTICAST,
PARAM_NOT_CARE, RESULT_PER_BIT,
HWS_CONTROL_ELEMENT_ADLL,
search_dir, dir,
tm->if_act_mask, init_val,
iterations, pbs_pattern,
search_edge, CS_SINGLE, cs_num,
train_status);
DEBUG_PBS_ENGINE(DEBUG_LEVEL_INFO,
("ADLL shift results:\n"));
for (bit = 0; bit < BUS_WIDTH_IN_BITS; bit++) {
CHECK_STATUS(ddr3_tip_if_read
(dev_num, ACCESS_TYPE_MULTICAST,
PARAM_NOT_CARE,
mask_results_dq_reg_map[
bit + pup *
BUS_WIDTH_IN_BITS],
res0, MASK_ALL_BITS));
DEBUG_PBS_ENGINE(DEBUG_LEVEL_TRACE,
("FP I/F %d, bit:%d, pup:%d res0 0x%x\n",
if_id, bit, pup,
res0[if_id]));
if ((res0[if_id] & 0x2000000) == 0) {
DEBUG_PBS_ENGINE(DEBUG_LEVEL_TRACE,
(" -- EEBA Fail\n"));
bit = BUS_WIDTH_IN_BITS;
/* exit bit loop */
DEBUG_PBS_ENGINE(DEBUG_LEVEL_TRACE,
("-- EEBA Fail Training IP\n"));
/*
* training machine failed but pass
* before in the EBA so maybe the DQS
* shift change env.
*/
pup_state[if_id][pup] = 2;
adll_shift_lock[if_id][pup] = 0;
reg_addr = (pbs_mode == PBS_RX_MODE) ?
(0x54 + effective_cs * 0x10) :
(0x14 + effective_cs * 0x10);
CHECK_STATUS(ddr3_tip_bus_write
(dev_num,
ACCESS_TYPE_UNICAST,
if_id,
ACCESS_TYPE_UNICAST, pup,
DDR_PHY_DATA, reg_addr,
0x0));
reg_addr = (pbs_mode == PBS_RX_MODE) ?
(0x55 + effective_cs * 0x10) :
(0x15 + effective_cs * 0x10);
CHECK_STATUS(ddr3_tip_bus_write
(dev_num,
ACCESS_TYPE_UNICAST,
if_id,
ACCESS_TYPE_UNICAST, pup,
DDR_PHY_DATA, reg_addr,
0x0));
continue;
} else if ((res0[if_id] & res_valid_mask) ==
validation_val) {
/* exit bit loop */
bit = BUS_WIDTH_IN_BITS;
DEBUG_PBS_ENGINE(DEBUG_LEVEL_TRACE,
("-- FAIL EEBA\n"));
/* this pup move to SBA */
pup_state[if_id][pup] = 2;
adll_shift_lock[if_id][pup] = 0;
reg_addr = (pbs_mode == PBS_RX_MODE) ?
(0x54 + effective_cs * 0x10) :
(0x14 + effective_cs * 0x10);
CHECK_STATUS(ddr3_tip_bus_write
(dev_num,
ACCESS_TYPE_UNICAST,
if_id,
ACCESS_TYPE_UNICAST, pup,
DDR_PHY_DATA, reg_addr,
0x0));
reg_addr = (pbs_mode == PBS_RX_MODE) ?
(0x55 + effective_cs * 0x10) :
(0x15 + effective_cs * 0x10);
CHECK_STATUS(ddr3_tip_bus_write
(dev_num,
ACCESS_TYPE_UNICAST,
if_id,
ACCESS_TYPE_UNICAST, pup,
DDR_PHY_DATA, reg_addr,
0x0));
continue;
} else {
adll_shift_lock[if_id][pup] = 1;
/*
* The search ended in Pass we need
* Fail
*/
res0[if_id] =
(pbs_mode == PBS_RX_MODE) ?
((res0[if_id] &
res_valid_mask) + 1) :
((res0[if_id] &
res_valid_mask) - 1);
max_adll_per_pup[if_id][pup] =
(max_adll_per_pup[if_id][pup] <
res0[if_id]) ?
(u8)res0[if_id] :
max_adll_per_pup[if_id][pup];
min_adll_per_pup[if_id][pup] =
(res0[if_id] >
min_adll_per_pup[if_id][pup]) ?
min_adll_per_pup[if_id][pup] :
(u8)res0[if_id];
/*
* vs the Rx we are searching for the
* smallest value of DQ shift so all Bus
* would fail
*/
adll_shift_val[if_id][pup] =
(pbs_mode == PBS_RX_MODE) ?
max_adll_per_pup[if_id][pup] :
min_adll_per_pup[if_id][pup];
}
}
}
}
/* Print Stage result */
for (pup = 0; pup < octets_per_if_num; pup++) {
VALIDATE_BUS_ACTIVE(tm->bus_act_mask, pup);
for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
VALIDATE_IF_ACTIVE(tm->if_act_mask, if_id);
DEBUG_PBS_ENGINE(DEBUG_LEVEL_TRACE,
("FP I/F %d, ADLL Shift for EBA: pup[%d] Lock status = %d Lock Val = %d,%d\n",
if_id, pup,
adll_shift_lock[if_id][pup],
max_adll_per_pup[if_id][pup],
min_adll_per_pup[if_id][pup]));
}
}
DEBUG_PBS_ENGINE(DEBUG_LEVEL_INFO,
("Update ADLL Shift of all pups:\n"));
for (pup = 0; pup < octets_per_if_num; pup++) {
VALIDATE_BUS_ACTIVE(tm->bus_act_mask, pup);
for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
VALIDATE_IF_ACTIVE(tm->if_act_mask, if_id);
if (adll_shift_lock[if_id][pup] != 1)
continue;
/* if pup not locked continue to next pup */
reg_addr = (pbs_mode == PBS_RX_MODE) ?
(0x3 + effective_cs * 4) :
(0x1 + effective_cs * 4);
CHECK_STATUS(ddr3_tip_bus_write
(dev_num, ACCESS_TYPE_UNICAST, if_id,
ACCESS_TYPE_UNICAST, pup, DDR_PHY_DATA,
reg_addr, adll_shift_val[if_id][pup]));
DEBUG_PBS_ENGINE(DEBUG_LEVEL_TRACE,
("FP I/F %d, Pup[%d] = %d\n", if_id,
pup, adll_shift_val[if_id][pup]));
}
}
/* PBS EEBA&EBA */
/* Start the Per Bit Skew search */
for (pup = 0; pup < octets_per_if_num; pup++) {
VALIDATE_BUS_ACTIVE(tm->bus_act_mask, pup);
for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
VALIDATE_IF_ACTIVE(tm->if_act_mask, if_id);
max_pbs_per_pup[if_id][pup] = 0x0;
min_pbs_per_pup[if_id][pup] = 0x1f;
for (bit = 0; bit < BUS_WIDTH_IN_BITS; bit++) {
/* reset result for PBS */
result_all_bit[bit + pup * BUS_WIDTH_IN_BITS +
if_id * MAX_BUS_NUM *
BUS_WIDTH_IN_BITS] = 0;
}
}
}
iterations = 31;
search_dir = HWS_LOW2HIGH;
/* !!!!! ran sh (search_dir == HWS_LOW2HIGH)?0:iterations; */
init_val = 0;
ddr3_tip_ip_training(dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
RESULT_PER_BIT, HWS_CONTROL_ELEMENT_DQ_SKEW,
search_dir, dir, tm->if_act_mask, init_val,
iterations, pbs_pattern, search_edge,
CS_SINGLE, cs_num, train_status);
for (pup = 0; pup < octets_per_if_num; pup++) {
VALIDATE_BUS_ACTIVE(tm->bus_act_mask, pup);
for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
VALIDATE_IF_ACTIVE(tm->if_act_mask, if_id);
if (adll_shift_lock[if_id][pup] != 1) {
/* if pup not lock continue to next pup */
continue;
}
for (bit = 0; bit < BUS_WIDTH_IN_BITS; bit++) {
CHECK_STATUS(ddr3_tip_if_read
(dev_num, ACCESS_TYPE_MULTICAST,
PARAM_NOT_CARE,
mask_results_dq_reg_map[
bit +
pup * BUS_WIDTH_IN_BITS],
res0, MASK_ALL_BITS));
DEBUG_PBS_ENGINE(DEBUG_LEVEL_INFO,
("Per Bit Skew search, FP I/F %d, bit:%d, pup:%d res0 0x%x\n",
if_id, bit, pup,
res0[if_id]));
if ((res0[if_id] & 0x2000000) == 0) {
DEBUG_PBS_ENGINE(DEBUG_LEVEL_INFO,
("--EBA PBS Fail - Training IP machine\n"));
/* exit the bit loop */
bit = BUS_WIDTH_IN_BITS;
/*
* ADLL is no long in lock need new
* search
*/
adll_shift_lock[if_id][pup] = 0;
/* Move to SBA */
pup_state[if_id][pup] = 2;
max_pbs_per_pup[if_id][pup] = 0x0;
min_pbs_per_pup[if_id][pup] = 0x1f;
continue;
} else {
temp = (u8)(res0[if_id] &
res_valid_mask);
max_pbs_per_pup[if_id][pup] =
(temp >
max_pbs_per_pup[if_id][pup]) ?
temp :
max_pbs_per_pup[if_id][pup];
min_pbs_per_pup[if_id][pup] =
(temp <
min_pbs_per_pup[if_id][pup]) ?
temp :
min_pbs_per_pup[if_id][pup];
result_all_bit[bit +
pup * BUS_WIDTH_IN_BITS +
if_id * MAX_BUS_NUM *
BUS_WIDTH_IN_BITS] =
temp;
}
}
}
}
/* Check all Pup lock */
all_lock = 1;
for (pup = 0; pup < octets_per_if_num; pup++) {
VALIDATE_BUS_ACTIVE(tm->bus_act_mask, pup);
for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
VALIDATE_IF_ACTIVE(tm->if_act_mask, if_id);
all_lock = all_lock * adll_shift_lock[if_id][pup];
}
}
/* Only if not all Pups Lock */
if (all_lock == 0) {
DEBUG_PBS_ENGINE(DEBUG_LEVEL_INFO,
("##########ADLL shift for SBA###########\n"));
/* ADLL shift for SBA */
search_dir = (pbs_mode == PBS_RX_MODE) ? HWS_LOW2HIGH :
HWS_HIGH2LOW;
init_val = (search_dir == HWS_LOW2HIGH) ? 0 : iterations;
for (pup = 0; pup < octets_per_if_num; pup++) {
VALIDATE_BUS_ACTIVE(tm->bus_act_mask, pup);
for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1;
if_id++) {
VALIDATE_IF_ACTIVE(tm->if_act_mask, if_id);
if (adll_shift_lock[if_id][pup] == 1) {
/*if pup lock continue to next pup */
continue;
}
/*init the var altogth init before */
adll_shift_lock[if_id][pup] = 0;
reg_addr = (pbs_mode == PBS_RX_MODE) ?
(0x54 + effective_cs * 0x10) :
(0x14 + effective_cs * 0x10);
CHECK_STATUS(ddr3_tip_bus_write
(dev_num, ACCESS_TYPE_UNICAST,
if_id, ACCESS_TYPE_UNICAST, pup,
DDR_PHY_DATA, reg_addr, 0));
reg_addr = (pbs_mode == PBS_RX_MODE) ?
(0x55 + effective_cs * 0x10) :
(0x15 + effective_cs * 0x10);
CHECK_STATUS(ddr3_tip_bus_write
(dev_num, ACCESS_TYPE_UNICAST,
if_id, ACCESS_TYPE_UNICAST, pup,
DDR_PHY_DATA, reg_addr, 0));
reg_addr = (pbs_mode == PBS_RX_MODE) ?
(0x5f + effective_cs * 0x10) :
(0x1f + effective_cs * 0x10);
CHECK_STATUS(ddr3_tip_bus_write
(dev_num, ACCESS_TYPE_UNICAST,
if_id, ACCESS_TYPE_UNICAST, pup,
DDR_PHY_DATA, reg_addr, 0));
/* initilaze the Edge2 Max. */
adll_shift_val[if_id][pup] = 0;
min_adll_per_pup[if_id][pup] = 0x1f;
max_adll_per_pup[if_id][pup] = 0x0;
ddr3_tip_ip_training(dev_num,
ACCESS_TYPE_MULTICAST,
PARAM_NOT_CARE,
ACCESS_TYPE_MULTICAST,
PARAM_NOT_CARE,
RESULT_PER_BIT,
HWS_CONTROL_ELEMENT_ADLL,
search_dir, dir,
tm->if_act_mask,
init_val, iterations,
pbs_pattern,
search_edge, CS_SINGLE,
cs_num, train_status);
for (bit = 0; bit < BUS_WIDTH_IN_BITS; bit++) {
CHECK_STATUS(ddr3_tip_if_read
(dev_num,
ACCESS_TYPE_MULTICAST,
PARAM_NOT_CARE,
mask_results_dq_reg_map
[bit +
pup *
BUS_WIDTH_IN_BITS],
res0, MASK_ALL_BITS));
DEBUG_PBS_ENGINE(
DEBUG_LEVEL_INFO,
("FP I/F %d, bit:%d, pup:%d res0 0x%x\n",
if_id, bit, pup, res0[if_id]));
if ((res0[if_id] & 0x2000000) == 0) {
/* exit the bit loop */
bit = BUS_WIDTH_IN_BITS;
/* Fail SBA --> Fail PBS */
pup_state[if_id][pup] = 1;
DEBUG_PBS_ENGINE
(DEBUG_LEVEL_INFO,
(" SBA Fail\n"));
continue;
} else {
/*
* - increment to get all
* 8 bit lock.
*/
adll_shift_lock[if_id][pup]++;
/*
* The search ended in Pass
* we need Fail
*/
res0[if_id] =
(pbs_mode == PBS_RX_MODE) ?
((res0[if_id] & res_valid_mask) + 1) :
((res0[if_id] & res_valid_mask) - 1);
max_adll_per_pup[if_id][pup] =
(max_adll_per_pup[if_id]
[pup] < res0[if_id]) ?
(u8)res0[if_id] :
max_adll_per_pup[if_id][pup];
min_adll_per_pup[if_id][pup] =
(res0[if_id] >
min_adll_per_pup[if_id]
[pup]) ?
min_adll_per_pup[if_id][pup] :
(u8)res0[if_id];
/*
* vs the Rx we are searching for
* the smallest value of DQ shift
* so all Bus would fail
*/
adll_shift_val[if_id][pup] =
(pbs_mode == PBS_RX_MODE) ?
max_adll_per_pup[if_id][pup] :
min_adll_per_pup[if_id][pup];
}
}
/* 1 is lock */
adll_shift_lock[if_id][pup] =
(adll_shift_lock[if_id][pup] == 8) ?
1 : 0;
reg_addr = (pbs_mode == PBS_RX_MODE) ?
(0x3 + effective_cs * 4) :
(0x1 + effective_cs * 4);
CHECK_STATUS(ddr3_tip_bus_write
(dev_num, ACCESS_TYPE_UNICAST,
if_id, ACCESS_TYPE_UNICAST, pup,
DDR_PHY_DATA, reg_addr,
adll_shift_val[if_id][pup]));
DEBUG_PBS_ENGINE(
DEBUG_LEVEL_INFO,
("adll_shift_lock[%x][%x] = %x\n",
if_id, pup,
adll_shift_lock[if_id][pup]));
}
}
/* End ADLL Shift for SBA */
/* Start the Per Bit Skew search */
/* The ADLL shift finished with a Pass */
search_edge = (pbs_mode == PBS_RX_MODE) ? EDGE_PF : EDGE_FP;
search_dir = (pbs_mode == PBS_RX_MODE) ?
HWS_LOW2HIGH : HWS_HIGH2LOW;
iterations = 0x1f;
/* - The initial value is different in Rx and Tx mode */
init_val = (pbs_mode == PBS_RX_MODE) ? 0 : iterations;
ddr3_tip_ip_training(dev_num, ACCESS_TYPE_MULTICAST,
PARAM_NOT_CARE, ACCESS_TYPE_MULTICAST,
PARAM_NOT_CARE, RESULT_PER_BIT,
HWS_CONTROL_ELEMENT_DQ_SKEW,
search_dir, dir, tm->if_act_mask,
init_val, iterations, pbs_pattern,
search_edge, CS_SINGLE, cs_num,
train_status);
for (pup = 0; pup < octets_per_if_num; pup++) {
VALIDATE_BUS_ACTIVE(tm->bus_act_mask, pup);
for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1;
if_id++) {
VALIDATE_IF_ACTIVE(tm->if_act_mask, if_id);
for (bit = 0; bit < BUS_WIDTH_IN_BITS; bit++) {
CHECK_STATUS(ddr3_tip_if_read
(dev_num,
ACCESS_TYPE_MULTICAST,
PARAM_NOT_CARE,
mask_results_dq_reg_map
[bit +
pup *
BUS_WIDTH_IN_BITS],
res0, MASK_ALL_BITS));
if (pup_state[if_id][pup] != 2) {
/*
* if pup is not SBA continue
* to next pup
*/
bit = BUS_WIDTH_IN_BITS;
continue;
}
DEBUG_PBS_ENGINE(
DEBUG_LEVEL_INFO,
("Per Bit Skew search, PF I/F %d, bit:%d, pup:%d res0 0x%x\n",
if_id, bit, pup, res0[if_id]));
if ((res0[if_id] & 0x2000000) == 0) {
DEBUG_PBS_ENGINE
(DEBUG_LEVEL_INFO,
("SBA Fail\n"));
max_pbs_per_pup[if_id][pup] =
0x1f;
result_all_bit[
bit + pup *
BUS_WIDTH_IN_BITS +
if_id * MAX_BUS_NUM *
BUS_WIDTH_IN_BITS] =
0x1f;
} else {
temp = (u8)(res0[if_id] &
res_valid_mask);
max_pbs_per_pup[if_id][pup] =
(temp >
max_pbs_per_pup[if_id]
[pup]) ? temp :
max_pbs_per_pup
[if_id][pup];
min_pbs_per_pup[if_id][pup] =
(temp <
min_pbs_per_pup[if_id]
[pup]) ? temp :
min_pbs_per_pup
[if_id][pup];
result_all_bit[
bit + pup *
BUS_WIDTH_IN_BITS +
if_id * MAX_BUS_NUM *
BUS_WIDTH_IN_BITS] =
temp;
adll_shift_lock[if_id][pup] = 1;
}
}
}
}
/* Check all Pup state */
all_lock = 1;
for (pup = 0; pup < octets_per_if_num; pup++) {
/*
* DEBUG_PBS_ENGINE(DEBUG_LEVEL_INFO,
* ("pup_state[%d][%d] = %d\n",if_id,pup,pup_state
* [if_id][pup]));
*/
}
}
/* END OF SBA */
/* Norm */
for (pup = 0; pup < octets_per_if_num; pup++) {
VALIDATE_BUS_ACTIVE(tm->bus_act_mask, pup);
for (bit = 0; bit < BUS_WIDTH_IN_BITS; bit++) {
for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1;
if_id++) {
VALIDATE_IF_ACTIVE(tm->if_act_mask, if_id);
/* if pup not lock continue to next pup */
if (adll_shift_lock[if_id][pup] != 1) {
DEBUG_PBS_ENGINE(
DEBUG_LEVEL_ERROR,
("PBS failed for IF #%d\n",
if_id));
training_result[training_stage][if_id]
= TEST_FAILED;
result_mat[if_id][pup][bit] = 0;
max_pbs_per_pup[if_id][pup] = 0;
min_pbs_per_pup[if_id][pup] = 0;
} else {
training_result[
training_stage][if_id] =
(training_result[training_stage]
[if_id] == TEST_FAILED) ?
TEST_FAILED : TEST_SUCCESS;
result_mat[if_id][pup][bit] =
result_all_bit[
bit + pup *
BUS_WIDTH_IN_BITS +
if_id * MAX_BUS_NUM *
BUS_WIDTH_IN_BITS] -
min_pbs_per_pup[if_id][pup];
}
DEBUG_PBS_ENGINE(
DEBUG_LEVEL_INFO,
("The abs min_pbs[%d][%d] = %d\n",
if_id, pup,
min_pbs_per_pup[if_id][pup]));
}
}
}
/* Clean all results */
ddr3_tip_clean_pbs_result(dev_num, pbs_mode);
/* DQ PBS register update with the final result */
for (if_id = 0; if_id < MAX_INTERFACE_NUM; if_id++) {
VALIDATE_IF_ACTIVE(tm->if_act_mask, if_id);
for (pup = 0; pup < octets_per_if_num; pup++) {
VALIDATE_BUS_ACTIVE(tm->bus_act_mask, pup);
DEBUG_PBS_ENGINE(
DEBUG_LEVEL_INFO,
("Final Results: if_id %d, pup %d, Pup State: %d\n",
if_id, pup, pup_state[if_id][pup]));
for (bit = 0; bit < BUS_WIDTH_IN_BITS; bit++) {
if (dq_map_table == NULL) {
DEBUG_PBS_ENGINE(
DEBUG_LEVEL_ERROR,
("dq_map_table not initialized\n"));
return MV_FAIL;
}
pad_num = dq_map_table[
bit + pup * BUS_WIDTH_IN_BITS +
if_id * BUS_WIDTH_IN_BITS *
MAX_BUS_NUM];
DEBUG_PBS_ENGINE(DEBUG_LEVEL_INFO,
("result_mat: %d ",
result_mat[if_id][pup]
[bit]));
reg_addr = (pbs_mode == PBS_RX_MODE) ?
PBS_RX_PHY_REG(effective_cs, 0) :
PBS_TX_PHY_REG(effective_cs, 0);
CHECK_STATUS(ddr3_tip_bus_write
(dev_num, ACCESS_TYPE_UNICAST,
if_id, ACCESS_TYPE_UNICAST, pup,
DDR_PHY_DATA, reg_addr + pad_num,
result_mat[if_id][pup][bit]));
}
if (max_pbs_per_pup[if_id][pup] == min_pbs_per_pup[if_id][pup]) {
temp = TYPICAL_PBS_VALUE;
} else {
temp = ((max_adll_per_pup[if_id][pup] -
min_adll_per_pup[if_id][pup]) *
adll_tap /
(max_pbs_per_pup[if_id][pup] -
min_pbs_per_pup[if_id][pup]));
}
pbsdelay_per_pup[pbs_mode]
[if_id][pup][effective_cs] = temp;
/* RX results ready, write RX also */
if (pbs_mode == PBS_TX_MODE) {
/* Write TX results */
reg_addr = (0x14 + effective_cs * 0x10);
CHECK_STATUS(ddr3_tip_bus_write
(dev_num, ACCESS_TYPE_UNICAST,
if_id, ACCESS_TYPE_UNICAST, pup,
DDR_PHY_DATA, reg_addr,
(max_pbs_per_pup[if_id][pup] -
min_pbs_per_pup[if_id][pup]) /
2));
reg_addr = (0x15 + effective_cs * 0x10);
CHECK_STATUS(ddr3_tip_bus_write
(dev_num, ACCESS_TYPE_UNICAST,
if_id, ACCESS_TYPE_UNICAST, pup,
DDR_PHY_DATA, reg_addr,
(max_pbs_per_pup[if_id][pup] -
min_pbs_per_pup[if_id][pup]) /
2));
/* Write previously stored RX results */
reg_addr = (0x54 + effective_cs * 0x10);
CHECK_STATUS(ddr3_tip_bus_write
(dev_num, ACCESS_TYPE_UNICAST,
if_id, ACCESS_TYPE_UNICAST, pup,
DDR_PHY_DATA, reg_addr,
result_mat_rx_dqs[if_id][pup]
[effective_cs]));
reg_addr = (0x55 + effective_cs * 0x10);
CHECK_STATUS(ddr3_tip_bus_write
(dev_num, ACCESS_TYPE_UNICAST,
if_id, ACCESS_TYPE_UNICAST, pup,
DDR_PHY_DATA, reg_addr,
result_mat_rx_dqs[if_id][pup]
[effective_cs]));
} else {
/*
* RX results may affect RL results correctess,
* so just store the results that will written
* in TX stage
*/
result_mat_rx_dqs[if_id][pup][effective_cs] =
(max_pbs_per_pup[if_id][pup] -
min_pbs_per_pup[if_id][pup]) / 2;
}
DEBUG_PBS_ENGINE(
DEBUG_LEVEL_INFO,
(", PBS tap=%d [psec] ==> skew observed = %d\n",
temp,
((max_pbs_per_pup[if_id][pup] -
min_pbs_per_pup[if_id][pup]) *
temp)));
}
}
/* Write back to the phy the default values */
reg_addr = (pbs_mode == PBS_RX_MODE) ?
CRX_PHY_REG(effective_cs) :
CTX_PHY_REG(effective_cs);
ddr3_tip_write_adll_value(dev_num, nominal_adll, reg_addr);
for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
reg_addr = (pbs_mode == PBS_RX_MODE) ?
(0x5a + effective_cs * 0x10) :
(0x1a + effective_cs * 0x10);
CHECK_STATUS(ddr3_tip_bus_write
(dev_num, ACCESS_TYPE_UNICAST, if_id,
ACCESS_TYPE_UNICAST, pup, DDR_PHY_DATA, reg_addr,
0));
/* restore cs enable value */
VALIDATE_IF_ACTIVE(tm->if_act_mask, if_id);
CHECK_STATUS(ddr3_tip_if_write
(dev_num, ACCESS_TYPE_UNICAST, if_id,
DUAL_DUNIT_CFG_REG, cs_enable_reg_val[if_id],
MASK_ALL_BITS));
}
/* exit test mode */
CHECK_STATUS(ddr3_tip_if_write
(dev_num, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
ODPG_WR_RD_MODE_ENA_REG, 0xffff, MASK_ALL_BITS));
for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
VALIDATE_IF_ACTIVE(tm->if_act_mask, if_id);
for (pup = 0; pup < octets_per_if_num; pup++) {
VALIDATE_BUS_ACTIVE(tm->bus_act_mask, pup);
/*
* no valid window found
* (no lock at EBA ADLL shift at EBS)
*/
if (pup_state[if_id][pup] == 1)
return MV_FAIL;
}
}
return MV_OK;
}
/*
* Name: ddr3_tip_pbs_rx.
* Desc: PBS TX
* Args: TBD
* Notes:
* Returns: OK if success, other error code if fail.
*/
int ddr3_tip_pbs_rx(u32 uidev_num)
{
return ddr3_tip_pbs(uidev_num, PBS_RX_MODE);
}
/*
* Name: ddr3_tip_pbs_tx.
* Desc: PBS TX
* Args: TBD
* Notes:
* Returns: OK if success, other error code if fail.
*/
int ddr3_tip_pbs_tx(u32 uidev_num)
{
return ddr3_tip_pbs(uidev_num, PBS_TX_MODE);
}
#ifdef DDR_VIEWER_TOOL
/*
* Print PBS Result
*/
int ddr3_tip_print_all_pbs_result(u32 dev_num)
{
u32 curr_cs;
unsigned int max_cs = mv_ddr_cs_num_get();
for (curr_cs = 0; curr_cs < max_cs; curr_cs++) {
ddr3_tip_print_pbs_result(dev_num, curr_cs, PBS_RX_MODE);
ddr3_tip_print_pbs_result(dev_num, curr_cs, PBS_TX_MODE);
}
return MV_OK;
}
/*
* Print PBS Result
*/
int ddr3_tip_print_pbs_result(u32 dev_num, u32 cs_num, enum pbs_dir pbs_mode)
{
u32 data_value = 0, bit = 0, if_id = 0, pup = 0;
u32 reg_addr = (pbs_mode == PBS_RX_MODE) ?
PBS_RX_PHY_REG(cs_num, 0) :
PBS_TX_PHY_REG(cs_num , 0);
u32 octets_per_if_num = ddr3_tip_dev_attr_get(dev_num, MV_ATTR_OCTET_PER_INTERFACE);
struct mv_ddr_topology_map *tm = mv_ddr_topology_map_get();
printf("%s,CS%d,PBS,ADLLRATIO,,,",
(pbs_mode == PBS_RX_MODE) ? "Rx" : "Tx", cs_num);
for (if_id = 0; if_id < MAX_INTERFACE_NUM; if_id++) {
VALIDATE_IF_ACTIVE(tm->if_act_mask, if_id);
for (pup = 0; pup < octets_per_if_num; pup++) {
VALIDATE_BUS_ACTIVE(tm->bus_act_mask, pup);
printf("%d,",
pbsdelay_per_pup[pbs_mode][if_id][pup][cs_num]);
}
}
printf("CS%d, %s ,PBS\n", cs_num,
(pbs_mode == PBS_RX_MODE) ? "Rx" : "Tx");
for (bit = 0; bit < BUS_WIDTH_IN_BITS; bit++) {
printf("%s, DQ", (pbs_mode == PBS_RX_MODE) ? "Rx" : "Tx");
for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
VALIDATE_IF_ACTIVE(tm->if_act_mask, if_id);
printf("%d ,PBS,,, ", bit);
for (pup = 0; pup <= octets_per_if_num;
pup++) {
VALIDATE_BUS_ACTIVE(tm->bus_act_mask, pup);
CHECK_STATUS(ddr3_tip_bus_read
(dev_num, if_id,
ACCESS_TYPE_UNICAST, pup,
DDR_PHY_DATA, reg_addr + bit,
&data_value));
printf("%d , ", data_value);
}
}
printf("\n");
}
printf("\n");
return MV_OK;
}
#endif /* DDR_VIEWER_TOOL */
/*
* Fixup PBS Result
*/
int ddr3_tip_clean_pbs_result(u32 dev_num, enum pbs_dir pbs_mode)
{
u32 if_id, pup, bit;
u32 reg_addr = (pbs_mode == PBS_RX_MODE) ?
PBS_RX_PHY_REG(effective_cs, 0) :
PBS_TX_PHY_REG(effective_cs, 0);
u32 octets_per_if_num = ddr3_tip_dev_attr_get(dev_num, MV_ATTR_OCTET_PER_INTERFACE);
struct mv_ddr_topology_map *tm = mv_ddr_topology_map_get();
for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
VALIDATE_IF_ACTIVE(tm->if_act_mask, if_id);
for (pup = 0; pup <= octets_per_if_num; pup++) {
for (bit = 0; bit <= BUS_WIDTH_IN_BITS + 3; bit++) {
CHECK_STATUS(ddr3_tip_bus_write
(dev_num, ACCESS_TYPE_UNICAST,
if_id, ACCESS_TYPE_UNICAST, pup,
DDR_PHY_DATA, reg_addr + bit, 0));
}
}
}
return MV_OK;
}