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