int ddr3_tip_vref()

in drivers/ddr/marvell/a38x/ddr3_training_hw_algo.c [147:624]


int ddr3_tip_vref(u32 dev_num)
{
	/*
	 * The Vref register have non linear order. Need to check what will be
	 * in future projects.
	 */
	u32 vref_map[8] = {
		1, 2, 3, 4, 5, 6, 7, 0
	};
	/* State and parameter definitions */
	u32 initial_step = VREF_INITIAL_STEP;
	/* need to be assign with minus ????? */
	u32 second_step = VREF_SECOND_STEP;
	u32 algo_run_flag = 0, currrent_vref = 0;
	u32 while_count = 0;
	u32 pup = 0, if_id = 0, num_pup = 0, rep = 0;
	u32 val = 0;
	u32 reg_addr = 0xa8;
	u32 copy_start_pattern, copy_end_pattern;
	enum hws_result *flow_result = ddr3_tip_get_result_ptr(training_stage);
	u8 res[4];
	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();

	CHECK_STATUS(ddr3_tip_special_rx(dev_num));

	/* save start/end pattern */
	copy_start_pattern = start_pattern;
	copy_end_pattern = end_pattern;

	/* set vref as centralization pattern */
	start_pattern = PATTERN_VREF;
	end_pattern = PATTERN_VREF;

	/* init params */
	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++) {
			current_vref[pup][if_id] = 0;
			last_vref[pup][if_id] = 0;
			lim_vref[pup][if_id] = 0;
			current_valid_window[pup][if_id] = 0;
			last_valid_window[pup][if_id] = 0;
			if (vref_window_size[if_id][pup] >
			    vref_window_size_th) {
				pup_st[pup][if_id] = VREF_CONVERGE;
				DEBUG_TRAINING_HW_ALG(
					DEBUG_LEVEL_INFO,
					("VREF config, IF[ %d ]pup[ %d ] - Vref tune not requered (%d)\n",
					 if_id, pup, __LINE__));
			} else {
				pup_st[pup][if_id] = VREF_STEP_1;
				CHECK_STATUS(ddr3_tip_bus_read
					     (dev_num, if_id,
					      ACCESS_TYPE_UNICAST, pup,
					      DDR_PHY_DATA, reg_addr, &val));
				CHECK_STATUS(ddr3_tip_bus_write
					     (dev_num, ACCESS_TYPE_UNICAST,
					      if_id, ACCESS_TYPE_UNICAST,
					      pup, DDR_PHY_DATA, reg_addr,
					      (val & (~0xf)) | vref_map[0]));
				DEBUG_TRAINING_HW_ALG(
					DEBUG_LEVEL_INFO,
					("VREF config, IF[ %d ]pup[ %d ] - Vref = %X (%d)\n",
					 if_id, pup,
					 (val & (~0xf)) | vref_map[0],
					 __LINE__));
			}
		}
		interface_state[if_id] = 0;
	}

	/* TODO: Set number of active interfaces */
	num_pup = octets_per_if_num * MAX_INTERFACE_NUM;

	while ((algo_run_flag <= num_pup) & (while_count < 10)) {
		while_count++;
		for (rep = 1; rep < 4; rep++) {
			ddr3_tip_centr_skip_min_win_check = 1;
			ddr3_tip_centralization_rx(dev_num);
			ddr3_tip_centr_skip_min_win_check = 0;

			/* Read Valid window results only for non converge pups */
			for (if_id = 0; if_id < MAX_INTERFACE_NUM; if_id++) {
				VALIDATE_IF_ACTIVE(tm->if_act_mask, if_id);
				if (interface_state[if_id] != 4) {
					get_valid_win_rx(dev_num, if_id, res);
					for (pup = 0;
					     pup < octets_per_if_num;
					     pup++) {
						VALIDATE_BUS_ACTIVE
							(tm->bus_act_mask, pup);
						if (pup_st[pup]
						    [if_id] ==
						    VREF_CONVERGE)
							continue;

						current_valid_window[pup]
							[if_id] =
							(current_valid_window[pup]
							 [if_id] * (rep - 1) +
							 1000 * res[pup]) / rep;
					}
				}
			}
		}

		for (if_id = 0; if_id < MAX_INTERFACE_NUM; if_id++) {
			VALIDATE_IF_ACTIVE(tm->if_act_mask, if_id);
			DEBUG_TRAINING_HW_ALG(
				DEBUG_LEVEL_TRACE,
				("current_valid_window: IF[ %d ] - ", if_id));

			for (pup = 0;
			     pup < octets_per_if_num; pup++) {
				VALIDATE_BUS_ACTIVE(tm->bus_act_mask, pup);
				DEBUG_TRAINING_HW_ALG(DEBUG_LEVEL_TRACE,
						      ("%d ",
						       current_valid_window
						       [pup][if_id]));
			}
			DEBUG_TRAINING_HW_ALG(DEBUG_LEVEL_TRACE, ("\n"));
		}

		/* Compare results and respond as function of state */
		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_TRAINING_HW_ALG(DEBUG_LEVEL_TRACE,
						      ("I/F[ %d ], pup[ %d ] STATE #%d (%d)\n",
						       if_id, pup,
						       pup_st[pup]
						       [if_id], __LINE__));

				if (pup_st[pup][if_id] == VREF_CONVERGE)
					continue;

				DEBUG_TRAINING_HW_ALG(DEBUG_LEVEL_TRACE,
						      ("I/F[ %d ], pup[ %d ] CHECK progress - Current %d Last %d, limit VREF %d (%d)\n",
						       if_id, pup,
						       current_valid_window[pup]
						       [if_id],
						       last_valid_window[pup]
						       [if_id], lim_vref[pup]
						       [if_id], __LINE__));

				/*
				 * The -1 is for solution resolution +/- 1 tap
				 * of ADLL
				 */
				if (current_valid_window[pup][if_id] + 200 >=
				    (last_valid_window[pup][if_id])) {
					if (pup_st[pup][if_id] == VREF_STEP_1) {
						/*
						 * We stay in the same state and
						 * step just update the window
						 * size (take the max) and Vref
						 */
						if (current_vref[pup]
						    [if_id] == VREF_MAX_INDEX) {
							/*
							 * If we step to the end
							 * and didn't converge
							 * to some particular
							 * better Vref value
							 * define the pup as
							 * converge and step
							 * back to nominal
							 * Vref.
							 */
							pup_st[pup]
								[if_id] =
								VREF_CONVERGE;
							algo_run_flag++;
							interface_state
								[if_id]++;
							DEBUG_TRAINING_HW_ALG
								(DEBUG_LEVEL_TRACE,
								 ("I/F[ %d ], pup[ %d ] VREF_CONVERGE - Vref = %X (%d)\n",
								  if_id, pup,
								  current_vref[pup]
								  [if_id],
								  __LINE__));
						} else {
							/* continue to update the Vref index */
							current_vref[pup]
								[if_id] =
								((current_vref[pup]
								  [if_id] +
								  initial_step) >
								 VREF_MAX_INDEX) ?
								VREF_MAX_INDEX
								: (current_vref[pup]
								   [if_id] +
								   initial_step);
							if (current_vref[pup]
							    [if_id] ==
							    VREF_MAX_INDEX) {
								pup_st[pup]
									[if_id]
									=
									VREF_STEP_2;
							}
							lim_vref[pup]
								[if_id] =
								last_vref[pup]
								[if_id] =
								current_vref[pup]
								[if_id];
						}

						last_valid_window[pup]
							[if_id] =
							GET_MAX(current_valid_window
								[pup][if_id],
								last_valid_window
								[pup]
								[if_id]);

						/* update the Vref for next stage */
						currrent_vref =
							current_vref[pup]
							[if_id];
						CHECK_STATUS
							(ddr3_tip_bus_read
							 (dev_num, if_id,
							  ACCESS_TYPE_UNICAST, pup,
							  DDR_PHY_DATA, reg_addr,
							  &val));
						CHECK_STATUS
							(ddr3_tip_bus_write
							 (dev_num,
							  ACCESS_TYPE_UNICAST,
							  if_id,
							  ACCESS_TYPE_UNICAST, pup,
							  DDR_PHY_DATA, reg_addr,
							  (val & (~0xf)) |
							  vref_map[currrent_vref]));
						DEBUG_TRAINING_HW_ALG
							(DEBUG_LEVEL_TRACE,
							 ("VREF config, IF[ %d ]pup[ %d ] - Vref = %X (%d)\n",
							  if_id, pup,
							  (val & (~0xf)) |
							  vref_map[currrent_vref],
							  __LINE__));
					} else if (pup_st[pup][if_id]
						   == VREF_STEP_2) {
						/*
						 * We keep on search back with
						 * the same step size.
						 */
						last_valid_window[pup]
							[if_id] =
							GET_MAX(current_valid_window
								[pup][if_id],
								last_valid_window
								[pup]
								[if_id]);
						last_vref[pup][if_id] =
							current_vref[pup]
							[if_id];

						/* we finish all search space */
						if ((current_vref[pup]
						     [if_id] - second_step) == lim_vref[pup][if_id]) {
							/*
							 * If we step to the end
							 * and didn't converge
							 * to some particular
							 * better Vref value
							 * define the pup as
							 * converge and step
							 * back to nominal
							 * Vref.
							 */
							pup_st[pup]
								[if_id] =
								VREF_CONVERGE;
							algo_run_flag++;

							interface_state
								[if_id]++;

							current_vref[pup]
								[if_id] =
								(current_vref[pup]
								 [if_id] -
								 second_step);

							DEBUG_TRAINING_HW_ALG
								(DEBUG_LEVEL_TRACE,
								 ("I/F[ %d ], pup[ %d ] VREF_CONVERGE - Vref = %X (%d)\n",
								  if_id, pup,
								  current_vref[pup]
								  [if_id],
								  __LINE__));
						} else
							/* we finish all search space */
							if (current_vref[pup]
							    [if_id] ==
							    lim_vref[pup]
							    [if_id]) {
								/*
								 * If we step to the end
								 * and didn't converge
								 * to some particular
								 * better Vref value
								 * define the pup as
								 * converge and step
								 * back to nominal
								 * Vref.
								 */
								pup_st[pup]
									[if_id] =
									VREF_CONVERGE;

								algo_run_flag++;
								interface_state
									[if_id]++;
								DEBUG_TRAINING_HW_ALG
									(DEBUG_LEVEL_TRACE,
									 ("I/F[ %d ], pup[ %d ] VREF_CONVERGE - Vref = %X (%d)\n",
									  if_id, pup,
									  current_vref[pup]
									  [if_id],
									  __LINE__));
							} else {
								current_vref[pup]
									[if_id] =
									current_vref[pup]
									[if_id] -
									second_step;
							}

						/* Update the Vref for next stage */
						currrent_vref =
							current_vref[pup]
							[if_id];
						CHECK_STATUS
							(ddr3_tip_bus_read
							 (dev_num, if_id,
							  ACCESS_TYPE_UNICAST, pup,
							  DDR_PHY_DATA, reg_addr,
							  &val));
						CHECK_STATUS
							(ddr3_tip_bus_write
							 (dev_num,
							  ACCESS_TYPE_UNICAST,
							  if_id,
							  ACCESS_TYPE_UNICAST, pup,
							  DDR_PHY_DATA, reg_addr,
							  (val & (~0xf)) |
							  vref_map[currrent_vref]));
						DEBUG_TRAINING_HW_ALG
							(DEBUG_LEVEL_TRACE,
							 ("VREF config, IF[ %d ]pup[ %d ] - Vref = %X (%d)\n",
							  if_id, pup,
							  (val & (~0xf)) |
							  vref_map[currrent_vref],
							  __LINE__));
					}
				} else {
					/* we change state and change step */
					if (pup_st[pup][if_id] == VREF_STEP_1) {
						pup_st[pup][if_id] =
							VREF_STEP_2;
						lim_vref[pup][if_id] =
							current_vref[pup]
							[if_id] - initial_step;
						last_valid_window[pup]
							[if_id] =
							current_valid_window[pup]
							[if_id];
						last_vref[pup][if_id] =
							current_vref[pup]
							[if_id];
						current_vref[pup][if_id] =
							last_vref[pup][if_id] -
							second_step;

						/* Update the Vref for next stage */
						CHECK_STATUS
							(ddr3_tip_bus_read
							 (dev_num, if_id,
							  ACCESS_TYPE_UNICAST, pup,
							  DDR_PHY_DATA, reg_addr,
							  &val));
						CHECK_STATUS
							(ddr3_tip_bus_write
							 (dev_num,
							  ACCESS_TYPE_UNICAST,
							  if_id,
							  ACCESS_TYPE_UNICAST, pup,
							  DDR_PHY_DATA, reg_addr,
							  (val & (~0xf)) |
							  vref_map[current_vref[pup]
								   [if_id]]));
						DEBUG_TRAINING_HW_ALG
							(DEBUG_LEVEL_TRACE,
							 ("VREF config, IF[ %d ]pup[ %d ] - Vref = %X (%d)\n",
							  if_id, pup,
							  (val & (~0xf)) |
							  vref_map[current_vref[pup]
								   [if_id]],
							  __LINE__));

					} else if (pup_st[pup][if_id] == VREF_STEP_2) {
						/*
						 * The last search was the max
						 * point set value and exit
						 */
						CHECK_STATUS
							(ddr3_tip_bus_read
							 (dev_num, if_id,
							  ACCESS_TYPE_UNICAST, pup,
							  DDR_PHY_DATA, reg_addr,
							  &val));
						CHECK_STATUS
							(ddr3_tip_bus_write
							 (dev_num,
							  ACCESS_TYPE_UNICAST,
							  if_id,
							  ACCESS_TYPE_UNICAST, pup,
							  DDR_PHY_DATA, reg_addr,
							  (val & (~0xf)) |
							  vref_map[last_vref[pup]
								   [if_id]]));
						DEBUG_TRAINING_HW_ALG
							(DEBUG_LEVEL_TRACE,
							 ("VREF config, IF[ %d ]pup[ %d ] - Vref = %X (%d)\n",
							  if_id, pup,
							  (val & (~0xf)) |
							  vref_map[last_vref[pup]
								   [if_id]],
							  __LINE__));
						pup_st[pup][if_id] =
							VREF_CONVERGE;
						algo_run_flag++;
						interface_state[if_id]++;
						DEBUG_TRAINING_HW_ALG
							(DEBUG_LEVEL_TRACE,
							 ("I/F[ %d ], pup[ %d ] VREF_CONVERGE - Vref = %X (%d)\n",
							  if_id, pup,
							  current_vref[pup]
							  [if_id], __LINE__));
					}
				}
			}
		}
	}

	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);
			CHECK_STATUS(ddr3_tip_bus_read
				     (dev_num, if_id,
				      ACCESS_TYPE_UNICAST, pup,
				      DDR_PHY_DATA, reg_addr, &val));
			DEBUG_TRAINING_HW_ALG(
				DEBUG_LEVEL_INFO,
				("FINAL values: I/F[ %d ], pup[ %d ] - Vref = %X (%d)\n",
				 if_id, pup, val, __LINE__));
		}
	}

	flow_result[if_id] = TEST_SUCCESS;

	/* restore start/end pattern */
	start_pattern = copy_start_pattern;
	end_pattern = copy_end_pattern;

	return 0;
}