123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675 |
- // SPDX-License-Identifier: GPL-2.0
- /*
- * Copyright (C) Marvell International Ltd. and its affiliates
- */
- #include "ddr3_init.h"
- #define VREF_INITIAL_STEP 3
- #define VREF_SECOND_STEP 1
- #define VREF_MAX_INDEX 7
- #define MAX_VALUE (1024 - 1)
- #define MIN_VALUE (-MAX_VALUE)
- #define GET_RD_SAMPLE_DELAY(data, cs) ((data >> rd_sample_mask[cs]) & 0xf)
- u32 ca_delay;
- int ddr3_tip_centr_skip_min_win_check = 0;
- u8 current_vref[MAX_BUS_NUM][MAX_INTERFACE_NUM];
- u8 last_vref[MAX_BUS_NUM][MAX_INTERFACE_NUM];
- u16 current_valid_window[MAX_BUS_NUM][MAX_INTERFACE_NUM];
- u16 last_valid_window[MAX_BUS_NUM][MAX_INTERFACE_NUM];
- u8 lim_vref[MAX_BUS_NUM][MAX_INTERFACE_NUM];
- u8 interface_state[MAX_INTERFACE_NUM];
- u8 vref_window_size[MAX_INTERFACE_NUM][MAX_BUS_NUM];
- u8 vref_window_size_th = 12;
- static u8 pup_st[MAX_BUS_NUM][MAX_INTERFACE_NUM];
- static u32 rd_sample_mask[] = {
- 0,
- 8,
- 16,
- 24
- };
- #define VREF_STEP_1 0
- #define VREF_STEP_2 1
- #define VREF_CONVERGE 2
- /*
- * ODT additional timing
- */
- int ddr3_tip_write_additional_odt_setting(u32 dev_num, u32 if_id)
- {
- u32 cs_num = 0, max_read_sample = 0, min_read_sample = 0x1f;
- u32 data_read[MAX_INTERFACE_NUM] = { 0 };
- u32 read_sample[MAX_CS_NUM];
- u32 val;
- u32 pup_index;
- int max_phase = MIN_VALUE, current_phase;
- enum hws_access_type access_type = ACCESS_TYPE_UNICAST;
- u32 octets_per_if_num = ddr3_tip_dev_attr_get(dev_num, MV_ATTR_OCTET_PER_INTERFACE);
- CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, if_id,
- DUNIT_ODT_CTRL_REG,
- 0 << 8, 0x3 << 8));
- CHECK_STATUS(ddr3_tip_if_read(dev_num, access_type, if_id,
- RD_DATA_SMPL_DLYS_REG,
- data_read, MASK_ALL_BITS));
- val = data_read[if_id];
- for (cs_num = 0; cs_num < MAX_CS_NUM; cs_num++) {
- read_sample[cs_num] = GET_RD_SAMPLE_DELAY(val, cs_num);
- /* find maximum of read_samples */
- if (read_sample[cs_num] >= max_read_sample) {
- if (read_sample[cs_num] == max_read_sample)
- max_phase = MIN_VALUE;
- else
- max_read_sample = read_sample[cs_num];
- for (pup_index = 0;
- pup_index < octets_per_if_num;
- pup_index++) {
- CHECK_STATUS(ddr3_tip_bus_read
- (dev_num, if_id,
- ACCESS_TYPE_UNICAST, pup_index,
- DDR_PHY_DATA,
- RL_PHY_REG(cs_num),
- &val));
- current_phase = ((int)val & 0xe0) >> 6;
- if (current_phase >= max_phase)
- max_phase = current_phase;
- }
- }
- /* find minimum */
- if (read_sample[cs_num] < min_read_sample)
- min_read_sample = read_sample[cs_num];
- }
- min_read_sample = min_read_sample - 1;
- max_read_sample = max_read_sample + 4 + (max_phase + 1) / 2 + 1;
- if (min_read_sample >= 0xf)
- min_read_sample = 0xf;
- if (max_read_sample >= 0x1f)
- max_read_sample = 0x1f;
- CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, if_id,
- DDR_ODT_TIMING_LOW_REG,
- ((min_read_sample - 1) << 12),
- 0xf << 12));
- CHECK_STATUS(ddr3_tip_if_write(dev_num, access_type, if_id,
- DDR_ODT_TIMING_LOW_REG,
- (max_read_sample << 16),
- 0x1f << 16));
- return MV_OK;
- }
- int get_valid_win_rx(u32 dev_num, u32 if_id, u8 res[4])
- {
- u32 reg_pup = RESULT_PHY_REG;
- u32 reg_data;
- u32 cs_num;
- int i;
- cs_num = 0;
- /* TBD */
- reg_pup += cs_num;
- for (i = 0; i < 4; i++) {
- CHECK_STATUS(ddr3_tip_bus_read(dev_num, if_id,
- ACCESS_TYPE_UNICAST, i,
- DDR_PHY_DATA, reg_pup,
- ®_data));
- res[i] = (reg_data >> RESULT_PHY_RX_OFFS) & 0x1f;
- }
- return 0;
- }
- /*
- * This algorithm deals with the vertical optimum from Voltage point of view
- * of the sample signal.
- * Voltage sample point can improve the Eye / window size of the bit and the
- * pup.
- * The problem is that it is tune for all DQ the same so there isn't any
- * PBS like code.
- * It is more like centralization.
- * But because we don't have The training SM support we do it a bit more
- * smart search to save time.
- */
- 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;
- }
- /*
- * CK/CA Delay
- */
- int ddr3_tip_cmd_addr_init_delay(u32 dev_num, u32 adll_tap)
- {
- u32 if_id = 0;
- u32 ck_num_adll_tap = 0, ca_num_adll_tap = 0, data = 0;
- struct mv_ddr_topology_map *tm = mv_ddr_topology_map_get();
- /*
- * ck_delay_table is delaying the of the clock signal only.
- * (to overcome timing issues between_c_k & command/address signals)
- */
- /*
- * ca_delay is delaying the of the entire command & Address signals
- * (include Clock signal to overcome DGL error on the Clock versus
- * the DQS).
- */
- /* Calc ADLL Tap */
- if (ck_delay == PARAM_UNDEFINED)
- DEBUG_TRAINING_HW_ALG(
- DEBUG_LEVEL_ERROR,
- ("ERROR: ck_delay is not initialized!\n"));
- for (if_id = 0; if_id <= MAX_INTERFACE_NUM - 1; if_id++) {
- VALIDATE_IF_ACTIVE(tm->if_act_mask, if_id);
- /* Calc delay ps in ADLL tap */
- ck_num_adll_tap = ck_delay / adll_tap;
- ca_num_adll_tap = ca_delay / adll_tap;
- data = (ck_num_adll_tap & 0x3f) +
- ((ca_num_adll_tap & 0x3f) << 10);
- /*
- * Set the ADLL number to the CK ADLL for Interfaces for
- * all Pup
- */
- DEBUG_TRAINING_HW_ALG(
- DEBUG_LEVEL_TRACE,
- ("ck_num_adll_tap %d ca_num_adll_tap %d adll_tap %d\n",
- ck_num_adll_tap, ca_num_adll_tap, adll_tap));
- CHECK_STATUS(ddr3_tip_bus_write(dev_num, ACCESS_TYPE_UNICAST,
- if_id, ACCESS_TYPE_MULTICAST,
- PARAM_NOT_CARE, DDR_PHY_CONTROL,
- 0x0, data));
- }
- return MV_OK;
- }
|