1 /*
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 */
26 op_execute_func_ptr op_execute_func_arr[] = {
27 	write_op_execute,
28 	delay_op_execute,
29 	poll_op_execute
30 };
31 
32 int 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 
71 int 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 
85 int 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 
128 enum 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 
138 int 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 }
171