blob: ee2305b983651771ea530b3018bf46b040963bad [file] [log] [blame]
Stefan Roese6a905952015-04-20 09:31:27 +02001/*
2 * Copyright (C) Marvell International Ltd. and its affiliates
3 *
4 * SPDX-License-Identifier: GPL-2.0
5 */
6
7#include <common.h>
8#include <i2c.h>
9#include <spl.h>
10#include <asm/io.h>
11#include <asm/arch/cpu.h>
12#include <asm/arch/soc.h>
13
14#include "seq_exec.h"
15#include "high_speed_env_spec.h"
16
17#include "../../../drivers/ddr/marvell/a38x/ddr3_init.h"
18
19#if defined(MV_DEBUG_INIT_FULL) || defined(MV_DEBUG)
20#define DB(x) x
21#else
22#define DB(x)
23#endif
24
25/* Array for mapping the operation (write, poll or delay) functions */
26op_execute_func_ptr op_execute_func_arr[] = {
27 write_op_execute,
28 delay_op_execute,
29 poll_op_execute
30};
31
32int write_op_execute(u32 serdes_num, struct op_params *params, u32 data_arr_idx)
33{
34 u32 unit_base_reg, unit_offset, data, mask, reg_data, reg_addr;
35
36 /* Getting write op params from the input parameter */
37 data = params->data[data_arr_idx];
38 mask = params->mask;
39
40 /* an empty operation */
41 if (data == NO_DATA)
42 return MV_OK;
43
44 /* get updated base address since it can be different between Serdes */
45 CHECK_STATUS(hws_get_ext_base_addr(serdes_num, params->unit_base_reg,
46 params->unit_offset,
47 &unit_base_reg, &unit_offset));
48
49 /* Address calculation */
50 reg_addr = unit_base_reg + unit_offset * serdes_num;
51
52#ifdef SEQ_DEBUG
53 printf("Write: 0x%x: 0x%x (mask 0x%x) - ", reg_addr, data, mask);
54#endif
55 /* Reading old value */
56 reg_data = reg_read(reg_addr);
57 reg_data &= (~mask);
58
59 /* Writing new data */
60 data &= mask;
61 reg_data |= data;
62 reg_write(reg_addr, reg_data);
63
64#ifdef SEQ_DEBUG
65 printf(" - 0x%x\n", reg_data);
66#endif
67
68 return MV_OK;
69}
70
71int delay_op_execute(u32 serdes_num, struct op_params *params, u32 data_arr_idx)
72{
73 u32 delay;
74
75 /* Getting delay op params from the input parameter */
76 delay = params->wait_time;
77#ifdef SEQ_DEBUG
78 printf("Delay: %d\n", delay);
79#endif
80 mdelay(delay);
81
82 return MV_OK;
83}
84
85int poll_op_execute(u32 serdes_num, struct op_params *params, u32 data_arr_idx)
86{
87 u32 unit_base_reg, unit_offset, data, mask, num_of_loops, wait_time;
88 u32 poll_counter = 0;
89 u32 reg_addr, reg_data;
90
91 /* Getting poll op params from the input parameter */
92 data = params->data[data_arr_idx];
93 mask = params->mask;
94 num_of_loops = params->num_of_loops;
95 wait_time = params->wait_time;
96
97 /* an empty operation */
98 if (data == NO_DATA)
99 return MV_OK;
100
101 /* get updated base address since it can be different between Serdes */
102 CHECK_STATUS(hws_get_ext_base_addr(serdes_num, params->unit_base_reg,
103 params->unit_offset,
104 &unit_base_reg, &unit_offset));
105
106 /* Address calculation */
107 reg_addr = unit_base_reg + unit_offset * serdes_num;
108
109 /* Polling */
110#ifdef SEQ_DEBUG
111 printf("Poll: 0x%x: 0x%x (mask 0x%x)\n", reg_addr, data, mask);
112#endif
113
114 do {
115 reg_data = reg_read(reg_addr) & mask;
116 poll_counter++;
117 udelay(wait_time);
118 } while ((reg_data != data) && (poll_counter < num_of_loops));
119
120 if ((poll_counter >= num_of_loops) && (reg_data != data)) {
121 DEBUG_INIT_S("poll_op_execute: TIMEOUT\n");
122 return MV_TIMEOUT;
123 }
124
125 return MV_OK;
126}
127
128enum mv_op get_cfg_seq_op(struct op_params *params)
129{
130 if (params->wait_time == 0)
131 return WRITE_OP;
132 else if (params->num_of_loops == 0)
133 return DELAY_OP;
134
135 return POLL_OP;
136}
137
138int mv_seq_exec(u32 serdes_num, u32 seq_id)
139{
140 u32 seq_idx;
141 struct op_params *seq_arr;
142 u32 seq_size;
143 u32 data_arr_idx;
144 enum mv_op curr_op;
145
146 DB(printf("\n### mv_seq_exec ###\n"));
147 DB(printf("seq id: %d\n", seq_id));
148
149 if (hws_is_serdes_active(serdes_num) != 1) {
150 printf("mv_seq_exec_ext:Error: SerDes lane %d is not valid\n",
151 serdes_num);
152 return MV_BAD_PARAM;
153 }
154
155 seq_arr = serdes_seq_db[seq_id].op_params_ptr;
156 seq_size = serdes_seq_db[seq_id].cfg_seq_size;
157 data_arr_idx = serdes_seq_db[seq_id].data_arr_idx;
158
159 DB(printf("seq_size: %d\n", seq_size));
160 DB(printf("data_arr_idx: %d\n", data_arr_idx));
161
162 /* Executing the sequence operations */
163 for (seq_idx = 0; seq_idx < seq_size; seq_idx++) {
164 curr_op = get_cfg_seq_op(&seq_arr[seq_idx]);
165 op_execute_func_arr[curr_op](serdes_num, &seq_arr[seq_idx],
166 data_arr_idx);
167 }
168
169 return MV_OK;
170}