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