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