static int ddr3_read_leveling_single_cs_window_mode()

in drivers/ddr/marvell/axp/ddr3_read_leveling.c [752:1213]


static int ddr3_read_leveling_single_cs_window_mode(u32 cs, u32 freq,
						    int ratio_2to1, u32 ecc,
						    MV_DRAM_INFO *dram_info)
{
	u32 reg, delay, phase, sum, pup, rd_sample_delay, add, locked_pups,
	    repeat_max_cnt, sdram_offset, final_sum, locked_sum;
	u32 delay_s, delay_e, tmp, phase_min, ui_max_delay;
	int all_locked, first_octet_locked, counter_in_progress;
	int final_delay = 0;

	DEBUG_RL_FULL_C("DDR3 - Read Leveling - Single CS - ", (u32) cs, 1);

	/* Init values */
	phase = 0;
	delay = 0;
	rd_sample_delay = dram_info->cl;
	all_locked = 0;
	first_octet_locked = 0;
	repeat_max_cnt = 0;
	sum = 0;
	final_sum = 0;
	locked_sum = 0;

	for (pup = 0; pup < (dram_info->num_of_std_pups * (1 - ecc) + ecc);
	     pup++)
		dram_info->rl_val[cs][pup + ecc * ECC_BIT][S] = 0;

	/* Main loop */
	while (!all_locked) {
		counter_in_progress = 0;

		DEBUG_RL_FULL_S("DDR3 - Read Leveling - RdSmplDly = ");
		DEBUG_RL_FULL_D(rd_sample_delay, 2);
		DEBUG_RL_FULL_S(", RdRdyDly = ");
		DEBUG_RL_FULL_D(dram_info->rd_rdy_dly, 2);
		DEBUG_RL_FULL_S(", Phase = ");
		DEBUG_RL_FULL_D(phase, 1);
		DEBUG_RL_FULL_S(", Delay = ");
		DEBUG_RL_FULL_D(delay, 2);
		DEBUG_RL_FULL_S("\n");

		/*
		 * Broadcast to all PUPs current RL delays: DQS phase,leveling
		 * delay
		 */
		ddr3_write_pup_reg(PUP_RL_MODE, cs, PUP_BC, phase, delay);

		/* Reset PHY read FIFO */
		reg = reg_read(REG_DRAM_TRAINING_2_ADDR) |
			(1 << REG_DRAM_TRAINING_2_FIFO_RST_OFFS);
		/* 0x15B8 - Training SW 2 Register */
		reg_write(REG_DRAM_TRAINING_2_ADDR, reg);

		do {
			reg = (reg_read(REG_DRAM_TRAINING_2_ADDR)) &
				(1 << REG_DRAM_TRAINING_2_FIFO_RST_OFFS);
		} while (reg);	/* Wait for '0' */

		/* Read pattern from SDRAM */
		sdram_offset = cs * (SDRAM_CS_SIZE + 1) + SDRAM_RL_OFFS;
		locked_pups = 0;
		if (MV_OK !=
		    ddr3_sdram_compare(dram_info, 0xFF, &locked_pups,
				       rl_pattern, LEN_STD_PATTERN,
				       sdram_offset, 0, 0, NULL, 0))
			return MV_DDR3_TRAINING_ERR_RD_LVL_WIN_PATTERN;

		/* Octet evaluation */
		for (pup = 0; pup < (dram_info->num_of_std_pups *
				     (1 - ecc) + ecc); pup++) {
			/* pup_num = Q or 1 for ECC */
			int idx;

			idx = pup + ecc * ECC_BIT;

			/* Check Overrun */
			if (!((reg_read(REG_DRAM_TRAINING_2_ADDR) >>
			      (REG_DRAM_TRAINING_2_OVERRUN_OFFS +
			       pup)) & 0x1)) {
				/* If no OverRun */

				/* Inside the window */
				if (dram_info->rl_val[cs][idx][S] == RL_WINDOW_STATE) {
					/*
					 * Match expected value ? - Update
					 * State Machine
					 */
					if (((~locked_pups >> pup) & 0x1)
					    && (final_delay == 0)) {
						/* Match - Still inside the Window */
						DEBUG_RL_FULL_C("DDR3 - Read Leveling - We got another match inside the window  for pup: ",
								(u32)pup, 1);

					} else {
						/* We got fail -> this is the end of the window */
						dram_info->rl_val[cs][idx][DE] = delay;
						dram_info->rl_val[cs][idx][PE] = phase;
						/* Go to Final State */
						dram_info->rl_val[cs][idx][S]++;
						final_sum++;
						DEBUG_RL_FULL_C("DDR3 - Read Leveling - We finished the window for pup: ",
								(u32)pup, 1);
					}

					/* Before the start of the window */
				} else if (dram_info->rl_val[cs][idx][S] ==
					   RL_UNLOCK_STATE) {
					/* Must be RL_UNLOCK_STATE */
					/*
					 * Match expected value ? - Update
					 * State Machine
					 */
					if (dram_info->rl_val[cs][idx][C] <
					    RL_RETRY_COUNT) {
						if (((~locked_pups >> pup) & 0x1)) {
							/* Match */
							DEBUG_RL_FULL_C("DDR3 - Read Leveling - We have no overrun and a match on pup: ",
									(u32)pup, 1);
							dram_info->rl_val[cs][idx][C]++;

							/* If pup got to last state - lock the delays */
							if (dram_info->rl_val[cs][idx][C] ==
							    RL_RETRY_COUNT) {
								dram_info->rl_val[cs][idx][C] = 0;
								dram_info->rl_val[cs][idx][DS] =
									delay;
								dram_info->rl_val[cs][idx][PS] =
									phase;
								dram_info->rl_val[cs][idx][S]++;	/* Go to Window State */
								locked_sum++;
								/* Will count the pups that got locked */

								/* IF First lock - need to lock delays */
								if (first_octet_locked == 0) {
									DEBUG_RL_FULL_C("DDR3 - Read Leveling - We got first lock on pup: ",
											(u32)pup, 1);
									first_octet_locked
									    =
									    1;
								}
							}

							/* if pup is in not in final state but there was match - dont increment counter */
							else {
								counter_in_progress
								    = 1;
							}
						}
					}
				}
			} else {
				DEBUG_RL_FULL_C("DDR3 - Read Leveling - We got overrun on pup: ",
						(u32)pup, 1);
				counter_in_progress = 1;
			}
		}

		if (final_sum == (dram_info->num_of_std_pups * (1 - ecc) + ecc)) {
			all_locked = 1;
			DEBUG_RL_FULL_S("DDR3 - Read Leveling - Single Cs - All pups locked\n");
		}

		/*
		 * This is a fix for unstable condition where pups are
		 * toggling between match and no match
		 */
		/*
		 * If some of the pups is >1 <3, check if we did it too many
		 * times
		 */
		if (counter_in_progress == 1) {
			if (repeat_max_cnt < RL_RETRY_COUNT) {
				/* Notify at least one Counter is >=1 and < 3 */
				repeat_max_cnt++;
				counter_in_progress = 1;
				DEBUG_RL_FULL_S("DDR3 - Read Leveling - Counter is >=1 and <3\n");
				DEBUG_RL_FULL_S("DDR3 - Read Leveling - So we will not increment the delay to see if locked again\n");
			} else {
				DEBUG_RL_FULL_S("DDR3 - Read Leveling - repeat_max_cnt reached max so now we will increment the delay\n");
				counter_in_progress = 0;
			}
		}

		/*
		 * Check some of the pups are in the middle of state machine
		 * and don't increment the delays
		 */
		if (!counter_in_progress && !all_locked) {
			repeat_max_cnt = 0;
			if (!ratio_2to1)
				ui_max_delay = MAX_DELAY_INV;
			else
				ui_max_delay = MAX_DELAY;

			/* Increment Delay */
			if (delay < ui_max_delay) {
				/* Delay Incrementation */
				delay++;
				if (delay == ui_max_delay) {
					/*
					 * Mark the last delay/pahse place
					 * for window final place
					 */
					if ((!ratio_2to1
					     && phase == MAX_PHASE_RL_L_1TO1)
					    || (ratio_2to1
						&& phase ==
						MAX_PHASE_RL_L_2TO1))
						final_delay = 1;
				}
			} else {
				/* Phase+CL Incrementation */
				delay = 0;
				if (!ratio_2to1) {
					/* 1:1 mode */
					if (first_octet_locked) {
						/* some pupet was Locked */
						if (phase < MAX_PHASE_RL_L_1TO1) {
#ifdef RL_WINDOW_WA
							if (phase == 0)
#else
							if (phase == 1)
#endif
								phase = 4;
							else
								phase++;
						} else {
							DEBUG_RL_FULL_S("DDR3 - Read Leveling - ERROR - NOT all PUPs Locked\n");
							return MV_DDR3_TRAINING_ERR_RD_LVL_WIN_PUP_UNLOCK;
						}
					} else {
						/* No Pup was Locked */
						if (phase < MAX_PHASE_RL_UL_1TO1) {
#ifdef RL_WINDOW_WA
							if (phase == 0)
								phase = 4;
#else
							phase++;
#endif
						} else
							phase = 0;
					}
				} else {
					/* 2:1 mode */
					if (first_octet_locked) {
						/* Some Pup was Locked */
						if (phase < MAX_PHASE_RL_L_2TO1) {
							phase++;
						} else {
							DEBUG_RL_FULL_S("DDR3 - Read Leveling - ERROR - NOT all PUPs Locked\n");
							return MV_DDR3_TRAINING_ERR_RD_LVL_WIN_PUP_UNLOCK;
						}
					} else {
						/* No Pup was Locked */
						if (phase < MAX_PHASE_RL_UL_2TO1)
							phase++;
						else
							phase = 0;
					}
				}

				/*
				 * If we finished a full Phases cycle (so
				 * now phase = 0, need to increment
				 * rd_sample_dly
				 */
				if (phase == 0 && first_octet_locked == 0) {
					rd_sample_delay++;

					/* Set current rd_sample_delay  */
					reg = reg_read(REG_READ_DATA_SAMPLE_DELAYS_ADDR);
					reg &= ~(REG_READ_DATA_SAMPLE_DELAYS_MASK <<
						 (REG_READ_DATA_SAMPLE_DELAYS_OFFS
						  * cs));
					reg |= (rd_sample_delay <<
						(REG_READ_DATA_SAMPLE_DELAYS_OFFS *
						 cs));
					reg_write(REG_READ_DATA_SAMPLE_DELAYS_ADDR,
						  reg);
				}

				/*
				 * Set current rdReadyDelay according to the
				 * hash table (Need to do this in every phase
				 * change)
				 */
				if (!ratio_2to1) {
					/* 1:1 mode */
					add = reg_read(REG_TRAINING_DEBUG_2_ADDR);
					switch (phase) {
					case 0:
						add = add >>
							REG_TRAINING_DEBUG_2_OFFS;
						break;
					case 1:
						add = add >>
							(REG_TRAINING_DEBUG_2_OFFS
							 + 3);
						break;
					case 4:
						add = add >>
							(REG_TRAINING_DEBUG_2_OFFS
							 + 6);
						break;
					case 5:
						add = add >>
							(REG_TRAINING_DEBUG_2_OFFS
							 + 9);
						break;
					}
				} else {
					/* 2:1 mode */
					add = reg_read(REG_TRAINING_DEBUG_3_ADDR);
					add = (add >> phase *
					       REG_TRAINING_DEBUG_3_OFFS);
				}
				add &= REG_TRAINING_DEBUG_2_MASK;
				reg = reg_read(REG_READ_DATA_READY_DELAYS_ADDR);
				reg &= ~(REG_READ_DATA_READY_DELAYS_MASK <<
					 (REG_READ_DATA_READY_DELAYS_OFFS * cs));
				reg |= ((rd_sample_delay + add) <<
					(REG_READ_DATA_READY_DELAYS_OFFS * cs));
				reg_write(REG_READ_DATA_READY_DELAYS_ADDR, reg);
				dram_info->rd_smpl_dly = rd_sample_delay;
				dram_info->rd_rdy_dly = rd_sample_delay + add;
			}

			/* Reset counters for pups with states<RD_STATE_COUNT */
			for (pup = 0;
			     pup <
			     (dram_info->num_of_std_pups * (1 - ecc) + ecc);
			     pup++) {
				if (dram_info->rl_val[cs][idx][C] < RL_RETRY_COUNT)
					dram_info->rl_val[cs][idx][C] = 0;
			}
		}
	}

	phase_min = 10;

	for (pup = 0; pup < (dram_info->num_of_std_pups); pup++) {
		DEBUG_RL_S("DDR3 - Read Leveling - Window info - PUP: ");
		DEBUG_RL_D((u32) pup, 1);
		DEBUG_RL_S(", PS: ");
		DEBUG_RL_D((u32) dram_info->rl_val[cs][pup][PS], 1);
		DEBUG_RL_S(", DS: ");
		DEBUG_RL_D((u32) dram_info->rl_val[cs][pup][DS], 2);
		DEBUG_RL_S(", PE: ");
		DEBUG_RL_D((u32) dram_info->rl_val[cs][pup][PE], 1);
		DEBUG_RL_S(", DE: ");
		DEBUG_RL_D((u32) dram_info->rl_val[cs][pup][DE], 2);
		DEBUG_RL_S("\n");
	}

	/* Find center of the window procedure */
	for (pup = 0; pup < (dram_info->num_of_std_pups * (1 - ecc) + ecc);
	     pup++) {
#ifdef RL_WINDOW_WA
		if (!ratio_2to1) {	/* 1:1 mode */
			if (dram_info->rl_val[cs][idx][PS] == 4)
				dram_info->rl_val[cs][idx][PS] = 1;
			if (dram_info->rl_val[cs][idx][PE] == 4)
				dram_info->rl_val[cs][idx][PE] = 1;

			delay_s = dram_info->rl_val[cs][idx][PS] *
				MAX_DELAY_INV + dram_info->rl_val[cs][idx][DS];
			delay_e = dram_info->rl_val[cs][idx][PE] *
				MAX_DELAY_INV + dram_info->rl_val[cs][idx][DE];

			tmp = (delay_e - delay_s) / 2 + delay_s;
			phase = tmp / MAX_DELAY_INV;
			if (phase == 1)	/* 1:1 mode */
				phase = 4;

			if (phase < phase_min)	/* for the read ready delay */
				phase_min = phase;

			dram_info->rl_val[cs][idx][P] = phase;
			dram_info->rl_val[cs][idx][D] = tmp % MAX_DELAY_INV;

		} else {
			delay_s = dram_info->rl_val[cs][idx][PS] *
				MAX_DELAY + dram_info->rl_val[cs][idx][DS];
			delay_e = dram_info->rl_val[cs][idx][PE] *
				MAX_DELAY + dram_info->rl_val[cs][idx][DE];

			tmp = (delay_e - delay_s) / 2 + delay_s;
			phase = tmp / MAX_DELAY;

			if (phase < phase_min)	/* for the read ready delay */
				phase_min = phase;

			dram_info->rl_val[cs][idx][P] = phase;
			dram_info->rl_val[cs][idx][D] = tmp % MAX_DELAY;
		}
#else
		if (!ratio_2to1) {	/* 1:1 mode */
			if (dram_info->rl_val[cs][idx][PS] > 1)
				dram_info->rl_val[cs][idx][PS] -= 2;
			if (dram_info->rl_val[cs][idx][PE] > 1)
				dram_info->rl_val[cs][idx][PE] -= 2;
		}

		delay_s = dram_info->rl_val[cs][idx][PS] * MAX_DELAY +
			dram_info->rl_val[cs][idx][DS];
		delay_e = dram_info->rl_val[cs][idx][PE] * MAX_DELAY +
			dram_info->rl_val[cs][idx][DE];

		tmp = (delay_e - delay_s) / 2 + delay_s;
		phase = tmp / MAX_DELAY;
		if (!ratio_2to1 && phase > 1)	/* 1:1 mode */
			phase += 2;

		if (phase < phase_min)	/* for the read ready delay */
			phase_min = phase;

		dram_info->rl_val[cs][idx][P] = phase;
		dram_info->rl_val[cs][idx][D] = tmp % MAX_DELAY;
#endif
	}

	/* Set current rdReadyDelay according to the hash table (Need to do this in every phase change) */
	if (!ratio_2to1) {	/* 1:1 mode */
		add = reg_read(REG_TRAINING_DEBUG_2_ADDR);
		switch (phase_min) {
		case 0:
			add = (add >> REG_TRAINING_DEBUG_2_OFFS);
			break;
		case 1:
			add = (add >> (REG_TRAINING_DEBUG_2_OFFS + 3));
			break;
		case 4:
			add = (add >> (REG_TRAINING_DEBUG_2_OFFS + 6));
			break;
		case 5:
			add = (add >> (REG_TRAINING_DEBUG_2_OFFS + 9));
			break;
		}
	} else {		/* 2:1 mode */
		add = reg_read(REG_TRAINING_DEBUG_3_ADDR);
		add = (add >> phase_min * REG_TRAINING_DEBUG_3_OFFS);
	}

	add &= REG_TRAINING_DEBUG_2_MASK;
	reg = reg_read(REG_READ_DATA_READY_DELAYS_ADDR);
	reg &=
	    ~(REG_READ_DATA_READY_DELAYS_MASK <<
	      (REG_READ_DATA_READY_DELAYS_OFFS * cs));
	reg |=
	    ((rd_sample_delay + add) << (REG_READ_DATA_READY_DELAYS_OFFS * cs));
	reg_write(REG_READ_DATA_READY_DELAYS_ADDR, reg);
	dram_info->rd_rdy_dly = rd_sample_delay + add;

	for (cs = 0; cs < dram_info->num_cs; cs++) {
		for (pup = 0; pup < dram_info->num_of_total_pups; pup++) {
			reg = ddr3_read_pup_reg(PUP_RL_MODE + 0x1, cs, pup);
			dram_info->rl_val[cs][pup][DQS] = (reg & 0x3F);
		}
	}

	return MV_OK;
}