SPDX: Convert all of our single license tags to Linux Kernel style
[platform/kernel/u-boot.git] / drivers / ddr / marvell / a38x / xor.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 <i2c.h>
8 #include <spl.h>
9 #include <asm/io.h>
10 #include <asm/arch/cpu.h>
11 #include <asm/arch/soc.h>
12
13 #include "ddr3_init.h"
14 #include "xor_regs.h"
15
16 /* defines  */
17 #ifdef MV_DEBUG
18 #define DB(x)   x
19 #else
20 #define DB(x)
21 #endif
22
23 static u32 ui_xor_regs_ctrl_backup;
24 static u32 ui_xor_regs_base_backup[MAX_CS];
25 static u32 ui_xor_regs_mask_backup[MAX_CS];
26
27 void mv_sys_xor_init(u32 num_of_cs, u32 cs_ena, u32 cs_size, u32 base_delta)
28 {
29         u32 reg, ui, base, cs_count;
30
31         ui_xor_regs_ctrl_backup = reg_read(XOR_WINDOW_CTRL_REG(0, 0));
32         for (ui = 0; ui < MAX_CS; ui++)
33                 ui_xor_regs_base_backup[ui] =
34                         reg_read(XOR_BASE_ADDR_REG(0, ui));
35         for (ui = 0; ui < MAX_CS; ui++)
36                 ui_xor_regs_mask_backup[ui] =
37                         reg_read(XOR_SIZE_MASK_REG(0, ui));
38
39         reg = 0;
40         for (ui = 0; ui < (num_of_cs); ui++) {
41                 /* Enable Window x for each CS */
42                 reg |= (0x1 << (ui));
43                 /* Enable Window x for each CS */
44                 reg |= (0x3 << ((ui * 2) + 16));
45         }
46
47         reg_write(XOR_WINDOW_CTRL_REG(0, 0), reg);
48
49         cs_count = 0;
50         for (ui = 0; ui < num_of_cs; ui++) {
51                 if (cs_ena & (1 << ui)) {
52                         /*
53                          * window x - Base - 0x00000000,
54                          * Attribute 0x0e - DRAM
55                          */
56                         base = cs_size * ui + base_delta;
57                         switch (ui) {
58                         case 0:
59                                 base |= 0xe00;
60                                 break;
61                         case 1:
62                                 base |= 0xd00;
63                                 break;
64                         case 2:
65                                 base |= 0xb00;
66                                 break;
67                         case 3:
68                                 base |= 0x700;
69                                 break;
70                         }
71
72                         reg_write(XOR_BASE_ADDR_REG(0, cs_count), base);
73
74                         /* window x - Size */
75                         reg_write(XOR_SIZE_MASK_REG(0, cs_count), 0x7fff0000);
76                         cs_count++;
77                 }
78         }
79
80         mv_xor_hal_init(1);
81
82         return;
83 }
84
85 void mv_sys_xor_finish(void)
86 {
87         u32 ui;
88
89         reg_write(XOR_WINDOW_CTRL_REG(0, 0), ui_xor_regs_ctrl_backup);
90         for (ui = 0; ui < MAX_CS; ui++)
91                 reg_write(XOR_BASE_ADDR_REG(0, ui),
92                           ui_xor_regs_base_backup[ui]);
93         for (ui = 0; ui < MAX_CS; ui++)
94                 reg_write(XOR_SIZE_MASK_REG(0, ui),
95                           ui_xor_regs_mask_backup[ui]);
96
97         reg_write(XOR_ADDR_OVRD_REG(0, 0), 0);
98 }
99
100 /*
101  * mv_xor_hal_init - Initialize XOR engine
102  *
103  * DESCRIPTION:
104  *               This function initialize XOR unit.
105  * INPUT:
106  *       None.
107  *
108  * OUTPUT:
109  *       None.
110  *
111  * RETURN:
112  *       MV_BAD_PARAM if parameters to function invalid, MV_OK otherwise.
113  */
114 void mv_xor_hal_init(u32 xor_chan_num)
115 {
116         u32 i;
117
118         /* Abort any XOR activity & set default configuration */
119         for (i = 0; i < xor_chan_num; i++) {
120                 mv_xor_command_set(i, MV_STOP);
121                 mv_xor_ctrl_set(i, (1 << XEXCR_REG_ACC_PROTECT_OFFS) |
122                                 (4 << XEXCR_DST_BURST_LIMIT_OFFS) |
123                                 (4 << XEXCR_SRC_BURST_LIMIT_OFFS));
124         }
125 }
126
127 /*
128  * mv_xor_ctrl_set - Set XOR channel control registers
129  *
130  * DESCRIPTION:
131  *
132  * INPUT:
133  *
134  * OUTPUT:
135  *       None.
136  *
137  * RETURN:
138  *       MV_BAD_PARAM if parameters to function invalid, MV_OK otherwise.
139  * NOTE:
140  *  This function does not modify the Operation_mode field of control register.
141  */
142 int mv_xor_ctrl_set(u32 chan, u32 xor_ctrl)
143 {
144         u32 old_value;
145
146         /* update the XOR Engine [0..1] Configuration Registers (XEx_c_r) */
147         old_value = reg_read(XOR_CONFIG_REG(XOR_UNIT(chan), XOR_CHAN(chan))) &
148                 XEXCR_OPERATION_MODE_MASK;
149         xor_ctrl &= ~XEXCR_OPERATION_MODE_MASK;
150         xor_ctrl |= old_value;
151         reg_write(XOR_CONFIG_REG(XOR_UNIT(chan), XOR_CHAN(chan)), xor_ctrl);
152
153         return MV_OK;
154 }
155
156 int mv_xor_mem_init(u32 chan, u32 start_ptr, u32 block_size,
157                     u32 init_val_high, u32 init_val_low)
158 {
159         u32 temp;
160
161         /* Parameter checking */
162         if (chan >= MV_XOR_MAX_CHAN)
163                 return MV_BAD_PARAM;
164
165         if (MV_ACTIVE == mv_xor_state_get(chan))
166                 return MV_BUSY;
167
168         if ((block_size < XEXBSR_BLOCK_SIZE_MIN_VALUE) ||
169             (block_size > XEXBSR_BLOCK_SIZE_MAX_VALUE))
170                 return MV_BAD_PARAM;
171
172         /* set the operation mode to Memory Init */
173         temp = reg_read(XOR_CONFIG_REG(XOR_UNIT(chan), XOR_CHAN(chan)));
174         temp &= ~XEXCR_OPERATION_MODE_MASK;
175         temp |= XEXCR_OPERATION_MODE_MEM_INIT;
176         reg_write(XOR_CONFIG_REG(XOR_UNIT(chan), XOR_CHAN(chan)), temp);
177
178         /*
179          * update the start_ptr field in XOR Engine [0..1] Destination Pointer
180          * Register
181          */
182         reg_write(XOR_DST_PTR_REG(XOR_UNIT(chan), XOR_CHAN(chan)), start_ptr);
183
184         /*
185          * update the Block_size field in the XOR Engine[0..1] Block Size
186          * Registers
187          */
188         reg_write(XOR_BLOCK_SIZE_REG(XOR_UNIT(chan), XOR_CHAN(chan)),
189                   block_size);
190
191         /*
192          * update the field Init_val_l in the XOR Engine Initial Value Register
193          * Low (XEIVRL)
194          */
195         reg_write(XOR_INIT_VAL_LOW_REG(XOR_UNIT(chan)), init_val_low);
196
197         /*
198          * update the field Init_val_h in the XOR Engine Initial Value Register
199          * High (XEIVRH)
200          */
201         reg_write(XOR_INIT_VAL_HIGH_REG(XOR_UNIT(chan)), init_val_high);
202
203         /* start transfer */
204         reg_bit_set(XOR_ACTIVATION_REG(XOR_UNIT(chan), XOR_CHAN(chan)),
205                     XEXACTR_XESTART_MASK);
206
207         return MV_OK;
208 }
209
210 /*
211  * mv_xor_state_get - Get XOR channel state.
212  *
213  * DESCRIPTION:
214  *       XOR channel activity state can be active, idle, paused.
215  *       This function retrunes the channel activity state.
216  *
217  * INPUT:
218  *       chan     - the channel number
219  *
220  * OUTPUT:
221  *       None.
222  *
223  * RETURN:
224  *       XOR_CHANNEL_IDLE    - If the engine is idle.
225  *       XOR_CHANNEL_ACTIVE  - If the engine is busy.
226  *       XOR_CHANNEL_PAUSED  - If the engine is paused.
227  *       MV_UNDEFINED_STATE  - If the engine state is undefind or there is no
228  *                             such engine
229  */
230 enum mv_state mv_xor_state_get(u32 chan)
231 {
232         u32 state;
233
234         /* Parameter checking   */
235         if (chan >= MV_XOR_MAX_CHAN) {
236                 DB(printf("%s: ERR. Invalid chan num %d\n", __func__, chan));
237                 return MV_UNDEFINED_STATE;
238         }
239
240         /* read the current state */
241         state = reg_read(XOR_ACTIVATION_REG(XOR_UNIT(chan), XOR_CHAN(chan)));
242         state &= XEXACTR_XESTATUS_MASK;
243
244         /* return the state */
245         switch (state) {
246         case XEXACTR_XESTATUS_IDLE:
247                 return MV_IDLE;
248         case XEXACTR_XESTATUS_ACTIVE:
249                 return MV_ACTIVE;
250         case XEXACTR_XESTATUS_PAUSED:
251                 return MV_PAUSED;
252         }
253
254         return MV_UNDEFINED_STATE;
255 }
256
257 /*
258  * mv_xor_command_set - Set command of XOR channel
259  *
260  * DESCRIPTION:
261  *       XOR channel can be started, idle, paused and restarted.
262  *       Paused can be set only if channel is active.
263  *       Start can be set only if channel is idle or paused.
264  *       Restart can be set only if channel is paused.
265  *       Stop can be set only if channel is active.
266  *
267  * INPUT:
268  *       chan     - The channel number
269  *       command  - The command type (start, stop, restart, pause)
270  *
271  * OUTPUT:
272  *       None.
273  *
274  * RETURN:
275  *       MV_OK on success , MV_BAD_PARAM on erroneous parameter, MV_ERROR on
276  *       undefind XOR engine mode
277  */
278 int mv_xor_command_set(u32 chan, enum mv_command command)
279 {
280         enum mv_state state;
281
282         /* Parameter checking */
283         if (chan >= MV_XOR_MAX_CHAN) {
284                 DB(printf("%s: ERR. Invalid chan num %d\n", __func__, chan));
285                 return MV_BAD_PARAM;
286         }
287
288         /* get the current state */
289         state = mv_xor_state_get(chan);
290
291         if ((command == MV_START) && (state == MV_IDLE)) {
292                 /* command is start and current state is idle */
293                 reg_bit_set(XOR_ACTIVATION_REG
294                             (XOR_UNIT(chan), XOR_CHAN(chan)),
295                             XEXACTR_XESTART_MASK);
296                 return MV_OK;
297         } else if ((command == MV_STOP) && (state == MV_ACTIVE)) {
298                 /* command is stop and current state is active */
299                 reg_bit_set(XOR_ACTIVATION_REG
300                             (XOR_UNIT(chan), XOR_CHAN(chan)),
301                             XEXACTR_XESTOP_MASK);
302                 return MV_OK;
303         } else if (((enum mv_state)command == MV_PAUSED) &&
304                    (state == MV_ACTIVE)) {
305                 /* command is paused and current state is active */
306                 reg_bit_set(XOR_ACTIVATION_REG
307                             (XOR_UNIT(chan), XOR_CHAN(chan)),
308                             XEXACTR_XEPAUSE_MASK);
309                 return MV_OK;
310         } else if ((command == MV_RESTART) && (state == MV_PAUSED)) {
311                 /* command is restart and current state is paused */
312                 reg_bit_set(XOR_ACTIVATION_REG
313                             (XOR_UNIT(chan), XOR_CHAN(chan)),
314                             XEXACTR_XERESTART_MASK);
315                 return MV_OK;
316         } else if ((command == MV_STOP) && (state == MV_IDLE)) {
317                 /* command is stop and current state is active */
318                 return MV_OK;
319         }
320
321         /* illegal command */
322         DB(printf("%s: ERR. Illegal command\n", __func__));
323
324         return MV_BAD_PARAM;
325 }
326
327 void ddr3_new_tip_ecc_scrub(void)
328 {
329         u32 cs_c, max_cs;
330         u32 cs_ena = 0;
331
332         printf("DDR3 Training Sequence - Start scrubbing\n");
333
334         max_cs = hws_ddr3_tip_max_cs_get();
335         for (cs_c = 0; cs_c < max_cs; cs_c++)
336                 cs_ena |= 1 << cs_c;
337
338         mv_sys_xor_init(max_cs, cs_ena, 0x80000000, 0);
339
340         mv_xor_mem_init(0, 0x00000000, 0x80000000, 0xdeadbeef, 0xdeadbeef);
341         /* wait for previous transfer completion */
342         while (mv_xor_state_get(0) != MV_IDLE)
343                 ;
344
345         mv_xor_mem_init(0, 0x80000000, 0x40000000, 0xdeadbeef, 0xdeadbeef);
346
347         /* wait for previous transfer completion */
348         while (mv_xor_state_get(0) != MV_IDLE)
349                 ;
350
351         /* Return XOR State */
352         mv_sys_xor_finish();
353
354         printf("DDR3 Training Sequence - End scrubbing\n");
355 }