183d290c5STom Rini // SPDX-License-Identifier: GPL-2.0
2f1df9364SStefan Roese /*
3f1df9364SStefan Roese  * Copyright (C) Marvell International Ltd. and its affiliates
4f1df9364SStefan Roese  */
5f1df9364SStefan Roese 
6f1df9364SStefan Roese #include "ddr3_init.h"
7*ebb1a593SChris Packham #include "mv_ddr_regs.h"
8f1df9364SStefan Roese 
9f1df9364SStefan Roese static u32 bist_offset = 32;
10f1df9364SStefan Roese enum hws_pattern sweep_pattern = PATTERN_KILLER_DQ0;
11f1df9364SStefan Roese 
12f1df9364SStefan Roese static int ddr3_tip_bist_operation(u32 dev_num,
13f1df9364SStefan Roese 				   enum hws_access_type access_type,
14f1df9364SStefan Roese 				   u32 if_id,
15f1df9364SStefan Roese 				   enum hws_bist_operation oper_type);
16f1df9364SStefan Roese 
17f1df9364SStefan Roese /*
18f1df9364SStefan Roese  * BIST activate
19f1df9364SStefan Roese  */
ddr3_tip_bist_activate(u32 dev_num,enum hws_pattern pattern,enum hws_access_type access_type,u32 if_num,enum hws_dir dir,enum hws_stress_jump addr_stress_jump,enum hws_pattern_duration duration,enum hws_bist_operation oper_type,u32 offset,u32 cs_num,u32 pattern_addr_length)20f1df9364SStefan Roese int ddr3_tip_bist_activate(u32 dev_num, enum hws_pattern pattern,
21f1df9364SStefan Roese 			   enum hws_access_type access_type, u32 if_num,
222b4ffbf6SChris Packham 			   enum hws_dir dir,
23f1df9364SStefan Roese 			   enum hws_stress_jump addr_stress_jump,
24f1df9364SStefan Roese 			   enum hws_pattern_duration duration,
25f1df9364SStefan Roese 			   enum hws_bist_operation oper_type,
26f1df9364SStefan Roese 			   u32 offset, u32 cs_num, u32 pattern_addr_length)
27f1df9364SStefan Roese {
28f1df9364SStefan Roese 	u32 tx_burst_size;
29f1df9364SStefan Roese 	u32 delay_between_burst;
302b4ffbf6SChris Packham 	u32 rd_mode;
31f1df9364SStefan Roese 	struct pattern_info *pattern_table = ddr3_tip_get_pattern_table();
32f1df9364SStefan Roese 
332b4ffbf6SChris Packham 	/* odpg bist write enable */
342b4ffbf6SChris Packham 	ddr3_tip_if_write(0, access_type, 0, ODPG_DATA_CTRL_REG,
352b4ffbf6SChris Packham 			  (ODPG_WRBUF_WR_CTRL_ENA << ODPG_WRBUF_WR_CTRL_OFFS),
362b4ffbf6SChris Packham 			  (ODPG_WRBUF_WR_CTRL_MASK << ODPG_WRBUF_WR_CTRL_OFFS));
37f1df9364SStefan Roese 
382b4ffbf6SChris Packham 	/* odpg bist read enable/disable */
392b4ffbf6SChris Packham 	ddr3_tip_if_write(0, access_type, 0, ODPG_DATA_CTRL_REG,
402b4ffbf6SChris Packham 			  (dir == OPER_READ) ? (ODPG_WRBUF_RD_CTRL_ENA << ODPG_WRBUF_RD_CTRL_OFFS) :
412b4ffbf6SChris Packham 					       (ODPG_WRBUF_RD_CTRL_DIS << ODPG_WRBUF_RD_CTRL_OFFS),
422b4ffbf6SChris Packham 			  (ODPG_WRBUF_RD_CTRL_MASK << ODPG_WRBUF_RD_CTRL_OFFS));
432b4ffbf6SChris Packham 
442b4ffbf6SChris Packham 	ddr3_tip_load_pattern_to_odpg(0, access_type, 0, pattern, offset);
452b4ffbf6SChris Packham 
462b4ffbf6SChris Packham 	ddr3_tip_if_write(0, access_type, 0, ODPG_DATA_BUFFER_SIZE_REG, pattern_addr_length, MASK_ALL_BITS);
472b4ffbf6SChris Packham 	tx_burst_size = (dir == OPER_WRITE) ?
48f1df9364SStefan Roese 		pattern_table[pattern].tx_burst_size : 0;
492b4ffbf6SChris Packham 	delay_between_burst = (dir == OPER_WRITE) ? 2 : 0;
502b4ffbf6SChris Packham 	rd_mode = (dir == OPER_WRITE) ? 1 : 0;
512b4ffbf6SChris Packham 	ddr3_tip_configure_odpg(0, access_type, 0, dir,
52f1df9364SStefan Roese 		      pattern_table[pattern].num_of_phases_tx, tx_burst_size,
53f1df9364SStefan Roese 		      pattern_table[pattern].num_of_phases_rx,
54f1df9364SStefan Roese 		      delay_between_burst,
552b4ffbf6SChris Packham 		      rd_mode, cs_num, addr_stress_jump, duration);
562b4ffbf6SChris Packham 	ddr3_tip_if_write(0, access_type, 0, ODPG_DATA_BUFFER_OFFS_REG, offset, MASK_ALL_BITS);
572b4ffbf6SChris Packham 
58f1df9364SStefan Roese 	if (oper_type == BIST_STOP) {
592b4ffbf6SChris Packham 		ddr3_tip_bist_operation(0, access_type, 0, BIST_STOP);
60f1df9364SStefan Roese 	} else {
612b4ffbf6SChris Packham 		ddr3_tip_bist_operation(0, access_type, 0, BIST_START);
622b4ffbf6SChris Packham 		if (mv_ddr_is_odpg_done(MAX_POLLING_ITERATIONS) != MV_OK)
63f1df9364SStefan Roese 			return MV_FAIL;
642b4ffbf6SChris Packham 		ddr3_tip_bist_operation(0, access_type, 0, BIST_STOP);
65f1df9364SStefan Roese 	}
662b4ffbf6SChris Packham 	ddr3_tip_if_write(0, access_type, 0, ODPG_DATA_CTRL_REG, 0, MASK_ALL_BITS);
67f1df9364SStefan Roese 
68f1df9364SStefan Roese 	return MV_OK;
69f1df9364SStefan Roese }
70f1df9364SStefan Roese 
71f1df9364SStefan Roese /*
72f1df9364SStefan Roese  * BIST read result
73f1df9364SStefan Roese  */
ddr3_tip_bist_read_result(u32 dev_num,u32 if_id,struct bist_result * pst_bist_result)74f1df9364SStefan Roese int ddr3_tip_bist_read_result(u32 dev_num, u32 if_id,
75f1df9364SStefan Roese 			      struct bist_result *pst_bist_result)
76f1df9364SStefan Roese {
77f1df9364SStefan Roese 	int ret;
78f1df9364SStefan Roese 	u32 read_data[MAX_INTERFACE_NUM];
792b4ffbf6SChris Packham 	struct mv_ddr_topology_map *tm = mv_ddr_topology_map_get();
80f1df9364SStefan Roese 
812b4ffbf6SChris Packham 	if (IS_IF_ACTIVE(tm->if_act_mask, if_id) == 0)
82f1df9364SStefan Roese 		return MV_NOT_SUPPORTED;
83f1df9364SStefan Roese 	DEBUG_TRAINING_BIST_ENGINE(DEBUG_LEVEL_TRACE,
84f1df9364SStefan Roese 				   ("ddr3_tip_bist_read_result if_id %d\n",
85f1df9364SStefan Roese 				    if_id));
86f1df9364SStefan Roese 	ret = ddr3_tip_if_read(dev_num, ACCESS_TYPE_UNICAST, if_id,
872b4ffbf6SChris Packham 			       ODPG_DATA_RX_WORD_ERR_DATA_HIGH_REG, read_data,
88f1df9364SStefan Roese 			       MASK_ALL_BITS);
89f1df9364SStefan Roese 	if (ret != MV_OK)
90f1df9364SStefan Roese 		return ret;
91f1df9364SStefan Roese 	pst_bist_result->bist_fail_high = read_data[if_id];
92f1df9364SStefan Roese 	ret = ddr3_tip_if_read(dev_num, ACCESS_TYPE_UNICAST, if_id,
932b4ffbf6SChris Packham 			       ODPG_DATA_RX_WORD_ERR_DATA_LOW_REG, read_data,
94f1df9364SStefan Roese 			       MASK_ALL_BITS);
95f1df9364SStefan Roese 	if (ret != MV_OK)
96f1df9364SStefan Roese 		return ret;
97f1df9364SStefan Roese 	pst_bist_result->bist_fail_low = read_data[if_id];
98f1df9364SStefan Roese 
99f1df9364SStefan Roese 	ret = ddr3_tip_if_read(dev_num, ACCESS_TYPE_UNICAST, if_id,
1002b4ffbf6SChris Packham 			       ODPG_DATA_RX_WORD_ERR_ADDR_REG, read_data,
101f1df9364SStefan Roese 			       MASK_ALL_BITS);
102f1df9364SStefan Roese 	if (ret != MV_OK)
103f1df9364SStefan Roese 		return ret;
104f1df9364SStefan Roese 	pst_bist_result->bist_last_fail_addr = read_data[if_id];
105f1df9364SStefan Roese 	ret = ddr3_tip_if_read(dev_num, ACCESS_TYPE_UNICAST, if_id,
1062b4ffbf6SChris Packham 			       ODPG_DATA_RX_WORD_ERR_CNTR_REG, read_data,
107f1df9364SStefan Roese 			       MASK_ALL_BITS);
108f1df9364SStefan Roese 	if (ret != MV_OK)
109f1df9364SStefan Roese 		return ret;
110f1df9364SStefan Roese 	pst_bist_result->bist_error_cnt = read_data[if_id];
111f1df9364SStefan Roese 
112f1df9364SStefan Roese 	return MV_OK;
113f1df9364SStefan Roese }
114f1df9364SStefan Roese 
115f1df9364SStefan Roese /*
116f1df9364SStefan Roese  * BIST flow - Activate & read result
117f1df9364SStefan Roese  */
hws_ddr3_run_bist(u32 dev_num,enum hws_pattern pattern,u32 * result,u32 cs_num)118f1df9364SStefan Roese int hws_ddr3_run_bist(u32 dev_num, enum hws_pattern pattern, u32 *result,
119f1df9364SStefan Roese 		      u32 cs_num)
120f1df9364SStefan Roese {
121f1df9364SStefan Roese 	int ret;
122f1df9364SStefan Roese 	u32 i = 0;
123f1df9364SStefan Roese 	u32 win_base;
124f1df9364SStefan Roese 	struct bist_result st_bist_result;
1252b4ffbf6SChris Packham 	struct mv_ddr_topology_map *tm = mv_ddr_topology_map_get();
126f1df9364SStefan Roese 
127f1df9364SStefan Roese 	for (i = 0; i < MAX_INTERFACE_NUM; i++) {
1282b4ffbf6SChris Packham 		VALIDATE_IF_ACTIVE(tm->if_act_mask, i);
129f1df9364SStefan Roese 		hws_ddr3_cs_base_adr_calc(i, cs_num, &win_base);
130f1df9364SStefan Roese 		ret = ddr3_tip_bist_activate(dev_num, pattern,
131f1df9364SStefan Roese 					     ACCESS_TYPE_UNICAST,
132f1df9364SStefan Roese 					     i, OPER_WRITE, STRESS_NONE,
133f1df9364SStefan Roese 					     DURATION_SINGLE, BIST_START,
134f1df9364SStefan Roese 					     bist_offset + win_base,
135f1df9364SStefan Roese 					     cs_num, 15);
136f1df9364SStefan Roese 		if (ret != MV_OK) {
137f1df9364SStefan Roese 			printf("ddr3_tip_bist_activate failed (0x%x)\n", ret);
138f1df9364SStefan Roese 			return ret;
139f1df9364SStefan Roese 		}
140f1df9364SStefan Roese 
141f1df9364SStefan Roese 		ret = ddr3_tip_bist_activate(dev_num, pattern,
142f1df9364SStefan Roese 					     ACCESS_TYPE_UNICAST,
143f1df9364SStefan Roese 					     i, OPER_READ, STRESS_NONE,
144f1df9364SStefan Roese 					     DURATION_SINGLE, BIST_START,
145f1df9364SStefan Roese 					     bist_offset + win_base,
146f1df9364SStefan Roese 					     cs_num, 15);
147f1df9364SStefan Roese 		if (ret != MV_OK) {
148f1df9364SStefan Roese 			printf("ddr3_tip_bist_activate failed (0x%x)\n", ret);
149f1df9364SStefan Roese 			return ret;
150f1df9364SStefan Roese 		}
151f1df9364SStefan Roese 
152f1df9364SStefan Roese 		ret = ddr3_tip_bist_read_result(dev_num, i, &st_bist_result);
153f1df9364SStefan Roese 		if (ret != MV_OK) {
154f1df9364SStefan Roese 			printf("ddr3_tip_bist_read_result failed\n");
155f1df9364SStefan Roese 			return ret;
156f1df9364SStefan Roese 		}
157f1df9364SStefan Roese 		result[i] = st_bist_result.bist_error_cnt;
158f1df9364SStefan Roese 	}
159f1df9364SStefan Roese 
160f1df9364SStefan Roese 	return MV_OK;
161f1df9364SStefan Roese }
162f1df9364SStefan Roese 
163f1df9364SStefan Roese /*
164f1df9364SStefan Roese  * Set BIST Operation
165f1df9364SStefan Roese  */
166f1df9364SStefan Roese 
ddr3_tip_bist_operation(u32 dev_num,enum hws_access_type access_type,u32 if_id,enum hws_bist_operation oper_type)167f1df9364SStefan Roese static int ddr3_tip_bist_operation(u32 dev_num,
168f1df9364SStefan Roese 				   enum hws_access_type access_type,
169f1df9364SStefan Roese 				   u32 if_id, enum hws_bist_operation oper_type)
170f1df9364SStefan Roese {
1712b4ffbf6SChris Packham 	if (oper_type == BIST_STOP)
1722b4ffbf6SChris Packham 		mv_ddr_odpg_disable();
1732b4ffbf6SChris Packham 	else
1742b4ffbf6SChris Packham 		mv_ddr_odpg_enable();
175f1df9364SStefan Roese 
176f1df9364SStefan Roese 	return MV_OK;
177f1df9364SStefan Roese }
178f1df9364SStefan Roese 
179f1df9364SStefan Roese /*
180f1df9364SStefan Roese  * Print BIST result
181f1df9364SStefan Roese  */
ddr3_tip_print_bist_res(void)182f1df9364SStefan Roese void ddr3_tip_print_bist_res(void)
183f1df9364SStefan Roese {
184f1df9364SStefan Roese 	u32 dev_num = 0;
185f1df9364SStefan Roese 	u32 i;
186f1df9364SStefan Roese 	struct bist_result st_bist_result[MAX_INTERFACE_NUM];
187f1df9364SStefan Roese 	int res;
1882b4ffbf6SChris Packham 	struct mv_ddr_topology_map *tm = mv_ddr_topology_map_get();
189f1df9364SStefan Roese 
190f1df9364SStefan Roese 	for (i = 0; i < MAX_INTERFACE_NUM; i++) {
1912b4ffbf6SChris Packham 		VALIDATE_IF_ACTIVE(tm->if_act_mask, i);
192f1df9364SStefan Roese 
193f1df9364SStefan Roese 		res = ddr3_tip_bist_read_result(dev_num, i, &st_bist_result[i]);
194f1df9364SStefan Roese 		if (res != MV_OK) {
195f1df9364SStefan Roese 			DEBUG_TRAINING_BIST_ENGINE(
196f1df9364SStefan Roese 				DEBUG_LEVEL_ERROR,
197f1df9364SStefan Roese 				("ddr3_tip_bist_read_result failed\n"));
198f1df9364SStefan Roese 			return;
199f1df9364SStefan Roese 		}
200f1df9364SStefan Roese 	}
201f1df9364SStefan Roese 
202f1df9364SStefan Roese 	DEBUG_TRAINING_BIST_ENGINE(
203f1df9364SStefan Roese 		DEBUG_LEVEL_INFO,
204f1df9364SStefan Roese 		("interface | error_cnt | fail_low | fail_high | fail_addr\n"));
205f1df9364SStefan Roese 
206f1df9364SStefan Roese 	for (i = 0; i < MAX_INTERFACE_NUM; i++) {
2072b4ffbf6SChris Packham 		VALIDATE_IF_ACTIVE(tm->if_act_mask, i);
208f1df9364SStefan Roese 
209f1df9364SStefan Roese 		DEBUG_TRAINING_BIST_ENGINE(
210f1df9364SStefan Roese 			DEBUG_LEVEL_INFO,
211f1df9364SStefan Roese 			("%d |  0x%08x  |  0x%08x  |  0x%08x  | 0x%08x\n",
212f1df9364SStefan Roese 			 i, st_bist_result[i].bist_error_cnt,
213f1df9364SStefan Roese 			 st_bist_result[i].bist_fail_low,
214f1df9364SStefan Roese 			 st_bist_result[i].bist_fail_high,
215f1df9364SStefan Roese 			 st_bist_result[i].bist_last_fail_addr));
216f1df9364SStefan Roese 	}
217f1df9364SStefan Roese }
2182b4ffbf6SChris Packham 
2192b4ffbf6SChris Packham enum {
2202b4ffbf6SChris Packham 	PASS,
2212b4ffbf6SChris Packham 	FAIL
2222b4ffbf6SChris Packham };
2232b4ffbf6SChris Packham #define TIP_ITERATION_NUM	31
mv_ddr_tip_bist(enum hws_dir dir,u32 val,enum hws_pattern pattern,u32 cs,u32 * result)2242b4ffbf6SChris Packham static int mv_ddr_tip_bist(enum hws_dir dir, u32 val, enum hws_pattern pattern, u32 cs, u32 *result)
2252b4ffbf6SChris Packham {
2262b4ffbf6SChris Packham 	struct mv_ddr_topology_map *tm = mv_ddr_topology_map_get();
2272b4ffbf6SChris Packham 	enum hws_training_ip_stat training_result;
2282b4ffbf6SChris Packham 	u16 *reg_map = ddr3_tip_get_mask_results_pup_reg_map();
2292b4ffbf6SChris Packham 	u32 max_subphy = ddr3_tip_dev_attr_get(0, MV_ATTR_OCTET_PER_INTERFACE);
2302b4ffbf6SChris Packham 	u32 subphy, read_data;
2312b4ffbf6SChris Packham 
2322b4ffbf6SChris Packham 	ddr3_tip_ip_training(0, ACCESS_TYPE_MULTICAST, 0, ACCESS_TYPE_MULTICAST, PARAM_NOT_CARE,
2332b4ffbf6SChris Packham 			     RESULT_PER_BYTE, HWS_CONTROL_ELEMENT_ADLL, HWS_LOW2HIGH, dir, tm->if_act_mask, val,
2342b4ffbf6SChris Packham 			     TIP_ITERATION_NUM, pattern, EDGE_FP, CS_SINGLE, cs, &training_result);
2352b4ffbf6SChris Packham 
2362b4ffbf6SChris Packham 	for (subphy = 0; subphy < max_subphy; subphy++) {
2372b4ffbf6SChris Packham 		ddr3_tip_if_read(0, ACCESS_TYPE_UNICAST, 0, reg_map[subphy], &read_data, MASK_ALL_BITS);
2382b4ffbf6SChris Packham 		if (((read_data >> BLOCK_STATUS_OFFS) & BLOCK_STATUS_MASK) == BLOCK_STATUS_NOT_LOCKED)
2392b4ffbf6SChris Packham 			*result |= (FAIL << subphy);
2402b4ffbf6SChris Packham 	}
2412b4ffbf6SChris Packham 
2422b4ffbf6SChris Packham 	return MV_OK;
2432b4ffbf6SChris Packham }
2442b4ffbf6SChris Packham 
2452b4ffbf6SChris Packham struct interval {
2462b4ffbf6SChris Packham 	u8 *vector;
2472b4ffbf6SChris Packham 	u8 lendpnt;		/* interval's left endpoint */
2482b4ffbf6SChris Packham 	u8 rendpnt;		/* interval's right endpoint */
2492b4ffbf6SChris Packham 	u8 size;		/* interval's size */
2502b4ffbf6SChris Packham 	u8 lmarker;		/* left marker */
2512b4ffbf6SChris Packham 	u8 rmarker;		/* right marker */
2522b4ffbf6SChris Packham 	u8 pass_lendpnt;	/* left endpoint of internal pass interval */
2532b4ffbf6SChris Packham 	u8 pass_rendpnt;	/* right endpoint of internal pass interval */
2542b4ffbf6SChris Packham };
2552b4ffbf6SChris Packham 
interval_init(u8 * vector,u8 lendpnt,u8 rendpnt,u8 lmarker,u8 rmarker,struct interval * intrvl)2562b4ffbf6SChris Packham static int interval_init(u8 *vector, u8 lendpnt, u8 rendpnt,
2572b4ffbf6SChris Packham 			 u8 lmarker, u8 rmarker, struct interval *intrvl)
2582b4ffbf6SChris Packham {
2592b4ffbf6SChris Packham 	if (intrvl == NULL) {
2602b4ffbf6SChris Packham 		printf("%s: NULL intrvl pointer found\n", __func__);
2612b4ffbf6SChris Packham 		return MV_FAIL;
2622b4ffbf6SChris Packham 	}
2632b4ffbf6SChris Packham 
2642b4ffbf6SChris Packham 	if (vector == NULL) {
2652b4ffbf6SChris Packham 		printf("%s: NULL vector pointer found\n", __func__);
2662b4ffbf6SChris Packham 		return MV_FAIL;
2672b4ffbf6SChris Packham 	}
2682b4ffbf6SChris Packham 	intrvl->vector = vector;
2692b4ffbf6SChris Packham 
2702b4ffbf6SChris Packham 	if (lendpnt >= rendpnt) {
2712b4ffbf6SChris Packham 		printf("%s: incorrect lendpnt and/or rendpnt parameters found\n", __func__);
2722b4ffbf6SChris Packham 		return MV_FAIL;
2732b4ffbf6SChris Packham 	}
2742b4ffbf6SChris Packham 	intrvl->lendpnt = lendpnt;
2752b4ffbf6SChris Packham 	intrvl->rendpnt = rendpnt;
2762b4ffbf6SChris Packham 	intrvl->size = rendpnt - lendpnt + 1;
2772b4ffbf6SChris Packham 
2782b4ffbf6SChris Packham 	if ((lmarker < lendpnt) || (lmarker > rendpnt)) {
2792b4ffbf6SChris Packham 		printf("%s: incorrect lmarker parameter found\n", __func__);
2802b4ffbf6SChris Packham 		return MV_FAIL;
2812b4ffbf6SChris Packham 	}
2822b4ffbf6SChris Packham 	intrvl->lmarker = lmarker;
2832b4ffbf6SChris Packham 
2842b4ffbf6SChris Packham 	if ((rmarker < lmarker) || (rmarker > (intrvl->rendpnt + intrvl->size))) {
2852b4ffbf6SChris Packham 		printf("%s: incorrect rmarker parameter found\n", __func__);
2862b4ffbf6SChris Packham 		return MV_FAIL;
2872b4ffbf6SChris Packham 	}
2882b4ffbf6SChris Packham 	intrvl->rmarker = rmarker;
2892b4ffbf6SChris Packham 
2902b4ffbf6SChris Packham 	return MV_OK;
2912b4ffbf6SChris Packham }
interval_set(u8 pass_lendpnt,u8 pass_rendpnt,struct interval * intrvl)2922b4ffbf6SChris Packham static int interval_set(u8 pass_lendpnt, u8 pass_rendpnt, struct interval *intrvl)
2932b4ffbf6SChris Packham {
2942b4ffbf6SChris Packham 	if (intrvl == NULL) {
2952b4ffbf6SChris Packham 		printf("%s: NULL intrvl pointer found\n", __func__);
2962b4ffbf6SChris Packham 		return MV_FAIL;
2972b4ffbf6SChris Packham 	}
2982b4ffbf6SChris Packham 
2992b4ffbf6SChris Packham 	intrvl->pass_lendpnt = pass_lendpnt;
3002b4ffbf6SChris Packham 	intrvl->pass_rendpnt = pass_rendpnt;
3012b4ffbf6SChris Packham 
3022b4ffbf6SChris Packham 	return MV_OK;
3032b4ffbf6SChris Packham }
3042b4ffbf6SChris Packham 
interval_proc(struct interval * intrvl)3052b4ffbf6SChris Packham static int interval_proc(struct interval *intrvl)
3062b4ffbf6SChris Packham {
3072b4ffbf6SChris Packham 	int curr;
3082b4ffbf6SChris Packham 	int pass_lendpnt, pass_rendpnt;
3092b4ffbf6SChris Packham 	int lmt;
3102b4ffbf6SChris Packham 	int fcnt = 0, pcnt = 0;
3112b4ffbf6SChris Packham 
3122b4ffbf6SChris Packham 	if (intrvl == NULL) {
3132b4ffbf6SChris Packham 		printf("%s: NULL intrvl pointer found\n", __func__);
3142b4ffbf6SChris Packham 		return MV_FAIL;
3152b4ffbf6SChris Packham 	}
3162b4ffbf6SChris Packham 
3172b4ffbf6SChris Packham 	/* count fails and passes */
3182b4ffbf6SChris Packham 	curr = intrvl->lendpnt;
3192b4ffbf6SChris Packham 	while (curr <= intrvl->rendpnt) {
3202b4ffbf6SChris Packham 		if (intrvl->vector[curr] == PASS)
3212b4ffbf6SChris Packham 			pcnt++;
3222b4ffbf6SChris Packham 		else
3232b4ffbf6SChris Packham 			fcnt++;
3242b4ffbf6SChris Packham 		curr++;
3252b4ffbf6SChris Packham 	}
3262b4ffbf6SChris Packham 
3272b4ffbf6SChris Packham 	/* check for all fail */
3282b4ffbf6SChris Packham 	if (fcnt == intrvl->size) {
3292b4ffbf6SChris Packham 		printf("%s: no pass found\n", __func__);
3302b4ffbf6SChris Packham 		return MV_FAIL;
3312b4ffbf6SChris Packham 	}
3322b4ffbf6SChris Packham 
3332b4ffbf6SChris Packham 	/* check for all pass */
3342b4ffbf6SChris Packham 	if (pcnt == intrvl->size) {
3352b4ffbf6SChris Packham 		if (interval_set(intrvl->lendpnt, intrvl->rendpnt, intrvl) != MV_OK)
3362b4ffbf6SChris Packham 			return MV_FAIL;
3372b4ffbf6SChris Packham 		return MV_OK;
3382b4ffbf6SChris Packham 	}
3392b4ffbf6SChris Packham 
3402b4ffbf6SChris Packham 	/* proceed with rmarker */
3412b4ffbf6SChris Packham 	curr = intrvl->rmarker;
3422b4ffbf6SChris Packham 	if (intrvl->vector[curr % intrvl->size] == PASS) { /* pass at rmarker */
3432b4ffbf6SChris Packham 		/* search for fail on right */
3442b4ffbf6SChris Packham 		if (intrvl->rmarker > intrvl->rendpnt)
3452b4ffbf6SChris Packham 			lmt = intrvl->rendpnt + intrvl->size;
3462b4ffbf6SChris Packham 		else
3472b4ffbf6SChris Packham 			lmt = intrvl->rmarker + intrvl->size - 1;
3482b4ffbf6SChris Packham 		while ((curr <= lmt) &&
3492b4ffbf6SChris Packham 		       (intrvl->vector[curr % intrvl->size] == PASS))
3502b4ffbf6SChris Packham 			curr++;
3512b4ffbf6SChris Packham 		if (curr > lmt) { /* fail not found */
3522b4ffbf6SChris Packham 			printf("%s: rmarker: fail following pass not found\n", __func__);
3532b4ffbf6SChris Packham 			return MV_FAIL;
3542b4ffbf6SChris Packham 		}
3552b4ffbf6SChris Packham 		/* fail found */
3562b4ffbf6SChris Packham 		pass_rendpnt = curr - 1;
3572b4ffbf6SChris Packham 	} else { /* fail at rmarker */
3582b4ffbf6SChris Packham 		/* search for pass on left */
3592b4ffbf6SChris Packham 		if (intrvl->rmarker > intrvl->rendpnt)
3602b4ffbf6SChris Packham 			lmt = intrvl->rmarker - intrvl->size + 1;
3612b4ffbf6SChris Packham 		else
3622b4ffbf6SChris Packham 			lmt = intrvl->lendpnt;
3632b4ffbf6SChris Packham 		while ((curr >= lmt) &&
3642b4ffbf6SChris Packham 		       (intrvl->vector[curr % intrvl->size] == FAIL))
3652b4ffbf6SChris Packham 			curr--;
3662b4ffbf6SChris Packham 		if (curr < lmt) { /* pass not found */
3672b4ffbf6SChris Packham 			printf("%s: rmarker: pass preceding fail not found\n", __func__);
3682b4ffbf6SChris Packham 			return MV_FAIL;
3692b4ffbf6SChris Packham 		}
3702b4ffbf6SChris Packham 		/* pass found */
3712b4ffbf6SChris Packham 		pass_rendpnt = curr;
3722b4ffbf6SChris Packham 	}
3732b4ffbf6SChris Packham 
3742b4ffbf6SChris Packham 	/* search for fail on left */
3752b4ffbf6SChris Packham 	curr = pass_rendpnt;
3762b4ffbf6SChris Packham 	if (pass_rendpnt > intrvl->rendpnt)
3772b4ffbf6SChris Packham 		lmt =  pass_rendpnt - intrvl->size + 1;
3782b4ffbf6SChris Packham 	else
3792b4ffbf6SChris Packham 		lmt = intrvl->lendpnt;
3802b4ffbf6SChris Packham 	while ((curr >= lmt) &&
3812b4ffbf6SChris Packham 	       (intrvl->vector[curr % intrvl->size] == PASS))
3822b4ffbf6SChris Packham 		curr--;
3832b4ffbf6SChris Packham 	if (curr < lmt) { /* fail not found */
3842b4ffbf6SChris Packham 		printf("%s: rmarker: fail preceding pass not found\n", __func__);
3852b4ffbf6SChris Packham 		return MV_FAIL;
3862b4ffbf6SChris Packham 	}
3872b4ffbf6SChris Packham 	/* fail found */
3882b4ffbf6SChris Packham 	pass_lendpnt = curr + 1;
3892b4ffbf6SChris Packham 	if (interval_set(pass_lendpnt, pass_rendpnt, intrvl) != MV_OK)
3902b4ffbf6SChris Packham 		return MV_FAIL;
3912b4ffbf6SChris Packham 
3922b4ffbf6SChris Packham 	return MV_OK;
3932b4ffbf6SChris Packham }
3942b4ffbf6SChris Packham 
3952b4ffbf6SChris Packham #define ADLL_TAPS_PER_PERIOD	64
mv_ddr_dm_to_dq_diff_get(u8 vw_sphy_hi_lmt,u8 vw_sphy_lo_lmt,u8 * vw_vector,int * vw_sphy_hi_diff,int * vw_sphy_lo_diff)3962b4ffbf6SChris Packham int mv_ddr_dm_to_dq_diff_get(u8 vw_sphy_hi_lmt, u8 vw_sphy_lo_lmt, u8 *vw_vector,
3972b4ffbf6SChris Packham 			     int *vw_sphy_hi_diff, int *vw_sphy_lo_diff)
3982b4ffbf6SChris Packham {
3992b4ffbf6SChris Packham 	struct interval intrvl;
4002b4ffbf6SChris Packham 
4012b4ffbf6SChris Packham 	/* init interval structure */
4022b4ffbf6SChris Packham 	if (interval_init(vw_vector, 0, ADLL_TAPS_PER_PERIOD - 1,
4032b4ffbf6SChris Packham 			  vw_sphy_lo_lmt, vw_sphy_hi_lmt, &intrvl) != MV_OK)
4042b4ffbf6SChris Packham 		return MV_FAIL;
4052b4ffbf6SChris Packham 
4062b4ffbf6SChris Packham 	/* find pass sub-interval */
4072b4ffbf6SChris Packham 	if (interval_proc(&intrvl) != MV_OK)
4082b4ffbf6SChris Packham 		return MV_FAIL;
4092b4ffbf6SChris Packham 
4102b4ffbf6SChris Packham 	/* check for all pass */
4112b4ffbf6SChris Packham 	if ((intrvl.pass_rendpnt == intrvl.rendpnt) &&
4122b4ffbf6SChris Packham 	    (intrvl.pass_lendpnt == intrvl.lendpnt)) {
4132b4ffbf6SChris Packham 		printf("%s: no fail found\n", __func__);
4142b4ffbf6SChris Packham 		return MV_FAIL;
4152b4ffbf6SChris Packham 	}
4162b4ffbf6SChris Packham 
4172b4ffbf6SChris Packham 	*vw_sphy_hi_diff = intrvl.pass_rendpnt - vw_sphy_hi_lmt;
4182b4ffbf6SChris Packham 	*vw_sphy_lo_diff = vw_sphy_lo_lmt - intrvl.pass_lendpnt;
4192b4ffbf6SChris Packham 
4202b4ffbf6SChris Packham 	return MV_OK;
4212b4ffbf6SChris Packham }
4222b4ffbf6SChris Packham 
mv_ddr_bist_tx(enum hws_access_type access_type)4232b4ffbf6SChris Packham static int mv_ddr_bist_tx(enum hws_access_type access_type)
4242b4ffbf6SChris Packham {
4252b4ffbf6SChris Packham 	mv_ddr_odpg_done_clr();
4262b4ffbf6SChris Packham 
4272b4ffbf6SChris Packham 	ddr3_tip_bist_operation(0, access_type, 0, BIST_START);
4282b4ffbf6SChris Packham 
4292b4ffbf6SChris Packham 	if (mv_ddr_is_odpg_done(MAX_POLLING_ITERATIONS) != MV_OK)
4302b4ffbf6SChris Packham 		return MV_FAIL;
4312b4ffbf6SChris Packham 
4322b4ffbf6SChris Packham 	ddr3_tip_bist_operation(0, access_type, 0, BIST_STOP);
4332b4ffbf6SChris Packham 
4342b4ffbf6SChris Packham 	ddr3_tip_if_write(0, access_type, 0, ODPG_DATA_CTRL_REG, 0, MASK_ALL_BITS);
4352b4ffbf6SChris Packham 
4362b4ffbf6SChris Packham 	return MV_OK;
4372b4ffbf6SChris Packham }
4382b4ffbf6SChris Packham 
4392b4ffbf6SChris Packham /* prepare odpg for bist operation */
4402b4ffbf6SChris Packham #define WR_OP_ODPG_DATA_CMD_BURST_DLY	2
mv_ddr_odpg_bist_prepare(enum hws_pattern pattern,enum hws_access_type access_type,enum hws_dir dir,enum hws_stress_jump stress_jump_addr,enum hws_pattern_duration duration,u32 offset,u32 cs,u32 pattern_addr_len,enum dm_direction dm_dir)4412b4ffbf6SChris Packham static int mv_ddr_odpg_bist_prepare(enum hws_pattern pattern, enum hws_access_type access_type,
4422b4ffbf6SChris Packham 			     enum hws_dir dir, enum hws_stress_jump stress_jump_addr,
4432b4ffbf6SChris Packham 			     enum hws_pattern_duration duration, u32 offset, u32 cs,
4442b4ffbf6SChris Packham 			     u32 pattern_addr_len, enum dm_direction dm_dir)
4452b4ffbf6SChris Packham {
4462b4ffbf6SChris Packham 	struct pattern_info *pattern_table = ddr3_tip_get_pattern_table();
4472b4ffbf6SChris Packham 	u32 tx_burst_size;
4482b4ffbf6SChris Packham 	u32 burst_delay;
4492b4ffbf6SChris Packham 	u32 rd_mode;
4502b4ffbf6SChris Packham 
4512b4ffbf6SChris Packham 	/* odpg bist write enable */
4522b4ffbf6SChris Packham 	ddr3_tip_if_write(0, access_type, 0, ODPG_DATA_CTRL_REG,
4532b4ffbf6SChris Packham 			  (ODPG_WRBUF_WR_CTRL_ENA << ODPG_WRBUF_WR_CTRL_OFFS),
4542b4ffbf6SChris Packham 			  (ODPG_WRBUF_WR_CTRL_MASK << ODPG_WRBUF_WR_CTRL_OFFS));
4552b4ffbf6SChris Packham 
4562b4ffbf6SChris Packham 	/* odpg bist read enable/disable */
4572b4ffbf6SChris Packham 	ddr3_tip_if_write(0, access_type, 0, ODPG_DATA_CTRL_REG,
4582b4ffbf6SChris Packham 			  (dir == OPER_READ) ? (ODPG_WRBUF_RD_CTRL_ENA << ODPG_WRBUF_RD_CTRL_OFFS) :
4592b4ffbf6SChris Packham 					       (ODPG_WRBUF_RD_CTRL_DIS << ODPG_WRBUF_RD_CTRL_OFFS),
4602b4ffbf6SChris Packham 			  (ODPG_WRBUF_RD_CTRL_MASK << ODPG_WRBUF_RD_CTRL_OFFS));
4612b4ffbf6SChris Packham 
4622b4ffbf6SChris Packham 	if (pattern == PATTERN_00 || pattern == PATTERN_FF)
4632b4ffbf6SChris Packham 		ddr3_tip_load_pattern_to_odpg(0, access_type, 0, pattern, offset);
4642b4ffbf6SChris Packham 	else
4652b4ffbf6SChris Packham 		mv_ddr_load_dm_pattern_to_odpg(access_type, pattern, dm_dir);
4662b4ffbf6SChris Packham 
4672b4ffbf6SChris Packham 	ddr3_tip_if_write(0, access_type, 0, ODPG_DATA_BUFFER_SIZE_REG, pattern_addr_len, MASK_ALL_BITS);
4682b4ffbf6SChris Packham 	if (dir == OPER_WRITE) {
4692b4ffbf6SChris Packham 		tx_burst_size = pattern_table[pattern].tx_burst_size;
4702b4ffbf6SChris Packham 		burst_delay = WR_OP_ODPG_DATA_CMD_BURST_DLY;
4712b4ffbf6SChris Packham 		rd_mode = ODPG_MODE_TX;
4722b4ffbf6SChris Packham 	} else {
4732b4ffbf6SChris Packham 		tx_burst_size = 0;
4742b4ffbf6SChris Packham 		burst_delay = 0;
4752b4ffbf6SChris Packham 		rd_mode = ODPG_MODE_RX;
4762b4ffbf6SChris Packham 	}
4772b4ffbf6SChris Packham 	ddr3_tip_configure_odpg(0, access_type, 0, dir, pattern_table[pattern].num_of_phases_tx,
4782b4ffbf6SChris Packham 				tx_burst_size, pattern_table[pattern].num_of_phases_rx, burst_delay,
4792b4ffbf6SChris Packham 				rd_mode, cs, stress_jump_addr, duration);
4802b4ffbf6SChris Packham 
4812b4ffbf6SChris Packham 	return MV_OK;
4822b4ffbf6SChris Packham }
4832b4ffbf6SChris Packham 
4842b4ffbf6SChris Packham #define BYTES_PER_BURST_64BIT	0x20
4852b4ffbf6SChris Packham #define BYTES_PER_BURST_32BIT	0x10
mv_ddr_dm_vw_get(enum hws_pattern pattern,u32 cs,u8 * vw_vector)4862b4ffbf6SChris Packham int mv_ddr_dm_vw_get(enum hws_pattern pattern, u32 cs, u8 *vw_vector)
4872b4ffbf6SChris Packham {
4882b4ffbf6SChris Packham 	struct mv_ddr_topology_map *tm = mv_ddr_topology_map_get();
4892b4ffbf6SChris Packham 	struct pattern_info *pattern_table = ddr3_tip_get_pattern_table();
4902b4ffbf6SChris Packham 	u32 adll_tap;
4912b4ffbf6SChris Packham 	u32 wr_ctrl_adll[MAX_BUS_NUM] = {0};
4922b4ffbf6SChris Packham 	u32 rd_ctrl_adll[MAX_BUS_NUM] = {0};
4932b4ffbf6SChris Packham 	u32 subphy;
4942b4ffbf6SChris Packham 	u32 subphy_max = ddr3_tip_dev_attr_get(0, MV_ATTR_OCTET_PER_INTERFACE);
4952b4ffbf6SChris Packham 	u32 odpg_addr = 0x0;
4962b4ffbf6SChris Packham 	u32 result;
4972b4ffbf6SChris Packham 	u32 idx;
4982b4ffbf6SChris Packham 	/* burst length in bytes */
4992b4ffbf6SChris Packham 	u32 burst_len = (MV_DDR_IS_64BIT_DRAM_MODE(tm->bus_act_mask) ?
5002b4ffbf6SChris Packham 			BYTES_PER_BURST_64BIT : BYTES_PER_BURST_32BIT);
5012b4ffbf6SChris Packham 
5022b4ffbf6SChris Packham 	/* save dqs values to restore after algorithm's run */
5032b4ffbf6SChris Packham 	ddr3_tip_read_adll_value(0, wr_ctrl_adll, CTX_PHY_REG(cs), MASK_ALL_BITS);
5042b4ffbf6SChris Packham 	ddr3_tip_read_adll_value(0, rd_ctrl_adll, CRX_PHY_REG(cs), MASK_ALL_BITS);
5052b4ffbf6SChris Packham 
5062b4ffbf6SChris Packham 	/* fill memory with base pattern */
5072b4ffbf6SChris Packham 	ddr3_tip_if_write(0, ACCESS_TYPE_UNICAST, 0, ODPG_DATA_CTRL_REG, 0, MASK_ALL_BITS);
5082b4ffbf6SChris Packham 	mv_ddr_odpg_bist_prepare(pattern, ACCESS_TYPE_UNICAST, OPER_WRITE, STRESS_NONE, DURATION_SINGLE,
5092b4ffbf6SChris Packham 				 bist_offset, cs, pattern_table[pattern].num_of_phases_tx,
5102b4ffbf6SChris Packham 				 (pattern == PATTERN_00) ? DM_DIR_DIRECT : DM_DIR_INVERSE);
5112b4ffbf6SChris Packham 
5122b4ffbf6SChris Packham 	for (adll_tap = 0; adll_tap < ADLL_TAPS_PER_PERIOD; adll_tap++) {
5132b4ffbf6SChris Packham 		/* change target odpg address */
5142b4ffbf6SChris Packham 		odpg_addr = adll_tap * burst_len;
5152b4ffbf6SChris Packham 		ddr3_tip_if_write(0, ACCESS_TYPE_UNICAST, 0, ODPG_DATA_BUFFER_OFFS_REG,
5162b4ffbf6SChris Packham 				  odpg_addr, MASK_ALL_BITS);
5172b4ffbf6SChris Packham 
5182b4ffbf6SChris Packham 		ddr3_tip_configure_odpg(0, ACCESS_TYPE_UNICAST, 0, OPER_WRITE,
5192b4ffbf6SChris Packham 					pattern_table[pattern].num_of_phases_tx,
5202b4ffbf6SChris Packham 					pattern_table[pattern].tx_burst_size,
5212b4ffbf6SChris Packham 					pattern_table[pattern].num_of_phases_rx,
5222b4ffbf6SChris Packham 					WR_OP_ODPG_DATA_CMD_BURST_DLY,
5232b4ffbf6SChris Packham 					ODPG_MODE_TX, cs, STRESS_NONE, DURATION_SINGLE);
5242b4ffbf6SChris Packham 
5252b4ffbf6SChris Packham 		/* odpg bist write enable */
5262b4ffbf6SChris Packham 		ddr3_tip_if_write(0, ACCESS_TYPE_UNICAST, 0, ODPG_DATA_CTRL_REG,
5272b4ffbf6SChris Packham 				  (ODPG_WRBUF_WR_CTRL_ENA << ODPG_WRBUF_WR_CTRL_OFFS),
5282b4ffbf6SChris Packham 				  (ODPG_WRBUF_WR_CTRL_MASK << ODPG_WRBUF_WR_CTRL_OFFS));
5292b4ffbf6SChris Packham 
5302b4ffbf6SChris Packham 		/* odpg bist read disable */
5312b4ffbf6SChris Packham 		ddr3_tip_if_write(0, ACCESS_TYPE_UNICAST, 0, ODPG_DATA_CTRL_REG,
5322b4ffbf6SChris Packham 				  (ODPG_WRBUF_RD_CTRL_DIS << ODPG_WRBUF_RD_CTRL_OFFS),
5332b4ffbf6SChris Packham 				  (ODPG_WRBUF_RD_CTRL_MASK << ODPG_WRBUF_RD_CTRL_OFFS));
5342b4ffbf6SChris Packham 
5352b4ffbf6SChris Packham 		/* trigger odpg */
5362b4ffbf6SChris Packham 		mv_ddr_bist_tx(ACCESS_TYPE_MULTICAST);
5372b4ffbf6SChris Packham 	}
5382b4ffbf6SChris Packham 
5392b4ffbf6SChris Packham 	/* fill memory with vref pattern to increment addr using odpg bist */
5402b4ffbf6SChris Packham 	mv_ddr_odpg_bist_prepare(PATTERN_VREF, ACCESS_TYPE_UNICAST, OPER_WRITE, STRESS_NONE, DURATION_SINGLE,
5412b4ffbf6SChris Packham 				 bist_offset, cs, pattern_table[pattern].num_of_phases_tx,
5422b4ffbf6SChris Packham 				 (pattern == PATTERN_00) ? DM_DIR_DIRECT : DM_DIR_INVERSE);
5432b4ffbf6SChris Packham 
5442b4ffbf6SChris Packham 	for (adll_tap = 0; adll_tap < ADLL_TAPS_PER_PERIOD; adll_tap++) {
5452b4ffbf6SChris Packham 		ddr3_tip_bus_write(0, ACCESS_TYPE_UNICAST, 0, ACCESS_TYPE_MULTICAST, 0,
5462b4ffbf6SChris Packham 				   DDR_PHY_DATA, CTX_PHY_REG(cs), adll_tap);
5472b4ffbf6SChris Packham 		/* change target odpg address */
5482b4ffbf6SChris Packham 		odpg_addr = adll_tap * burst_len;
5492b4ffbf6SChris Packham 		ddr3_tip_if_write(0, ACCESS_TYPE_UNICAST, 0, ODPG_DATA_BUFFER_OFFS_REG,
5502b4ffbf6SChris Packham 				  odpg_addr, MASK_ALL_BITS);
5512b4ffbf6SChris Packham 		ddr3_tip_configure_odpg(0, ACCESS_TYPE_UNICAST, 0, OPER_WRITE,
5522b4ffbf6SChris Packham 					pattern_table[pattern].num_of_phases_tx,
5532b4ffbf6SChris Packham 					pattern_table[pattern].tx_burst_size,
5542b4ffbf6SChris Packham 					pattern_table[pattern].num_of_phases_rx,
5552b4ffbf6SChris Packham 					WR_OP_ODPG_DATA_CMD_BURST_DLY,
5562b4ffbf6SChris Packham 					ODPG_MODE_TX, cs, STRESS_NONE, DURATION_SINGLE);
5572b4ffbf6SChris Packham 
5582b4ffbf6SChris Packham 		/* odpg bist write enable */
5592b4ffbf6SChris Packham 		ddr3_tip_if_write(0, ACCESS_TYPE_UNICAST, 0, ODPG_DATA_CTRL_REG,
5602b4ffbf6SChris Packham 				  (ODPG_WRBUF_WR_CTRL_ENA << ODPG_WRBUF_WR_CTRL_OFFS),
5612b4ffbf6SChris Packham 				  (ODPG_WRBUF_WR_CTRL_MASK << ODPG_WRBUF_WR_CTRL_OFFS));
5622b4ffbf6SChris Packham 
5632b4ffbf6SChris Packham 		/* odpg bist read disable */
5642b4ffbf6SChris Packham 		ddr3_tip_if_write(0, ACCESS_TYPE_UNICAST, 0, ODPG_DATA_CTRL_REG,
5652b4ffbf6SChris Packham 				  (ODPG_WRBUF_RD_CTRL_DIS << ODPG_WRBUF_RD_CTRL_OFFS),
5662b4ffbf6SChris Packham 				  (ODPG_WRBUF_RD_CTRL_MASK << ODPG_WRBUF_RD_CTRL_OFFS));
5672b4ffbf6SChris Packham 
5682b4ffbf6SChris Packham 		/* trigger odpg */
5692b4ffbf6SChris Packham 		mv_ddr_bist_tx(ACCESS_TYPE_MULTICAST);
5702b4ffbf6SChris Packham 	}
5712b4ffbf6SChris Packham 
5722b4ffbf6SChris Packham 	/* restore subphy's tx adll_tap to its position */
5732b4ffbf6SChris Packham 	for (subphy = 0; subphy < subphy_max; subphy++) {
5742b4ffbf6SChris Packham 		VALIDATE_BUS_ACTIVE(tm->bus_act_mask, subphy);
5752b4ffbf6SChris Packham 		ddr3_tip_bus_write(0, ACCESS_TYPE_UNICAST, 0, ACCESS_TYPE_UNICAST,
5762b4ffbf6SChris Packham 				   subphy, DDR_PHY_DATA, CTX_PHY_REG(cs),
5772b4ffbf6SChris Packham 				   wr_ctrl_adll[subphy]);
5782b4ffbf6SChris Packham 	}
5792b4ffbf6SChris Packham 
5802b4ffbf6SChris Packham 	/* read and validate bist (comparing with the base pattern) */
5812b4ffbf6SChris Packham 	for (adll_tap = 0; adll_tap < ADLL_TAPS_PER_PERIOD; adll_tap++) {
5822b4ffbf6SChris Packham 		result = 0;
5832b4ffbf6SChris Packham 		odpg_addr = adll_tap * burst_len;
5842b4ffbf6SChris Packham 		/* change addr to fit write */
5852b4ffbf6SChris Packham 		mv_ddr_pattern_start_addr_set(pattern_table, pattern, odpg_addr);
5862b4ffbf6SChris Packham 		mv_ddr_tip_bist(OPER_READ, 0, pattern, 0, &result);
5872b4ffbf6SChris Packham 		for (subphy = 0; subphy < subphy_max; subphy++) {
5882b4ffbf6SChris Packham 			VALIDATE_BUS_ACTIVE(tm->bus_act_mask, subphy);
5892b4ffbf6SChris Packham 			idx = ADLL_TAPS_PER_PERIOD * subphy + adll_tap;
5902b4ffbf6SChris Packham 			vw_vector[idx] |= ((result >> subphy) & 0x1);
5912b4ffbf6SChris Packham 		}
5922b4ffbf6SChris Packham 	}
5932b4ffbf6SChris Packham 
5942b4ffbf6SChris Packham 	/* restore subphy's rx adll_tap to its position */
5952b4ffbf6SChris Packham 	for (subphy = 0; subphy < subphy_max; subphy++) {
5962b4ffbf6SChris Packham 		VALIDATE_BUS_ACTIVE(tm->bus_act_mask, subphy);
5972b4ffbf6SChris Packham 		ddr3_tip_bus_write(0, ACCESS_TYPE_UNICAST, 0, ACCESS_TYPE_UNICAST,
5982b4ffbf6SChris Packham 				   subphy, DDR_PHY_DATA, CRX_PHY_REG(cs),
5992b4ffbf6SChris Packham 				   rd_ctrl_adll[subphy]);
6002b4ffbf6SChris Packham 	}
6012b4ffbf6SChris Packham 
6022b4ffbf6SChris Packham 	return MV_OK;
6032b4ffbf6SChris Packham }
604