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