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"
7ebb1a593SChris Packham #include "mv_ddr_regs.h"
8f1df9364SStefan Roese 
9f1df9364SStefan Roese #define VREF_INITIAL_STEP		3
10f1df9364SStefan Roese #define VREF_SECOND_STEP		1
11f1df9364SStefan Roese #define VREF_MAX_INDEX			7
12f1df9364SStefan Roese #define MAX_VALUE			(1024 - 1)
13f1df9364SStefan Roese #define MIN_VALUE			(-MAX_VALUE)
142b4ffbf6SChris Packham #define GET_RD_SAMPLE_DELAY(data, cs)	((data >> rd_sample_mask[cs]) & 0xf)
15f1df9364SStefan Roese 
16f1df9364SStefan Roese u32 ca_delay;
17f1df9364SStefan Roese int ddr3_tip_centr_skip_min_win_check = 0;
18f1df9364SStefan Roese u8 current_vref[MAX_BUS_NUM][MAX_INTERFACE_NUM];
19f1df9364SStefan Roese u8 last_vref[MAX_BUS_NUM][MAX_INTERFACE_NUM];
20f1df9364SStefan Roese u16 current_valid_window[MAX_BUS_NUM][MAX_INTERFACE_NUM];
21f1df9364SStefan Roese u16 last_valid_window[MAX_BUS_NUM][MAX_INTERFACE_NUM];
22f1df9364SStefan Roese u8 lim_vref[MAX_BUS_NUM][MAX_INTERFACE_NUM];
23f1df9364SStefan Roese u8 interface_state[MAX_INTERFACE_NUM];
24f1df9364SStefan Roese u8 vref_window_size[MAX_INTERFACE_NUM][MAX_BUS_NUM];
25f1df9364SStefan Roese u8 vref_window_size_th = 12;
26f1df9364SStefan Roese 
27f1df9364SStefan Roese static u8 pup_st[MAX_BUS_NUM][MAX_INTERFACE_NUM];
28f1df9364SStefan Roese 
29f1df9364SStefan Roese static u32 rd_sample_mask[] = {
30f1df9364SStefan Roese 	0,
31f1df9364SStefan Roese 	8,
32f1df9364SStefan Roese 	16,
33f1df9364SStefan Roese 	24
34f1df9364SStefan Roese };
35f1df9364SStefan Roese 
36f1df9364SStefan Roese #define	VREF_STEP_1		0
37f1df9364SStefan Roese #define	VREF_STEP_2		1
38f1df9364SStefan Roese #define	VREF_CONVERGE		2
39f1df9364SStefan Roese 
40f1df9364SStefan Roese /*
41f1df9364SStefan Roese  * ODT additional timing
42f1df9364SStefan Roese  */
ddr3_tip_write_additional_odt_setting(u32 dev_num,u32 if_id)43f1df9364SStefan Roese int ddr3_tip_write_additional_odt_setting(u32 dev_num, u32 if_id)
44f1df9364SStefan Roese {
452b4ffbf6SChris Packham 	u32 cs_num = 0, max_read_sample = 0, min_read_sample = 0x1f;
46f1df9364SStefan Roese 	u32 data_read[MAX_INTERFACE_NUM] = { 0 };
47f1df9364SStefan Roese 	u32 read_sample[MAX_CS_NUM];
48f1df9364SStefan Roese 	u32 val;
49f1df9364SStefan Roese 	u32 pup_index;
50f1df9364SStefan Roese 	int max_phase = MIN_VALUE, current_phase;
51f1df9364SStefan Roese 	enum hws_access_type access_type = ACCESS_TYPE_UNICAST;
522b4ffbf6SChris Packham 	u32 octets_per_if_num = ddr3_tip_dev_attr_get(dev_num, MV_ATTR_OCTET_PER_INTERFACE);
53*247c80d6SChris Packham 	unsigned int max_cs = mv_ddr_cs_num_get();
54f1df9364SStefan Roese 
55f1df9364SStefan Roese 	CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, if_id,
562b4ffbf6SChris Packham 				       DUNIT_ODT_CTRL_REG,
57f1df9364SStefan Roese 				       0 << 8, 0x3 << 8));
58f1df9364SStefan Roese 	CHECK_STATUS(ddr3_tip_if_read(dev_num, access_type, if_id,
592b4ffbf6SChris Packham 				      RD_DATA_SMPL_DLYS_REG,
60f1df9364SStefan Roese 				      data_read, MASK_ALL_BITS));
61f1df9364SStefan Roese 	val = data_read[if_id];
62f1df9364SStefan Roese 
63*247c80d6SChris Packham 	for (cs_num = 0; cs_num < max_cs; cs_num++) {
64f1df9364SStefan Roese 		read_sample[cs_num] = GET_RD_SAMPLE_DELAY(val, cs_num);
65f1df9364SStefan Roese 
66f1df9364SStefan Roese 		/* find maximum of read_samples */
67f1df9364SStefan Roese 		if (read_sample[cs_num] >= max_read_sample) {
682b4ffbf6SChris Packham 			if (read_sample[cs_num] == max_read_sample)
698bddf678SChris Packham 				max_phase = MIN_VALUE;
702b4ffbf6SChris Packham 			else
712b4ffbf6SChris Packham 				max_read_sample = read_sample[cs_num];
72f1df9364SStefan Roese 
73f1df9364SStefan Roese 			for (pup_index = 0;
742b4ffbf6SChris Packham 			     pup_index < octets_per_if_num;
75f1df9364SStefan Roese 			     pup_index++) {
76f1df9364SStefan Roese 				CHECK_STATUS(ddr3_tip_bus_read
77f1df9364SStefan Roese 					     (dev_num, if_id,
78f1df9364SStefan Roese 					      ACCESS_TYPE_UNICAST, pup_index,
79f1df9364SStefan Roese 					      DDR_PHY_DATA,
802b4ffbf6SChris Packham 					      RL_PHY_REG(cs_num),
81f1df9364SStefan Roese 					      &val));
82f1df9364SStefan Roese 
83f1df9364SStefan Roese 				current_phase = ((int)val & 0xe0) >> 6;
84f1df9364SStefan Roese 				if (current_phase >= max_phase)
85f1df9364SStefan Roese 					max_phase = current_phase;
86f1df9364SStefan Roese 			}
87f1df9364SStefan Roese 		}
88f1df9364SStefan Roese 
89f1df9364SStefan Roese 		/* find minimum */
90f1df9364SStefan Roese 		if (read_sample[cs_num] < min_read_sample)
91f1df9364SStefan Roese 			min_read_sample = read_sample[cs_num];
92f1df9364SStefan Roese 	}
93f1df9364SStefan Roese 
94f1df9364SStefan Roese 	min_read_sample = min_read_sample - 1;
95f1df9364SStefan Roese 	max_read_sample = max_read_sample + 4 + (max_phase + 1) / 2 + 1;
962b4ffbf6SChris Packham 	if (min_read_sample >= 0xf)
972b4ffbf6SChris Packham 		min_read_sample = 0xf;
98f1df9364SStefan Roese 	if (max_read_sample >= 0x1f)
99f1df9364SStefan Roese 		max_read_sample = 0x1f;
100f1df9364SStefan Roese 
101f1df9364SStefan Roese 	CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, if_id,
1022b4ffbf6SChris Packham 				       DDR_ODT_TIMING_LOW_REG,
103f1df9364SStefan Roese 				       ((min_read_sample - 1) << 12),
104f1df9364SStefan Roese 				       0xf << 12));
105f1df9364SStefan Roese 	CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, if_id,
1062b4ffbf6SChris Packham 				       DDR_ODT_TIMING_LOW_REG,
107f1df9364SStefan Roese 				       (max_read_sample << 16),
108f1df9364SStefan Roese 				       0x1f << 16));
109f1df9364SStefan Roese 
110f1df9364SStefan Roese 	return MV_OK;
111f1df9364SStefan Roese }
112f1df9364SStefan Roese 
get_valid_win_rx(u32 dev_num,u32 if_id,u8 res[4])113f1df9364SStefan Roese int get_valid_win_rx(u32 dev_num, u32 if_id, u8 res[4])
114f1df9364SStefan Roese {
1152b4ffbf6SChris Packham 	u32 reg_pup = RESULT_PHY_REG;
116f1df9364SStefan Roese 	u32 reg_data;
117f1df9364SStefan Roese 	u32 cs_num;
118f1df9364SStefan Roese 	int i;
119f1df9364SStefan Roese 
120f1df9364SStefan Roese 	cs_num = 0;
121f1df9364SStefan Roese 
122f1df9364SStefan Roese 	/* TBD */
123f1df9364SStefan Roese 	reg_pup += cs_num;
124f1df9364SStefan Roese 
125f1df9364SStefan Roese 	for (i = 0; i < 4; i++) {
126f1df9364SStefan Roese 		CHECK_STATUS(ddr3_tip_bus_read(dev_num, if_id,
127f1df9364SStefan Roese 					       ACCESS_TYPE_UNICAST, i,
128f1df9364SStefan Roese 					       DDR_PHY_DATA, reg_pup,
129f1df9364SStefan Roese 					       &reg_data));
1302b4ffbf6SChris Packham 		res[i] = (reg_data >> RESULT_PHY_RX_OFFS) & 0x1f;
131f1df9364SStefan Roese 	}
132f1df9364SStefan Roese 
133f1df9364SStefan Roese 	return 0;
134f1df9364SStefan Roese }
135f1df9364SStefan Roese 
136f1df9364SStefan Roese /*
137f1df9364SStefan Roese  * This algorithm deals with the vertical optimum from Voltage point of view
138f1df9364SStefan Roese  * of the sample signal.
139f1df9364SStefan Roese  * Voltage sample point can improve the Eye / window size of the bit and the
140f1df9364SStefan Roese  * pup.
141f1df9364SStefan Roese  * The problem is that it is tune for all DQ the same so there isn't any
142f1df9364SStefan Roese  * PBS like code.
143f1df9364SStefan Roese  * It is more like centralization.
144f1df9364SStefan Roese  * But because we don't have The training SM support we do it a bit more
145f1df9364SStefan Roese  * smart search to save time.
146f1df9364SStefan Roese  */
ddr3_tip_vref(u32 dev_num)147f1df9364SStefan Roese int ddr3_tip_vref(u32 dev_num)
148f1df9364SStefan Roese {
149f1df9364SStefan Roese 	/*
150f1df9364SStefan Roese 	 * The Vref register have non linear order. Need to check what will be
151f1df9364SStefan Roese 	 * in future projects.
152f1df9364SStefan Roese 	 */
153f1df9364SStefan Roese 	u32 vref_map[8] = {
154f1df9364SStefan Roese 		1, 2, 3, 4, 5, 6, 7, 0
155f1df9364SStefan Roese 	};
156f1df9364SStefan Roese 	/* State and parameter definitions */
157f1df9364SStefan Roese 	u32 initial_step = VREF_INITIAL_STEP;
158f1df9364SStefan Roese 	/* need to be assign with minus ????? */
159f1df9364SStefan Roese 	u32 second_step = VREF_SECOND_STEP;
160f1df9364SStefan Roese 	u32 algo_run_flag = 0, currrent_vref = 0;
161f1df9364SStefan Roese 	u32 while_count = 0;
162f1df9364SStefan Roese 	u32 pup = 0, if_id = 0, num_pup = 0, rep = 0;
163f1df9364SStefan Roese 	u32 val = 0;
164f1df9364SStefan Roese 	u32 reg_addr = 0xa8;
165f1df9364SStefan Roese 	u32 copy_start_pattern, copy_end_pattern;
166f1df9364SStefan Roese 	enum hws_result *flow_result = ddr3_tip_get_result_ptr(training_stage);
167f1df9364SStefan Roese 	u8 res[4];
1682b4ffbf6SChris Packham 	u32 octets_per_if_num = ddr3_tip_dev_attr_get(dev_num, MV_ATTR_OCTET_PER_INTERFACE);
1692b4ffbf6SChris Packham 	struct mv_ddr_topology_map *tm = mv_ddr_topology_map_get();
170f1df9364SStefan Roese 
171f1df9364SStefan Roese 	CHECK_STATUS(ddr3_tip_special_rx(dev_num));
172f1df9364SStefan Roese 
173f1df9364SStefan Roese 	/* save start/end pattern */
174f1df9364SStefan Roese 	copy_start_pattern = start_pattern;
175f1df9364SStefan Roese 	copy_end_pattern = end_pattern;
176f1df9364SStefan Roese 
177f1df9364SStefan Roese 	/* set vref as centralization pattern */
178f1df9364SStefan Roese 	start_pattern = PATTERN_VREF;
179f1df9364SStefan Roese 	end_pattern = PATTERN_VREF;
180f1df9364SStefan Roese 
181f1df9364SStefan Roese 	/* init params */
182f1df9364SStefan Roese 	for (if_id = 0; if_id < MAX_INTERFACE_NUM; if_id++) {
1832b4ffbf6SChris Packham 		VALIDATE_IF_ACTIVE(tm->if_act_mask, if_id);
184f1df9364SStefan Roese 		for (pup = 0;
1852b4ffbf6SChris Packham 		     pup < octets_per_if_num; pup++) {
186f1df9364SStefan Roese 			current_vref[pup][if_id] = 0;
187f1df9364SStefan Roese 			last_vref[pup][if_id] = 0;
188f1df9364SStefan Roese 			lim_vref[pup][if_id] = 0;
189f1df9364SStefan Roese 			current_valid_window[pup][if_id] = 0;
190f1df9364SStefan Roese 			last_valid_window[pup][if_id] = 0;
191f1df9364SStefan Roese 			if (vref_window_size[if_id][pup] >
192f1df9364SStefan Roese 			    vref_window_size_th) {
193f1df9364SStefan Roese 				pup_st[pup][if_id] = VREF_CONVERGE;
194f1df9364SStefan Roese 				DEBUG_TRAINING_HW_ALG(
195f1df9364SStefan Roese 					DEBUG_LEVEL_INFO,
196f1df9364SStefan Roese 					("VREF config, IF[ %d ]pup[ %d ] - Vref tune not requered (%d)\n",
197f1df9364SStefan Roese 					 if_id, pup, __LINE__));
198f1df9364SStefan Roese 			} else {
199f1df9364SStefan Roese 				pup_st[pup][if_id] = VREF_STEP_1;
200f1df9364SStefan Roese 				CHECK_STATUS(ddr3_tip_bus_read
201f1df9364SStefan Roese 					     (dev_num, if_id,
202f1df9364SStefan Roese 					      ACCESS_TYPE_UNICAST, pup,
203f1df9364SStefan Roese 					      DDR_PHY_DATA, reg_addr, &val));
204f1df9364SStefan Roese 				CHECK_STATUS(ddr3_tip_bus_write
205f1df9364SStefan Roese 					     (dev_num, ACCESS_TYPE_UNICAST,
206f1df9364SStefan Roese 					      if_id, ACCESS_TYPE_UNICAST,
207f1df9364SStefan Roese 					      pup, DDR_PHY_DATA, reg_addr,
208f1df9364SStefan Roese 					      (val & (~0xf)) | vref_map[0]));
209f1df9364SStefan Roese 				DEBUG_TRAINING_HW_ALG(
210f1df9364SStefan Roese 					DEBUG_LEVEL_INFO,
211f1df9364SStefan Roese 					("VREF config, IF[ %d ]pup[ %d ] - Vref = %X (%d)\n",
212f1df9364SStefan Roese 					 if_id, pup,
213f1df9364SStefan Roese 					 (val & (~0xf)) | vref_map[0],
214f1df9364SStefan Roese 					 __LINE__));
215f1df9364SStefan Roese 			}
216f1df9364SStefan Roese 		}
217f1df9364SStefan Roese 		interface_state[if_id] = 0;
218f1df9364SStefan Roese 	}
219f1df9364SStefan Roese 
220f1df9364SStefan Roese 	/* TODO: Set number of active interfaces */
2212b4ffbf6SChris Packham 	num_pup = octets_per_if_num * MAX_INTERFACE_NUM;
222f1df9364SStefan Roese 
223f1df9364SStefan Roese 	while ((algo_run_flag <= num_pup) & (while_count < 10)) {
224f1df9364SStefan Roese 		while_count++;
225f1df9364SStefan Roese 		for (rep = 1; rep < 4; rep++) {
226f1df9364SStefan Roese 			ddr3_tip_centr_skip_min_win_check = 1;
227f1df9364SStefan Roese 			ddr3_tip_centralization_rx(dev_num);
228f1df9364SStefan Roese 			ddr3_tip_centr_skip_min_win_check = 0;
229f1df9364SStefan Roese 
230f1df9364SStefan Roese 			/* Read Valid window results only for non converge pups */
231f1df9364SStefan Roese 			for (if_id = 0; if_id < MAX_INTERFACE_NUM; if_id++) {
2322b4ffbf6SChris Packham 				VALIDATE_IF_ACTIVE(tm->if_act_mask, if_id);
233f1df9364SStefan Roese 				if (interface_state[if_id] != 4) {
234f1df9364SStefan Roese 					get_valid_win_rx(dev_num, if_id, res);
235f1df9364SStefan Roese 					for (pup = 0;
2362b4ffbf6SChris Packham 					     pup < octets_per_if_num;
237f1df9364SStefan Roese 					     pup++) {
2382b4ffbf6SChris Packham 						VALIDATE_BUS_ACTIVE
239f1df9364SStefan Roese 							(tm->bus_act_mask, pup);
240f1df9364SStefan Roese 						if (pup_st[pup]
241f1df9364SStefan Roese 						    [if_id] ==
242f1df9364SStefan Roese 						    VREF_CONVERGE)
243f1df9364SStefan Roese 							continue;
244f1df9364SStefan Roese 
245f1df9364SStefan Roese 						current_valid_window[pup]
246f1df9364SStefan Roese 							[if_id] =
247f1df9364SStefan Roese 							(current_valid_window[pup]
248f1df9364SStefan Roese 							 [if_id] * (rep - 1) +
249f1df9364SStefan Roese 							 1000 * res[pup]) / rep;
250f1df9364SStefan Roese 					}
251f1df9364SStefan Roese 				}
252f1df9364SStefan Roese 			}
253f1df9364SStefan Roese 		}
254f1df9364SStefan Roese 
255f1df9364SStefan Roese 		for (if_id = 0; if_id < MAX_INTERFACE_NUM; if_id++) {
2562b4ffbf6SChris Packham 			VALIDATE_IF_ACTIVE(tm->if_act_mask, if_id);
257f1df9364SStefan Roese 			DEBUG_TRAINING_HW_ALG(
258f1df9364SStefan Roese 				DEBUG_LEVEL_TRACE,
259f1df9364SStefan Roese 				("current_valid_window: IF[ %d ] - ", if_id));
260f1df9364SStefan Roese 
261f1df9364SStefan Roese 			for (pup = 0;
2622b4ffbf6SChris Packham 			     pup < octets_per_if_num; pup++) {
2632b4ffbf6SChris Packham 				VALIDATE_BUS_ACTIVE(tm->bus_act_mask, pup);
264f1df9364SStefan Roese 				DEBUG_TRAINING_HW_ALG(DEBUG_LEVEL_TRACE,
265f1df9364SStefan Roese 						      ("%d ",
266f1df9364SStefan Roese 						       current_valid_window
267f1df9364SStefan Roese 						       [pup][if_id]));
268f1df9364SStefan Roese 			}
269f1df9364SStefan Roese 			DEBUG_TRAINING_HW_ALG(DEBUG_LEVEL_TRACE, ("\n"));
270f1df9364SStefan Roese 		}
271f1df9364SStefan Roese 
272f1df9364SStefan Roese 		/* Compare results and respond as function of state */
273f1df9364SStefan Roese 		for (if_id = 0; if_id < MAX_INTERFACE_NUM; if_id++) {
2742b4ffbf6SChris Packham 			VALIDATE_IF_ACTIVE(tm->if_act_mask, if_id);
275f1df9364SStefan Roese 			for (pup = 0;
2762b4ffbf6SChris Packham 			     pup < octets_per_if_num; pup++) {
2772b4ffbf6SChris Packham 				VALIDATE_BUS_ACTIVE(tm->bus_act_mask, pup);
278f1df9364SStefan Roese 				DEBUG_TRAINING_HW_ALG(DEBUG_LEVEL_TRACE,
279f1df9364SStefan Roese 						      ("I/F[ %d ], pup[ %d ] STATE #%d (%d)\n",
280f1df9364SStefan Roese 						       if_id, pup,
281f1df9364SStefan Roese 						       pup_st[pup]
282f1df9364SStefan Roese 						       [if_id], __LINE__));
283f1df9364SStefan Roese 
284f1df9364SStefan Roese 				if (pup_st[pup][if_id] == VREF_CONVERGE)
285f1df9364SStefan Roese 					continue;
286f1df9364SStefan Roese 
287f1df9364SStefan Roese 				DEBUG_TRAINING_HW_ALG(DEBUG_LEVEL_TRACE,
288f1df9364SStefan Roese 						      ("I/F[ %d ], pup[ %d ] CHECK progress - Current %d Last %d, limit VREF %d (%d)\n",
289f1df9364SStefan Roese 						       if_id, pup,
290f1df9364SStefan Roese 						       current_valid_window[pup]
291f1df9364SStefan Roese 						       [if_id],
292f1df9364SStefan Roese 						       last_valid_window[pup]
293f1df9364SStefan Roese 						       [if_id], lim_vref[pup]
294f1df9364SStefan Roese 						       [if_id], __LINE__));
295f1df9364SStefan Roese 
296f1df9364SStefan Roese 				/*
297f1df9364SStefan Roese 				 * The -1 is for solution resolution +/- 1 tap
298f1df9364SStefan Roese 				 * of ADLL
299f1df9364SStefan Roese 				 */
300f1df9364SStefan Roese 				if (current_valid_window[pup][if_id] + 200 >=
301f1df9364SStefan Roese 				    (last_valid_window[pup][if_id])) {
302f1df9364SStefan Roese 					if (pup_st[pup][if_id] == VREF_STEP_1) {
303f1df9364SStefan Roese 						/*
304f1df9364SStefan Roese 						 * We stay in the same state and
305f1df9364SStefan Roese 						 * step just update the window
306f1df9364SStefan Roese 						 * size (take the max) and Vref
307f1df9364SStefan Roese 						 */
308f1df9364SStefan Roese 						if (current_vref[pup]
309f1df9364SStefan Roese 						    [if_id] == VREF_MAX_INDEX) {
310f1df9364SStefan Roese 							/*
311f1df9364SStefan Roese 							 * If we step to the end
312f1df9364SStefan Roese 							 * and didn't converge
313f1df9364SStefan Roese 							 * to some particular
314f1df9364SStefan Roese 							 * better Vref value
315f1df9364SStefan Roese 							 * define the pup as
316f1df9364SStefan Roese 							 * converge and step
317f1df9364SStefan Roese 							 * back to nominal
318f1df9364SStefan Roese 							 * Vref.
319f1df9364SStefan Roese 							 */
320f1df9364SStefan Roese 							pup_st[pup]
321f1df9364SStefan Roese 								[if_id] =
322f1df9364SStefan Roese 								VREF_CONVERGE;
323f1df9364SStefan Roese 							algo_run_flag++;
324f1df9364SStefan Roese 							interface_state
325f1df9364SStefan Roese 								[if_id]++;
326f1df9364SStefan Roese 							DEBUG_TRAINING_HW_ALG
327f1df9364SStefan Roese 								(DEBUG_LEVEL_TRACE,
328f1df9364SStefan Roese 								 ("I/F[ %d ], pup[ %d ] VREF_CONVERGE - Vref = %X (%d)\n",
329f1df9364SStefan Roese 								  if_id, pup,
330f1df9364SStefan Roese 								  current_vref[pup]
331f1df9364SStefan Roese 								  [if_id],
332f1df9364SStefan Roese 								  __LINE__));
333f1df9364SStefan Roese 						} else {
334f1df9364SStefan Roese 							/* continue to update the Vref index */
335f1df9364SStefan Roese 							current_vref[pup]
336f1df9364SStefan Roese 								[if_id] =
337f1df9364SStefan Roese 								((current_vref[pup]
338f1df9364SStefan Roese 								  [if_id] +
339f1df9364SStefan Roese 								  initial_step) >
340f1df9364SStefan Roese 								 VREF_MAX_INDEX) ?
341f1df9364SStefan Roese 								VREF_MAX_INDEX
342f1df9364SStefan Roese 								: (current_vref[pup]
343f1df9364SStefan Roese 								   [if_id] +
344f1df9364SStefan Roese 								   initial_step);
345f1df9364SStefan Roese 							if (current_vref[pup]
346f1df9364SStefan Roese 							    [if_id] ==
347f1df9364SStefan Roese 							    VREF_MAX_INDEX) {
348f1df9364SStefan Roese 								pup_st[pup]
349f1df9364SStefan Roese 									[if_id]
350f1df9364SStefan Roese 									=
351f1df9364SStefan Roese 									VREF_STEP_2;
352f1df9364SStefan Roese 							}
353f1df9364SStefan Roese 							lim_vref[pup]
354f1df9364SStefan Roese 								[if_id] =
355f1df9364SStefan Roese 								last_vref[pup]
356f1df9364SStefan Roese 								[if_id] =
357f1df9364SStefan Roese 								current_vref[pup]
358f1df9364SStefan Roese 								[if_id];
359f1df9364SStefan Roese 						}
360f1df9364SStefan Roese 
361f1df9364SStefan Roese 						last_valid_window[pup]
362f1df9364SStefan Roese 							[if_id] =
363f1df9364SStefan Roese 							GET_MAX(current_valid_window
364f1df9364SStefan Roese 								[pup][if_id],
365f1df9364SStefan Roese 								last_valid_window
366f1df9364SStefan Roese 								[pup]
367f1df9364SStefan Roese 								[if_id]);
368f1df9364SStefan Roese 
369f1df9364SStefan Roese 						/* update the Vref for next stage */
370f1df9364SStefan Roese 						currrent_vref =
371f1df9364SStefan Roese 							current_vref[pup]
372f1df9364SStefan Roese 							[if_id];
373f1df9364SStefan Roese 						CHECK_STATUS
374f1df9364SStefan Roese 							(ddr3_tip_bus_read
375f1df9364SStefan Roese 							 (dev_num, if_id,
376f1df9364SStefan Roese 							  ACCESS_TYPE_UNICAST, pup,
377f1df9364SStefan Roese 							  DDR_PHY_DATA, reg_addr,
378f1df9364SStefan Roese 							  &val));
379f1df9364SStefan Roese 						CHECK_STATUS
380f1df9364SStefan Roese 							(ddr3_tip_bus_write
381f1df9364SStefan Roese 							 (dev_num,
382f1df9364SStefan Roese 							  ACCESS_TYPE_UNICAST,
383f1df9364SStefan Roese 							  if_id,
384f1df9364SStefan Roese 							  ACCESS_TYPE_UNICAST, pup,
385f1df9364SStefan Roese 							  DDR_PHY_DATA, reg_addr,
386f1df9364SStefan Roese 							  (val & (~0xf)) |
387f1df9364SStefan Roese 							  vref_map[currrent_vref]));
388f1df9364SStefan Roese 						DEBUG_TRAINING_HW_ALG
389f1df9364SStefan Roese 							(DEBUG_LEVEL_TRACE,
390f1df9364SStefan Roese 							 ("VREF config, IF[ %d ]pup[ %d ] - Vref = %X (%d)\n",
391f1df9364SStefan Roese 							  if_id, pup,
392f1df9364SStefan Roese 							  (val & (~0xf)) |
393f1df9364SStefan Roese 							  vref_map[currrent_vref],
394f1df9364SStefan Roese 							  __LINE__));
395f1df9364SStefan Roese 					} else if (pup_st[pup][if_id]
396f1df9364SStefan Roese 						   == VREF_STEP_2) {
397f1df9364SStefan Roese 						/*
398f1df9364SStefan Roese 						 * We keep on search back with
399f1df9364SStefan Roese 						 * the same step size.
400f1df9364SStefan Roese 						 */
401f1df9364SStefan Roese 						last_valid_window[pup]
402f1df9364SStefan Roese 							[if_id] =
403f1df9364SStefan Roese 							GET_MAX(current_valid_window
404f1df9364SStefan Roese 								[pup][if_id],
405f1df9364SStefan Roese 								last_valid_window
406f1df9364SStefan Roese 								[pup]
407f1df9364SStefan Roese 								[if_id]);
408f1df9364SStefan Roese 						last_vref[pup][if_id] =
409f1df9364SStefan Roese 							current_vref[pup]
410f1df9364SStefan Roese 							[if_id];
411f1df9364SStefan Roese 
412f1df9364SStefan Roese 						/* we finish all search space */
413f1df9364SStefan Roese 						if ((current_vref[pup]
414f1df9364SStefan Roese 						     [if_id] - second_step) == lim_vref[pup][if_id]) {
415f1df9364SStefan Roese 							/*
416f1df9364SStefan Roese 							 * If we step to the end
417f1df9364SStefan Roese 							 * and didn't converge
418f1df9364SStefan Roese 							 * to some particular
419f1df9364SStefan Roese 							 * better Vref value
420f1df9364SStefan Roese 							 * define the pup as
421f1df9364SStefan Roese 							 * converge and step
422f1df9364SStefan Roese 							 * back to nominal
423f1df9364SStefan Roese 							 * Vref.
424f1df9364SStefan Roese 							 */
425f1df9364SStefan Roese 							pup_st[pup]
426f1df9364SStefan Roese 								[if_id] =
427f1df9364SStefan Roese 								VREF_CONVERGE;
428f1df9364SStefan Roese 							algo_run_flag++;
429f1df9364SStefan Roese 
430f1df9364SStefan Roese 							interface_state
431f1df9364SStefan Roese 								[if_id]++;
432f1df9364SStefan Roese 
433f1df9364SStefan Roese 							current_vref[pup]
434f1df9364SStefan Roese 								[if_id] =
435f1df9364SStefan Roese 								(current_vref[pup]
436f1df9364SStefan Roese 								 [if_id] -
437f1df9364SStefan Roese 								 second_step);
438f1df9364SStefan Roese 
439f1df9364SStefan Roese 							DEBUG_TRAINING_HW_ALG
440f1df9364SStefan Roese 								(DEBUG_LEVEL_TRACE,
441f1df9364SStefan Roese 								 ("I/F[ %d ], pup[ %d ] VREF_CONVERGE - Vref = %X (%d)\n",
442f1df9364SStefan Roese 								  if_id, pup,
443f1df9364SStefan Roese 								  current_vref[pup]
444f1df9364SStefan Roese 								  [if_id],
445f1df9364SStefan Roese 								  __LINE__));
446f1df9364SStefan Roese 						} else
447f1df9364SStefan Roese 							/* we finish all search space */
448f1df9364SStefan Roese 							if (current_vref[pup]
449f1df9364SStefan Roese 							    [if_id] ==
450f1df9364SStefan Roese 							    lim_vref[pup]
451f1df9364SStefan Roese 							    [if_id]) {
452f1df9364SStefan Roese 								/*
453f1df9364SStefan Roese 								 * If we step to the end
454f1df9364SStefan Roese 								 * and didn't converge
455f1df9364SStefan Roese 								 * to some particular
456f1df9364SStefan Roese 								 * better Vref value
457f1df9364SStefan Roese 								 * define the pup as
458f1df9364SStefan Roese 								 * converge and step
459f1df9364SStefan Roese 								 * back to nominal
460f1df9364SStefan Roese 								 * Vref.
461f1df9364SStefan Roese 								 */
462f1df9364SStefan Roese 								pup_st[pup]
463f1df9364SStefan Roese 									[if_id] =
464f1df9364SStefan Roese 									VREF_CONVERGE;
465f1df9364SStefan Roese 
466f1df9364SStefan Roese 								algo_run_flag++;
467f1df9364SStefan Roese 								interface_state
468f1df9364SStefan Roese 									[if_id]++;
469f1df9364SStefan Roese 								DEBUG_TRAINING_HW_ALG
470f1df9364SStefan Roese 									(DEBUG_LEVEL_TRACE,
471f1df9364SStefan Roese 									 ("I/F[ %d ], pup[ %d ] VREF_CONVERGE - Vref = %X (%d)\n",
472f1df9364SStefan Roese 									  if_id, pup,
473f1df9364SStefan Roese 									  current_vref[pup]
474f1df9364SStefan Roese 									  [if_id],
475f1df9364SStefan Roese 									  __LINE__));
476f1df9364SStefan Roese 							} else {
477f1df9364SStefan Roese 								current_vref[pup]
478f1df9364SStefan Roese 									[if_id] =
479f1df9364SStefan Roese 									current_vref[pup]
480f1df9364SStefan Roese 									[if_id] -
481f1df9364SStefan Roese 									second_step;
482f1df9364SStefan Roese 							}
483f1df9364SStefan Roese 
484f1df9364SStefan Roese 						/* Update the Vref for next stage */
485f1df9364SStefan Roese 						currrent_vref =
486f1df9364SStefan Roese 							current_vref[pup]
487f1df9364SStefan Roese 							[if_id];
488f1df9364SStefan Roese 						CHECK_STATUS
489f1df9364SStefan Roese 							(ddr3_tip_bus_read
490f1df9364SStefan Roese 							 (dev_num, if_id,
491f1df9364SStefan Roese 							  ACCESS_TYPE_UNICAST, pup,
492f1df9364SStefan Roese 							  DDR_PHY_DATA, reg_addr,
493f1df9364SStefan Roese 							  &val));
494f1df9364SStefan Roese 						CHECK_STATUS
495f1df9364SStefan Roese 							(ddr3_tip_bus_write
496f1df9364SStefan Roese 							 (dev_num,
497f1df9364SStefan Roese 							  ACCESS_TYPE_UNICAST,
498f1df9364SStefan Roese 							  if_id,
499f1df9364SStefan Roese 							  ACCESS_TYPE_UNICAST, pup,
500f1df9364SStefan Roese 							  DDR_PHY_DATA, reg_addr,
501f1df9364SStefan Roese 							  (val & (~0xf)) |
502f1df9364SStefan Roese 							  vref_map[currrent_vref]));
503f1df9364SStefan Roese 						DEBUG_TRAINING_HW_ALG
504f1df9364SStefan Roese 							(DEBUG_LEVEL_TRACE,
505f1df9364SStefan Roese 							 ("VREF config, IF[ %d ]pup[ %d ] - Vref = %X (%d)\n",
506f1df9364SStefan Roese 							  if_id, pup,
507f1df9364SStefan Roese 							  (val & (~0xf)) |
508f1df9364SStefan Roese 							  vref_map[currrent_vref],
509f1df9364SStefan Roese 							  __LINE__));
510f1df9364SStefan Roese 					}
511f1df9364SStefan Roese 				} else {
512f1df9364SStefan Roese 					/* we change state and change step */
513f1df9364SStefan Roese 					if (pup_st[pup][if_id] == VREF_STEP_1) {
514f1df9364SStefan Roese 						pup_st[pup][if_id] =
515f1df9364SStefan Roese 							VREF_STEP_2;
516f1df9364SStefan Roese 						lim_vref[pup][if_id] =
517f1df9364SStefan Roese 							current_vref[pup]
518f1df9364SStefan Roese 							[if_id] - initial_step;
519f1df9364SStefan Roese 						last_valid_window[pup]
520f1df9364SStefan Roese 							[if_id] =
521f1df9364SStefan Roese 							current_valid_window[pup]
522f1df9364SStefan Roese 							[if_id];
523f1df9364SStefan Roese 						last_vref[pup][if_id] =
524f1df9364SStefan Roese 							current_vref[pup]
525f1df9364SStefan Roese 							[if_id];
526f1df9364SStefan Roese 						current_vref[pup][if_id] =
527f1df9364SStefan Roese 							last_vref[pup][if_id] -
528f1df9364SStefan Roese 							second_step;
529f1df9364SStefan Roese 
530f1df9364SStefan Roese 						/* Update the Vref for next stage */
531f1df9364SStefan Roese 						CHECK_STATUS
532f1df9364SStefan Roese 							(ddr3_tip_bus_read
533f1df9364SStefan Roese 							 (dev_num, if_id,
534f1df9364SStefan Roese 							  ACCESS_TYPE_UNICAST, pup,
535f1df9364SStefan Roese 							  DDR_PHY_DATA, reg_addr,
536f1df9364SStefan Roese 							  &val));
537f1df9364SStefan Roese 						CHECK_STATUS
538f1df9364SStefan Roese 							(ddr3_tip_bus_write
539f1df9364SStefan Roese 							 (dev_num,
540f1df9364SStefan Roese 							  ACCESS_TYPE_UNICAST,
541f1df9364SStefan Roese 							  if_id,
542f1df9364SStefan Roese 							  ACCESS_TYPE_UNICAST, pup,
543f1df9364SStefan Roese 							  DDR_PHY_DATA, reg_addr,
544f1df9364SStefan Roese 							  (val & (~0xf)) |
545f1df9364SStefan Roese 							  vref_map[current_vref[pup]
546f1df9364SStefan Roese 								   [if_id]]));
547f1df9364SStefan Roese 						DEBUG_TRAINING_HW_ALG
548f1df9364SStefan Roese 							(DEBUG_LEVEL_TRACE,
549f1df9364SStefan Roese 							 ("VREF config, IF[ %d ]pup[ %d ] - Vref = %X (%d)\n",
550f1df9364SStefan Roese 							  if_id, pup,
551f1df9364SStefan Roese 							  (val & (~0xf)) |
552f1df9364SStefan Roese 							  vref_map[current_vref[pup]
553f1df9364SStefan Roese 								   [if_id]],
554f1df9364SStefan Roese 							  __LINE__));
555f1df9364SStefan Roese 
556f1df9364SStefan Roese 					} else if (pup_st[pup][if_id] == VREF_STEP_2) {
557f1df9364SStefan Roese 						/*
558f1df9364SStefan Roese 						 * The last search was the max
559f1df9364SStefan Roese 						 * point set value and exit
560f1df9364SStefan Roese 						 */
561f1df9364SStefan Roese 						CHECK_STATUS
562f1df9364SStefan Roese 							(ddr3_tip_bus_read
563f1df9364SStefan Roese 							 (dev_num, if_id,
564f1df9364SStefan Roese 							  ACCESS_TYPE_UNICAST, pup,
565f1df9364SStefan Roese 							  DDR_PHY_DATA, reg_addr,
566f1df9364SStefan Roese 							  &val));
567f1df9364SStefan Roese 						CHECK_STATUS
568f1df9364SStefan Roese 							(ddr3_tip_bus_write
569f1df9364SStefan Roese 							 (dev_num,
570f1df9364SStefan Roese 							  ACCESS_TYPE_UNICAST,
571f1df9364SStefan Roese 							  if_id,
572f1df9364SStefan Roese 							  ACCESS_TYPE_UNICAST, pup,
573f1df9364SStefan Roese 							  DDR_PHY_DATA, reg_addr,
574f1df9364SStefan Roese 							  (val & (~0xf)) |
575f1df9364SStefan Roese 							  vref_map[last_vref[pup]
576f1df9364SStefan Roese 								   [if_id]]));
577f1df9364SStefan Roese 						DEBUG_TRAINING_HW_ALG
578f1df9364SStefan Roese 							(DEBUG_LEVEL_TRACE,
579f1df9364SStefan Roese 							 ("VREF config, IF[ %d ]pup[ %d ] - Vref = %X (%d)\n",
580f1df9364SStefan Roese 							  if_id, pup,
581f1df9364SStefan Roese 							  (val & (~0xf)) |
582f1df9364SStefan Roese 							  vref_map[last_vref[pup]
583f1df9364SStefan Roese 								   [if_id]],
584f1df9364SStefan Roese 							  __LINE__));
585f1df9364SStefan Roese 						pup_st[pup][if_id] =
586f1df9364SStefan Roese 							VREF_CONVERGE;
587f1df9364SStefan Roese 						algo_run_flag++;
588f1df9364SStefan Roese 						interface_state[if_id]++;
589f1df9364SStefan Roese 						DEBUG_TRAINING_HW_ALG
590f1df9364SStefan Roese 							(DEBUG_LEVEL_TRACE,
591f1df9364SStefan Roese 							 ("I/F[ %d ], pup[ %d ] VREF_CONVERGE - Vref = %X (%d)\n",
592f1df9364SStefan Roese 							  if_id, pup,
593f1df9364SStefan Roese 							  current_vref[pup]
594f1df9364SStefan Roese 							  [if_id], __LINE__));
595f1df9364SStefan Roese 					}
596f1df9364SStefan Roese 				}
597f1df9364SStefan Roese 			}
598f1df9364SStefan Roese 		}
599f1df9364SStefan Roese 	}
600f1df9364SStefan Roese 
601f1df9364SStefan Roese 	for (if_id = 0; if_id < MAX_INTERFACE_NUM; if_id++) {
6022b4ffbf6SChris Packham 		VALIDATE_IF_ACTIVE(tm->if_act_mask, if_id);
603f1df9364SStefan Roese 		for (pup = 0;
6042b4ffbf6SChris Packham 		     pup < octets_per_if_num; pup++) {
6052b4ffbf6SChris Packham 			VALIDATE_BUS_ACTIVE(tm->bus_act_mask, pup);
606f1df9364SStefan Roese 			CHECK_STATUS(ddr3_tip_bus_read
607f1df9364SStefan Roese 				     (dev_num, if_id,
608f1df9364SStefan Roese 				      ACCESS_TYPE_UNICAST, pup,
609f1df9364SStefan Roese 				      DDR_PHY_DATA, reg_addr, &val));
610f1df9364SStefan Roese 			DEBUG_TRAINING_HW_ALG(
611f1df9364SStefan Roese 				DEBUG_LEVEL_INFO,
612f1df9364SStefan Roese 				("FINAL values: I/F[ %d ], pup[ %d ] - Vref = %X (%d)\n",
613f1df9364SStefan Roese 				 if_id, pup, val, __LINE__));
614f1df9364SStefan Roese 		}
615f1df9364SStefan Roese 	}
616f1df9364SStefan Roese 
617f1df9364SStefan Roese 	flow_result[if_id] = TEST_SUCCESS;
618f1df9364SStefan Roese 
619f1df9364SStefan Roese 	/* restore start/end pattern */
620f1df9364SStefan Roese 	start_pattern = copy_start_pattern;
621f1df9364SStefan Roese 	end_pattern = copy_end_pattern;
622f1df9364SStefan Roese 
623f1df9364SStefan Roese 	return 0;
624f1df9364SStefan Roese }
625f1df9364SStefan Roese 
626f1df9364SStefan Roese /*
627f1df9364SStefan Roese  * CK/CA Delay
628f1df9364SStefan Roese  */
ddr3_tip_cmd_addr_init_delay(u32 dev_num,u32 adll_tap)629f1df9364SStefan Roese int ddr3_tip_cmd_addr_init_delay(u32 dev_num, u32 adll_tap)
630f1df9364SStefan Roese {
631f1df9364SStefan Roese 	u32 if_id = 0;
632f1df9364SStefan Roese 	u32 ck_num_adll_tap = 0, ca_num_adll_tap = 0, data = 0;
6332b4ffbf6SChris Packham 	struct mv_ddr_topology_map *tm = mv_ddr_topology_map_get();
634f1df9364SStefan Roese 
635f1df9364SStefan Roese 	/*
636f1df9364SStefan Roese 	 * ck_delay_table is delaying the of the clock signal only.
637f1df9364SStefan Roese 	 * (to overcome timing issues between_c_k & command/address signals)
638f1df9364SStefan Roese 	 */
639f1df9364SStefan Roese 	/*
640f1df9364SStefan Roese 	 * ca_delay is delaying the of the entire command & Address signals
641f1df9364SStefan Roese 	 * (include Clock signal to overcome DGL error on the Clock versus
642f1df9364SStefan Roese 	 * the DQS).
643f1df9364SStefan Roese 	 */
644f1df9364SStefan Roese 
645f1df9364SStefan Roese 	/* Calc ADLL Tap */
6462b4ffbf6SChris Packham 	if (ck_delay == PARAM_UNDEFINED)
647f1df9364SStefan Roese 		DEBUG_TRAINING_HW_ALG(
648f1df9364SStefan Roese 			DEBUG_LEVEL_ERROR,
6492b4ffbf6SChris Packham 			("ERROR: ck_delay is not initialized!\n"));
650f1df9364SStefan Roese 
651f1df9364SStefan Roese 	for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
6522b4ffbf6SChris Packham 		VALIDATE_IF_ACTIVE(tm->if_act_mask, if_id);
653f1df9364SStefan Roese 
6542b4ffbf6SChris Packham 		/* Calc delay ps in ADLL tap */
6552b4ffbf6SChris Packham 		ck_num_adll_tap = ck_delay / adll_tap;
656f1df9364SStefan Roese 		ca_num_adll_tap = ca_delay / adll_tap;
6572b4ffbf6SChris Packham 
658f1df9364SStefan Roese 		data = (ck_num_adll_tap & 0x3f) +
659f1df9364SStefan Roese 			((ca_num_adll_tap & 0x3f) << 10);
660f1df9364SStefan Roese 
661f1df9364SStefan Roese 		/*
662f1df9364SStefan Roese 		 * Set the ADLL number to the CK ADLL for Interfaces for
663f1df9364SStefan Roese 		 * all Pup
664f1df9364SStefan Roese 		 */
665f1df9364SStefan Roese 		DEBUG_TRAINING_HW_ALG(
666f1df9364SStefan Roese 			DEBUG_LEVEL_TRACE,
667f1df9364SStefan Roese 			("ck_num_adll_tap %d ca_num_adll_tap %d adll_tap %d\n",
668f1df9364SStefan Roese 			 ck_num_adll_tap, ca_num_adll_tap, adll_tap));
669f1df9364SStefan Roese 
670f1df9364SStefan Roese 		CHECK_STATUS(ddr3_tip_bus_write(dev_num, ACCESS_TYPE_UNICAST,
671f1df9364SStefan Roese 						if_id, ACCESS_TYPE_MULTICAST,
672f1df9364SStefan Roese 						PARAM_NOT_CARE, DDR_PHY_CONTROL,
673f1df9364SStefan Roese 						0x0, data));
674f1df9364SStefan Roese 	}
675f1df9364SStefan Roese 
676f1df9364SStefan Roese 	return MV_OK;
677f1df9364SStefan Roese }
678